From: Aaron Schulz Date: Mon, 1 Oct 2007 19:38:28 +0000 (+0000) Subject: *Clean up deletion of revisions and remove some gaps X-Git-Tag: 1.31.0-rc.0~51236 X-Git-Url: http://git.cyclocoop.org/%22.%24h.%22?a=commitdiff_plain;h=4febfc77c24ba5763aa7bbe7f8c76c9f5a4976a4;p=lhc%2Fweb%2Fwiklou.git *Clean up deletion of revisions and remove some gaps *Allow blocking of users to hide names *Implement revision deletion for images/deleted files/deleted revs *Log deletion set off for now *Add 'hidden' file dir *Dissallow merging via undelete (which was inefficient and hard to reverse) *Use restore points and diffs to special:undelete *Add a special page to merge pages *Get changeslist to use tables to avoid ugly formatting *Add logs into RC for rebuildrecentchanges.php *Add private logs *List private logs at specialpages *Tweak/add some deletion and merge messages --- diff --git a/includes/Article.php b/includes/Article.php index c0484e7f7b..cf1594f824 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -390,6 +390,7 @@ class Article { // We should instead work with the Revision object when we need it... $this->mContent = $revision->userCan( Revision::DELETED_TEXT ) ? $revision->getRawText() : ""; //$this->mContent = $revision->getText(); + $this->mContent = $revision->revText(); // Loads if user is allowed $this->mUser = $revision->getUser(); $this->mUserText = $revision->getUserText(); @@ -1069,7 +1070,6 @@ class Article { $result = $dbw->affectedRows() != 0; if ($result) { - // FIXME: Should the result from updateRedirectOn() be returned instead? $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect ); } @@ -1494,6 +1494,7 @@ class Article { * * @param boolean $noRedir Add redirect=no * @param string $sectionAnchor section to redirect to, including "#" + * @param string $extraq, extra query params */ function doRedirect( $noRedir = false, $sectionAnchor = '', $extraq = '' ) { global $wgOut; @@ -1689,7 +1690,7 @@ class Article { * @return bool true on success */ function updateRestrictions( $limit = array(), $reason = '', $cascade = 0, $expiry = null ) { - global $wgUser, $wgRestrictionTypes, $wgContLang; + global $wgUser, $wgRestrictionTypes, $wgContLang, $wgGroupPermissions; $id = $this->mTitle->getArticleID(); if( !$wgUser->isAllowed( 'protect' ) || wfReadOnly() || $id == 0 ) { @@ -1719,7 +1720,6 @@ class Article { # If nothing's changed, do nothing if( $changed ) { - global $wgGroupPermissions; if( wfRunHooks( 'ArticleProtect', array( &$this, &$wgUser, $limit, $reason ) ) ) { $dbw = wfGetDB( DB_MASTER ); @@ -1832,6 +1832,8 @@ class Article { $confirm = $wgRequest->wasPosted() && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ); $reason = $wgRequest->getText( 'wpReason' ); + # Flag to hide all contents of the archived revisions + $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgUser->isAllowed('deleterevision'); # This code desperately needs to be totally rewritten @@ -1856,7 +1858,7 @@ class Article { } if( $confirm ) { - $this->doDelete( $reason ); + $this->doDelete( $reason, $suppress ); if( $wgRequest->getCheck( 'wpWatch' ) ) { $this->doWatch(); } elseif( $this->mTitle->userIsWatching() ) { @@ -2002,7 +2004,14 @@ class Article { $delcom = htmlspecialchars( wfMsg( 'deletecomment' ) ); $token = htmlspecialchars( $wgUser->editToken() ); $watch = Xml::checkLabel( wfMsg( 'watchthis' ), 'wpWatch', 'wpWatch', $wgUser->getBoolOption( 'watchdeletion' ) || $this->mTitle->userIsWatching(), array( 'tabindex' => '2' ) ); - + if ( $wgUser->isAllowed( 'deleterevision' ) ) { + $supress = " "; + $supress .= Xml::checkLabel( wfMsg( 'revdelete-suppress' ), 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '2' ) ); + $supress .= ""; + } else { + $supress = ''; + } + $wgOut->addHTML( "
@@ -2014,6 +2023,7 @@ class Article { + $supress @@ -2051,12 +2061,12 @@ class Article { /** * Perform a deletion and output success or failure messages */ - function doDelete( $reason ) { + function doDelete( $reason, $suppress = false ) { global $wgOut, $wgUser; wfDebug( __METHOD__."\n" ); if (wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason))) { - if ( $this->doDeleteArticle( $reason ) ) { + if ( $this->doDeleteArticle( $reason, $suppress ) ) { $deleted = wfEscapeWikiText( $this->mTitle->getPrefixedText() ); $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); @@ -2069,7 +2079,7 @@ class Article { $wgOut->returnToMain( false ); wfRunHooks('ArticleDeleteComplete', array(&$this, &$wgUser, $reason)); } else { - $wgOut->showFatalError( wfMsg( 'cannotdelete' ) ); + $wgOut->showFatalError( wfMsg( 'cannotdelete' ).'
'.wfMsg('cannotdelete-merge') ); } } } @@ -2079,7 +2089,7 @@ class Article { * Deletes the article with database consistency, writes logs, purges caches * Returns success */ - function doDeleteArticle( $reason ) { + function doDeleteArticle( $reason, $suppress = false ) { global $wgUseSquid, $wgDeferredUpdateList; global $wgUseTrackbacks; @@ -2093,10 +2103,30 @@ class Article { if ( $t == '' || $id == 0 ) { return false; } + // Do not fuck up histories by merging them in annoying, unrevertable ways + // This page id should match any deleted ones (excepting NULL values) + $otherpages = $dbw->selectField( 'archive', 'COUNT(*)', + array('ar_namespace' => $ns, 'ar_title' => $t, + 'ar_page_id IS NOT NULL', "ar_page_id != $id" ), + __METHOD__ ); + if( $otherpages ) + return false; $u = new SiteStatsUpdate( 0, 1, -(int)$this->isCountable( $this->getContent() ), -1 ); array_push( $wgDeferredUpdateList, $u ); + // Bitfields to further supress the content + if ( $suppress ) { + $bitfield = 0; + // This should be 15... + $bitfield |= Revision::DELETED_TEXT; + $bitfield |= Revision::DELETED_COMMENT; + $bitfield |= Revision::DELETED_USER; + $bitfield |= Revision::DELETED_RESTRICTED; + } else { + $bitfield = 'rev_deleted'; + } + // For now, shunt the revision data into the archive table. // Text is *not* removed from the text table; bulk storage // is left intact to avoid breaking block-compression or @@ -2122,6 +2152,7 @@ class Article { 'ar_flags' => '\'\'', // MySQL's "strict mode"... 'ar_len' => 'rev_len', 'ar_page_id' => 'page_id', + 'ar_deleted' => $bitfield ), array( 'page_id' => $id, 'page_id = rev_page' @@ -2162,8 +2193,9 @@ class Article { # Clear caches Article::onArticleDelete( $this->mTitle ); - # Log the deletion - $log = new LogPage( 'delete' ); + # Log the deletion, if the page was suppressed, log it at Oversight instead + $logtype = ($suppress) ? 'oversight' : 'delete'; + $log = new LogPage( $logtype ); $log->addEntry( 'delete', $this->mTitle, $reason ); # Clear the cached article id so the interface doesn't act like we exist @@ -2262,8 +2294,13 @@ class Article { ); } - # Get the edit summary $target = Revision::newFromId( $s->rev_id ); + # Revision *must* be public and we don't well handle deleted edits on top + if ( $target->isDeleted(REVISION::DELETED_TEXT) ) { + $wgOut->setPageTitle( wfMsg('rollbackfailed') ); + $wgOut->addHTML( wfMsg( 'missingarticle' ) ); + } + # Get the edit summary if( empty( $summary ) ) $summary = wfMsgForContent( 'revertpage', $target->getUserText(), $from ); @@ -2524,8 +2561,28 @@ class Article { ? wfMsg( 'diff' ) : $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'diff' ), 'diff=next&oldid='.$oldid ); - $userlinks = $sk->userLink( $revision->getUser(), $revision->getUserText() ) - . $sk->userToolLinks( $revision->getUser(), $revision->getUserText() ); + $cdel=''; + if( $wgUser->isAllowed( 'deleterevision' ) ) { + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); + if( $revision->isCurrent() ) { + // We don't handle top deleted edits too well + $cdel = wfMsgHtml('rev-delundel'); + } else if( !$revision->userCan( Revision::DELETED_RESTRICTED ) ) { + // If revision was hidden from sysops + $cdel = wfMsgHtml('rev-delundel'); + } else { + $cdel = $sk->makeKnownLinkObj( $revdel, + wfMsgHtml('rev-delundel'), + 'target=' . urlencode( $this->mTitle->getPrefixedDbkey() ) . + '&oldid=' . urlencode( $oldid ) ); + // Bolden oversighted content + if( $revision->isDeleted( Revision::DELETED_RESTRICTED ) ) + $cdel = "$cdel"; + } + $cdel = "($cdel) "; + } + + $userlinks = $sk->revUserTools( $revision, true ); $m = wfMsg( 'revision-info-current' ); $infomsg = $current && !wfEmptyMsg( 'revision-info-current', $m ) && $m != '-' @@ -2533,7 +2590,8 @@ class Article { : 'revision-info'; $r = "\n\t\t\t\t
" . wfMsg( $infomsg, $td, $userlinks ) . "
\n" . - "\n\t\t\t\t
" . wfMsg( 'revision-nav', $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff ) . "
\n\t\t\t"; + + "\n\t\t\t\t
" . $cdel . wfMsg( 'revision-nav', $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff ) . "
\n\t\t\t"; $wgOut->setSubtitle( $r ); } diff --git a/includes/ChangesList.php b/includes/ChangesList.php index 8d0f95086f..71df7dd19c 100644 --- a/includes/ChangesList.php +++ b/includes/ChangesList.php @@ -75,7 +75,7 @@ class ChangesList { : $nothing; $f .= $bot ? '' . $this->message['boteditletter'] . '' : $nothing; $f .= $patrolled ? '!' : $nothing; - return $f; + return "$f"; } /** @@ -101,6 +101,32 @@ class ChangesList { } } + /** + * int $field one of DELETED_* bitfield constants + * @return bool + */ + function isDeleted( $rc, $field ) { + return ($rc->mAttribs['rc_deleted'] & $field) == $field; + } + + /** + * Determine if the current user is allowed to view a particular + * field of this revision, if it's marked as deleted. + * @param int $field + * @return bool + */ + function userCan( $rc, $field ) { + if( ( $rc->mAttribs['rc_deleted'] & $field ) == $field ) { + global $wgUser; + $permission = ( $rc->mAttribs['rc_deleted'] & Revision::DELETED_RESTRICTED ) == Revision::DELETED_RESTRICTED + ? 'hiderevision' + : 'deleterevision'; + wfDebug( "Checking for $permission due to $field match on $rc->mAttribs['rc_deleted']\n" ); + return $wgUser->isAllowed( $permission ); + } else { + return true; + } + } function insertMove( &$s, $rc ) { # Diff @@ -136,10 +162,11 @@ class ChangesList { $s .= '(' . $this->skin->makeKnownLinkObj($title, $logname ) . ')'; } - function insertDiffHist(&$s, &$rc, $unpatrolled) { # Diff link - if( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) { + if( !$this->userCan($rc,Revision::DELETED_TEXT) ) { + $diffLink = $this->message['diff']; + } else if( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) { $diffLink = $this->message['diff']; } else { $rcidparam = $unpatrolled @@ -170,7 +197,12 @@ class ChangesList { $params = ( $unpatrolled && $rc->mAttribs['rc_type'] == RC_NEW ) ? 'rcid='.$rc->mAttribs['rc_id'] : ''; - $articlelink = ' '. $this->skin->makeKnownLinkObj( $rc->getTitle(), '', $params ); + if( $this->isDeleted($rc,Revision::DELETED_TEXT) ) { + $articlelink = $this->skin->makeKnownLinkObj( $rc->getTitle(), '', $params ); + $articlelink = ''.$articlelink.''; + } else { + $articlelink = ' '. $this->skin->makeKnownLinkObj( $rc->getTitle(), '', $params ); + } if( $watched ) $articlelink = "{$articlelink}"; global $wgContLang; @@ -187,15 +219,38 @@ class ChangesList { /** Insert links to user page, user talk page and eventually a blocking link */ function insertUserRelatedLinks(&$s, &$rc) { - $s .= $this->skin->userLink( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); - $s .= $this->skin->userToolLinks( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); + if ( $this->isDeleted($rc,Revision::DELETED_USER) ) { + $s .= ' ' . wfMsgHtml('rev-deleted-user') . ''; + } else { + $s .= $this->skin->userLink( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); + $s .= $this->skin->userToolLinks( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); + } + } + + /** insert a formatted action */ + function insertAction(&$s, &$rc) { + # Add comment + if( $rc->mAttribs['rc_type'] == RC_LOG ) { + // log action + if ( $this->isDeleted($rc,LogViewer::DELETED_ACTION) ) { + $s .= ' ' . wfMsgHtml('rev-deleted-event') . ''; + } else { + $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 ); + } + } } /** insert a formatted comment */ function insertComment(&$s, &$rc) { # Add comment if( $rc->mAttribs['rc_type'] != RC_MOVE && $rc->mAttribs['rc_type'] != RC_MOVE_OVER_REDIRECT ) { - $s .= $this->skin->commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() ); + // log comment + if ( $this->isDeleted($rc,Revision::DELETED_COMMENT) ) { + $s .= ' ' . wfMsgHtml('rev-deleted-comment') . ''; + } else { + $s .= $this->skin->commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() ); + } } } @@ -251,18 +306,22 @@ class OldChangesList extends ChangesList { $s .= '
  • '; - // moved pages + // Moved pages if( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { $this->insertMove( $s, $rc ); - // log entries - } elseif ( $rc_namespace == NS_SPECIAL ) { + // Log entries + } elseif( $rc_log_type !='' ) { + $logtitle = Title::newFromText( "Log/$rc_log_type", NS_SPECIAL ); + $this->insertLog( $s, $logtitle, $rc_log_type ); + // Log entries (old format) or log targets, and special pages + } elseif( $rc_namespace == NS_SPECIAL ) { list( $specialName, $specialSubpage ) = SpecialPage::resolveAliasWithSubpage( $rc_title ); if ( $specialName == 'Log' ) { $this->insertLog( $s, $rc->getTitle(), $specialSubpage ); } else { wfDebug( "Unexpected special page in recentchanges\n" ); } - // all other stuff + // Log entries } else { wfProfileIn($fname.'-page'); @@ -284,9 +343,15 @@ class OldChangesList extends ChangesList { } $this->insertUserRelatedLinks($s,$rc); + $this->insertAction($s, $rc); $this->insertComment($s, $rc); - - $s .= rtrim(' ' . $this->numberofWatchingusers($rc->numberofWatchingusers)); + + # Mark revision as deleted + if ( !$rc_log_type && $this->isDeleted($rc,Revision::DELETED_TEXT) ) + $s .= ' ' . wfMsgHtml( 'deletedrev' ) . ''; + if($rc->numberofWatchingusers > 0) { + $s .= ' ' . wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rc->numberofWatchingusers)); + } $s .= "
  • \n"; @@ -334,12 +399,14 @@ class EnhancedChangesList extends ChangesList { $rc->unpatrolled = false; } + $showrev=true; # Make article link if( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir"; $clink = wfMsg( $msg, $this->skin->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ), $this->skin->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) ); - } elseif( $rc_namespace == NS_SPECIAL ) { + } else if( $rc_namespace == NS_SPECIAL ) { + // Log entries (old format) and special pages list( $specialName, $logtype ) = SpecialPage::resolveAliasWithSubpage( $rc_title ); if ( $specialName == 'Log' ) { # Log updates, etc @@ -349,7 +416,16 @@ class EnhancedChangesList extends ChangesList { wfDebug( "Unexpected special page in recentchanges\n" ); $clink = ''; } - } elseif( $rc->unpatrolled && $rc_type == RC_NEW ) { + } elseif ( $rc_log_type !='' ) { + // Log entries + $logtitle = Title::newFromText( "Log/$rc_log_type", NS_SPECIAL ); + $logname = LogPage::logName( $rc_log_type ); + $clink = '(' . $this->skin->makeKnownLinkObj($logtitle, $logname ) . ')'; + } if ( $this->isDeleted($rc,Revision::DELETED_TEXT) ) { + $clink = '' . $this->skin->makeKnownLinkObj( $rc->getTitle(), '' ) . ''; + if ( !ChangesList::userCan($rc,Revision::DELETED_TEXT) ) + $showrev=false; + } else if( $rc->unpatrolled && $rc_type == RC_NEW ) { # Unpatrolled new page, give rc_id in query $clink = $this->skin->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" ); } else { @@ -372,7 +448,10 @@ class EnhancedChangesList extends ChangesList { $querydiff = $curIdEq."&diff=$rc_this_oldid&oldid=$rc_last_oldid$rcIdQuery"; $aprops = ' tabindex="'.$baseRC->counter.'"'; $curLink = $this->skin->makeKnownLinkObj( $rc->getTitle(), $this->message['cur'], $querycur, '' ,'', $aprops ); - if( $rc_type == RC_NEW || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { + if ( !$showrev ) { + $curLink = $this->message['cur']; + $diffLink = $this->message['diff']; + } else if( $rc_type == RC_NEW || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { if( $rc_type != RC_NEW ) { $curLink = $this->message['cur']; } @@ -382,21 +461,27 @@ class EnhancedChangesList extends ChangesList { } # Make "last" link - if( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { + if ( !$showrev ) { + $lastLink = $this->message['last']; + } else if( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { $lastLink = $this->message['last']; } else { $lastLink = $this->skin->makeKnownLinkObj( $rc->getTitle(), $this->message['last'], - $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid . $rcIdQuery ); + $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid . $rcIdQuery ); + } + + # Make user links + if ( $this->isDeleted($rc,Revision::DELETED_USER) ) { + $rc->userlink = ' ' . wfMsgHtml('rev-deleted-user') . ''; + } else { + $rc->userlink = $this->skin->userLink( $rc_user, $rc_user_text ); + $rc->usertalklink = $this->skin->userToolLinks( $rc_user, $rc_user_text ); } - - $rc->userlink = $this->skin->userLink( $rc_user, $rc_user_text ); $rc->lastlink = $lastLink; $rc->curlink = $curLink; $rc->difflink = $diffLink; - $rc->usertalklink = $this->skin->userToolLinks( $rc_user, $rc_user_text ); - # Put accumulated information into the cache, for later display # Page moves go on their own line $title = $rc->getTitle(); @@ -418,10 +503,11 @@ class EnhancedChangesList extends ChangesList { */ function recentChangesBlockGroup( $block ) { global $wgLang, $wgContLang, $wgRCShowChangedSize; - $r = ''; + $r = '
      $watch
    '; # Collate list of users $isnew = false; + $namehidden = true; $unpatrolled = false; $userlinks = array(); foreach( $block as $rcObj ) { @@ -429,6 +515,11 @@ class EnhancedChangesList extends ChangesList { if( $rcObj->mAttribs['rc_new'] ) { $isnew = true; } + // if all log actions to this page were hidden, then don't + // give the name of the affected page for this block + if( !($rcObj->mAttribs['rc_deleted'] & LogViewer::DELETED_ACTION) ) { + $namehidden = false; + } $u = $rcObj->userlink; if( !isset( $userlinks[$u] ) ) { $userlinks[$u] = 0; @@ -462,24 +553,25 @@ class EnhancedChangesList extends ChangesList { $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')"; $tl = '' . $this->sideArrow() . ''; $tl .= ''; - $r .= $tl; + $r .= '
    '.$tl; # Main line - $r .= ''; - $r .= $this->recentChangesFlags( $isnew, false, $unpatrolled, ' ', $bot ); + $r .= ' '.$this->recentChangesFlags( $isnew, false, $unpatrolled, ' ', $bot ); # Timestamp - $r .= ' '.$block[0]->timestamp.' '; + $r .= ' '.$block[0]->timestamp.'  '; # Article link - $r .= $this->maybeWatchedLink( $block[0]->link, $block[0]->watched ); + if ( $namehidden ) + $r .= ' ' . wfMsgHtml('rev-deleted-event') . ''; + else + $r .= $this->maybeWatchedLink( $block[0]->link, $block[0]->watched ); $r .= $wgContLang->getDirMark(); $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id']; $currentRevision = $block[0]->mAttribs['rc_this_oldid']; if( $block[0]->mAttribs['rc_type'] != RC_LOG ) { # Changes - $n = count($block); static $nchanges = array(); if ( !isset( $nchanges[$n] ) ) { @@ -489,25 +581,25 @@ class EnhancedChangesList extends ChangesList { $r .= ' ('; - if( $isnew ) { + if( !ChangesList::userCan($rcObj,Revision::DELETED_TEXT) ) { + $r .= $nchanges[$n]; + } else if( $isnew ) { $r .= $nchanges[$n]; } else { $r .= $this->skin->makeKnownLinkObj( $block[0]->getTitle(), $nchanges[$n], $curIdEq."&diff=$currentRevision&oldid=$oldid" ); } - $r .= ') . . '; - if( $wgRCShowChangedSize ) { # Character difference $chardiff = $rcObj->getCharacterDifference( $block[ count( $block ) - 1 ]->mAttribs['rc_old_len'], $block[0]->mAttribs['rc_new_len'] ); if( $chardiff == '' ) { - $r .= ' ('; + $r .= ') '; } else { $r .= ' ' . $chardiff. ' . . '; } - } + } # History $r .= '(' . $this->skin->makeKnownLinkObj( $block[0]->getTitle(), @@ -516,51 +608,70 @@ class EnhancedChangesList extends ChangesList { } $r .= $users; - - $r .= $this->numberofWatchingusers($block[0]->numberofWatchingusers); - $r .= "
    \n"; + $r .=$this->numberofWatchingusers($block[0]->numberofWatchingusers); + + $r .= "
    \n"; # Sub-entries - $r .= '
    ', 'rev-delundel' => 'show/hide', 'revisiondelete' => 'Delete/undelete revisions', -'revdelete-nooldid-title' => 'No target revision', -'revdelete-nooldid-text' => 'You have not specified target revision or revisions to perform this function on.', -'revdelete-selected' => "{{PLURAL:$2|Selected revision|Selected revisions}} of '''$1:'''", -'logdelete-selected' => "{{PLURAL:$2|Selected log event|Selected log events}} for '''$1:'''", +'revdelete-nooldid-title' => 'Invalid target revision', +'revdelete-nooldid-text' => 'You have either not specified a target revision(s) to perform this +function, the specified revision does not exist, or you are attempting to hide the current revision.', +'revdelete-selected' => "{{PLURAL:$2|Selected revision|Selected revisions}} of [[:$1]]:", +'logdelete-selected' => "{{PLURAL:$1|Selected log event|Selected log events}}:", 'revdelete-text' => 'Deleted revisions and events will still appear in the page history and logs, but parts of their content will be inaccessible to the public. @@ -1160,7 +1163,7 @@ undelete it again through this same interface, unless additional restrictions ar 'revdelete-hide-name' => 'Hide action and target', 'revdelete-hide-comment' => 'Hide edit comment', 'revdelete-hide-user' => "Hide editor's username/IP", -'revdelete-hide-restricted' => 'Apply these restrictions to sysops as well as others', +'revdelete-hide-restricted' => 'Apply these restrictions to Sysops and lock this interface', 'revdelete-suppress' => 'Suppress data from sysops as well as others', 'revdelete-hide-image' => 'Hide file content', 'revdelete-unsuppress' => 'Remove restrictions on restored revisions', @@ -1169,14 +1172,43 @@ undelete it again through this same interface, unless additional restrictions ar 'revdelete-logentry' => 'changed revision visibility of [[$1]]', 'logdelete-logentry' => 'changed event visibility of [[$1]]', 'revdelete-logaction' => '$1 {{PLURAL:$1|revision|revisions}} set to mode $2', -'logdelete-logaction' => '$1 {{PLURAL:$1|event|events}} to [[$3]] set to mode $2', -'revdelete-success' => 'Revision visibility successfully set.', -'logdelete-success' => 'Event visibility successfully set.', +'logdelete-logaction' => '$1 {{PLURAL:$1|event|events}} set to mode $2', +'revdelete-success' => "'''Revision visibility successfully set.'''", +'logdelete-success' => "'''Log visibility successfully set.'''", +'revdel-restore' => 'Change visiblity', # Oversight log -'oversightlog' => 'Oversight log', -'overlogpagetext' => 'Below is a list of the most recent deletions and blocks involving content -hidden from Sysops. See the [[Special:Ipblocklist|IP block list]] for the list of currently operational bans and blocks.', +'oversightlog' => 'Suppression log', +'overlogpagetext' => 'Below is a list of the most recent deletions and blocks involving items +hidden from Sysops. Automatically blocked IP addresses are not listed. See the [[Special:Ipblocklist|IP block list]] +for the list of currently operational bans and blocks. + +Blocked users listed here can cannot edit their talk pages and thus can only communicate via email. Their accounts +will remain hidden only as long as they are blocked.', + +# History merging +'mergehistory' => 'Merge page histories', +'mergehistory-header' => 'This page lets you merge revisions of the history of one source page into a newer page. +Please make sure that this change will maintain historical page continuity. + +At least the current revision of the source page must be left.', +'mergehistory-box' => 'Merge revisions of two pages:', +'mergehistory-from' => 'Source page:', +'mergehistory-into' => 'Destination page:', +'mergehistory-list' => 'Mergeable edit history', +'mergehistory-merge' => 'The following revisions of [[:$1|$1]] can be merged into [[:$2|$2]]. Use the radio +button column to merge in only the revisions created at or before the specified time. Note that you will have to +reselect any options if you use the navigation links.', +'mergehistory-go' => 'Show mergeable edits', +'mergehistory-submit' => 'Merge revisions', +'mergehistory-empty' => 'No revisions can be merged', +'mergehistory-success' => '$3 revisions of [[:$1]] successfully merged into [[:$2]].', +'mergehistory-fail' => 'Unable to perform history merge, please recheck the page and time parameters.', + +'mergelog' => 'Merge log', +'pagemerge-logentry' => 'merged $1 into $2 (revisions up to $3)', +'revertmerge' => 'Unmerge', +'mergelogpagetext' => 'Below is a list of the most recent merges of one page history into another.', # Diffs 'history-title' => 'Revision history of "$1"', @@ -1322,6 +1354,11 @@ Unselected groups will not be changed. You can deselect a group with CTRL + Left 'grouppage-sysop' => '{{ns:project}}:Administrators', 'grouppage-bureaucrat' => '{{ns:project}}:Bureaucrats', +'oversight' => 'Oversight', +'group-oversight' => 'Oversights', +'group-oversight-member' => 'Oversight', +'grouppage-oversight' => '{{ns:project}}:Oversight', + # User rights log 'rightslog' => 'User rights log', 'rightslogtext' => 'This is a log of changes to user rights.', @@ -1665,6 +1702,7 @@ The [http://meta.wikimedia.org/wiki/Help:Job_queue job queue] length is '''\$7'' 'specialpages-summary' => '', # only translate this message to other languages if you have to change it 'spheading' => 'Special pages for all users', 'restrictedpheading' => 'Restricted special pages', +'restrictedlheading' => 'Restricted logs', 'rclsub' => '(to pages linked from "$1")', 'newpages' => 'New pages', 'newpages-summary' => '', # only translate this message to other languages if you have to change it @@ -1703,10 +1741,10 @@ further information about books you are looking for:', 'specialloguserlabel' => 'User:', 'speciallogtitlelabel' => 'Title:', 'log' => 'Logs', -'all-logs-page' => 'All logs', +'all-logs-page' => 'All public logs', 'log-search-legend' => 'Search for logs', 'log-search-submit' => 'Go', -'alllogstext' => 'Combined display of all available logs of {{SITENAME}}. +'alllogstext' => 'Combined display of all available public logs of {{SITENAME}}. You can narrow down the view by selecting a log type, the user name, or the affected page.', 'logempty' => 'No matching items in log.', 'log-title-wildcard' => 'Search titles starting with this text', @@ -1853,6 +1891,7 @@ consequences, and that you are doing this in accordance with 'deletedtext' => '"$1" has been deleted. See $2 for a record of recent deletions.', 'deletedarticle' => 'deleted "[[$1]]"', +'suppressedarticle' => 'suppressed "[[$1]]"', 'dellogpage' => 'Deletion log', 'dellogpagetext' => 'Below is a list of the most recent deletions.', 'deletionlog' => 'deletion log', @@ -1873,6 +1912,7 @@ Last edit was by [[User:$3|$3]] ([[User talk:$3|Talk]]).', 'sessionfailure' => 'There seems to be a problem with your login session; this action has been canceled as a precaution against session hijacking. Please hit "back" and reload the page you came from, then try again.', + 'protectlogpage' => 'Protection log', 'protectlogtext' => 'Below is a list of page locks and unlocks. See the [[Special:Protectedpages|protected pages list]] for the list of currently operational page protections.', 'protectedarticle' => 'protected "[[$1]]"', @@ -1880,6 +1920,7 @@ Please hit "back" and reload the page you came from, then try again.', 'unprotectedarticle' => 'unprotected "[[$1]]"', 'protectsub' => '(Setting protection level for "$1")', 'confirmprotect' => 'Confirm protection', +'protect-fileonly' => 'Apply edit restrictions to file uploads only', 'protectcomment' => 'Comment:', 'protectexpiry' => 'Expires:', 'protect_expiry_invalid' => 'Expiry time is invalid.', @@ -1910,6 +1951,7 @@ Here are the current settings for the page $1:', # Restrictions (nouns) 'restriction-edit' => 'Edit', 'restriction-move' => 'Move', +'restriction-upload' => 'Upload', # Restriction levels 'restriction-level-sysop' => 'full protected', @@ -1918,25 +1960,29 @@ Here are the current settings for the page $1:', # Undelete 'undelete' => 'View deleted pages', +'undeleterevs' => 'Deleted revisions', 'undeletepage' => 'View and restore deleted pages', 'viewdeletedpage' => 'View deleted pages', +'undeletepagetitle' => '\'\'\'The following consists of deleted revisions of [[:$1]]\'\'\'.', 'undeletepagetext' => 'The following pages have been deleted but are still in the archive and can be restored. The archive may be periodically cleaned out.', -'undeleteextrahelp' => "To restore the entire page, leave all checkboxes deselected and -click '''''Restore'''''. To perform a selective restoration, check the boxes corresponding to the -revisions to be restored, and click '''''Restore'''''. Clicking '''''Reset''''' will clear the -comment field and all checkboxes.", +'undeleteextrahelp' => "To restore the entire page, leave all radios deselected and click '''''Restore'''''. +To perform a selective restoration, check the desired restore point below and click '''''Restore'''''. +Clicking '''''Reset''''' will reset this form. Note that you will have to reselect any options if you +use the navigation links.", 'undeleterevisions' => '$1 {{PLURAL:$1|revision|revisions}} archived', 'undeletehistory' => 'If you restore the page, all revisions will be restored to the history. If a new page with the same name has been created since the deletion, the restored revisions will appear in the prior history, and the current revision of the live page -will not be automatically replaced. Also note that restrictions on file revisions are lost upon restoration', -'undeleterevdel' => "Undeletion will not be performed if it will result in the top page revision being -partially deleted. In such cases, you must uncheck or unhide the newest deleted revisions. Revisions of files -that you don't have permission to view will not be restored.", +will not be automatically replaced.', +'undeleterevdel' => 'Undeletion will not be performed if either it would result in the top page/image revision +being restricted. Histories of different pages cannot be merged unless the live page is a redirect with no edit history.', 'undeletehistorynoadmin' => 'This article has been deleted. The reason for deletion is shown in the summary below, along with details of the users who had edited this page before deletion. The actual text of these deleted revisions is only available to administrators.', +'restorepoint' => 'Use the radio button column to restore only revisions from the specified time onwards.', +'restorenone' => '(select this button to restore none of these revisions)', + 'undelete-revision' => 'Deleted revision of $1 (as of $2) by $3:', 'undeleterevision-missing' => 'Invalid or missing revision. You may have a bad link, or the revision may have been restored or removed from the archive.', diff --git a/maintenance/rebuildrecentchanges.inc b/maintenance/rebuildrecentchanges.inc index 5101815385..1e14040a32 100644 --- a/maintenance/rebuildrecentchanges.inc +++ b/maintenance/rebuildrecentchanges.inc @@ -11,7 +11,6 @@ function rebuildRecentChangesTablePass1() { $fname = 'rebuildRecentChangesTablePass1'; $dbw = wfGetDB( DB_MASTER ); - extract( $dbw->tableNames( 'recentchanges', 'cur', 'old' ) ); $dbw->delete( 'recentchanges', '*' ); @@ -35,6 +34,7 @@ function rebuildRecentChangesTablePass1() 'rc_this_oldid' => 'rev_id', 'rc_last_oldid' => 0, // is this ok? 'rc_type' => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ), + 'rc_deleted' => 'rev_deleted' ), array( 'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ), 'rev_page=page_id' @@ -98,6 +98,70 @@ function rebuildRecentChangesTablePass2() } function rebuildRecentChangesTablePass3() +{ + $fname = 'rebuildRecentChangesTablePass3'; + $dbw = wfGetDB( DB_MASTER ); + + print( "Loading from user, page, and logging tables...\n" ); + + global $wgRCMaxAge, $wgLogRestrictions; + + // Exclude non-public logs + $avoidLogs = array(); + if( isset($wgLogRestrictions) ) { + foreach ( $wgLogRestrictions as $logtype => $right ) { + // Do not show private logs when not specifically requested + if ( $right !='*' ) { + $safetype =$dbw->strencode( $logtype ); + $avoidLogs[] = "'$safetype'"; + } + } + } + // Some logs don't go in RC. This can't really detect all of those ... :( + $avoidLogs[] = "'patrol'"; // hack...we don't want this here + + if( !empty($avoidLogs) ) { + $skipLogs = 'log_type NOT IN(' . implode(',',$avoidLogs) . ')'; + } else { + $skipLogs = '1 = 1'; + } + + $cutoff = time() - $wgRCMaxAge; + $dbw->insertSelect( 'recentchanges', array( 'logging', 'page', 'user' ), + array( + 'rc_timestamp' => 'log_timestamp', + 'rc_cur_time' => 'log_timestamp', + 'rc_user' => 'log_user', + 'rc_user_text' => 'user_name', + 'rc_namespace' => 'log_namespace', + 'rc_title' => 'log_title', + 'rc_comment' => 'log_comment', + 'rc_minor' => 0, + 'rc_bot' => 0, + 'rc_new' => 0, + 'rc_cur_id' => 0, + 'rc_this_oldid' => 0, + 'rc_last_oldid' => 0, + 'rc_type' => RC_LOG, + 'rc_cur_id' => 'page_id', + 'rc_log_type' => 'log_type', + 'rc_log_action' => 'log_action', + 'rc_logid' => 'log_id', + 'rc_params' => 'log_params', + 'rc_deleted' => 'log_deleted' + ), array( + 'log_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ), + 'log_user=user_id', + 'log_namespace=page_namespace', + 'log_title=page_title', + $skipLogs + ), $fname, + array(), // INSERT options + array( 'ORDER BY' => 'log_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options + ); +} + +function rebuildRecentChangesTablePass4() { global $wgGroupPermissions, $wgUseRCPatrol; diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php index a94780e219..7825625179 100644 --- a/maintenance/rebuildrecentchanges.php +++ b/maintenance/rebuildrecentchanges.php @@ -17,7 +17,8 @@ $wgDBpassword = $wgDBadminpassword; rebuildRecentChangesTablePass1(); rebuildRecentChangesTablePass2(); -rebuildRecentChangesTablePass3(); // flag bot edits +rebuildRecentChangesTablePass3(); // logs entries +rebuildRecentChangesTablePass4(); // flag bot edits print "Done.\n"; exit();