diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2008-03-21 11:49:34 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2008-03-21 11:49:34 +0100 |
commit | 086ae52d12011746a75f5588e877347bc0457352 (patch) | |
tree | e73263c7a29d0f94fafb874562610e16eb292ba8 /includes/SpecialUndelete.php | |
parent | 749e7fb2bae7bbda855de3c9e319435b9f698ff7 (diff) |
Update auf MediaWiki 1.12.0
Diffstat (limited to 'includes/SpecialUndelete.php')
-rw-r--r-- | includes/SpecialUndelete.php | 248 |
1 files changed, 213 insertions, 35 deletions
diff --git a/includes/SpecialUndelete.php b/includes/SpecialUndelete.php index 5678a81e..e6f6298c 100644 --- a/includes/SpecialUndelete.php +++ b/includes/SpecialUndelete.php @@ -57,7 +57,7 @@ class PageArchive { $title = Title::newFromText( $prefix ); if( $title ) { $ns = $title->getNamespace(); - $encPrefix = $dbr->escapeLike( $title->getDbKey() ); + $encPrefix = $dbr->escapeLike( $title->getDBkey() ); } else { // Prolly won't work too good // @todo handle bare namespace names cleanly? @@ -132,7 +132,7 @@ class PageArchive { 'fa_user', 'fa_user_text', 'fa_timestamp' ), - array( 'fa_name' => $this->title->getDbKey() ), + array( 'fa_name' => $this->title->getDBkey() ), __METHOD__, array( 'ORDER BY' => 'fa_timestamp DESC' ) ); $ret = $dbr->resultObject( $res ); @@ -174,7 +174,7 @@ class PageArchive { 'ar_text_id', 'ar_len' ), array( 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDbkey(), + 'ar_title' => $this->title->getDBkey(), 'ar_timestamp' => $dbr->timestamp( $timestamp ) ), __METHOD__ ); if( $row ) { @@ -194,6 +194,59 @@ class PageArchive { return null; } } + + /** + * Return the most-previous revision, either live or deleted, against + * the deleted revision given by timestamp. + * + * May produce unexpected results in case of history merges or other + * unusual time issues. + * + * @param string $timestamp + * @return Revision or null + */ + function getPreviousRevision( $timestamp ) { + $dbr = wfGetDB( DB_SLAVE ); + + // Check the previous deleted revision... + $row = $dbr->selectRow( 'archive', + 'ar_timestamp', + array( 'ar_namespace' => $this->title->getNamespace(), + 'ar_title' => $this->title->getDBkey(), + 'ar_timestamp < ' . + $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ), + __METHOD__, + array( + 'ORDER BY' => 'ar_timestamp DESC', + 'LIMIT' => 1 ) ); + $prevDeleted = $row ? wfTimestamp( TS_MW, $row->ar_timestamp ) : false; + + $row = $dbr->selectRow( array( 'page', 'revision' ), + array( 'rev_id', 'rev_timestamp' ), + array( + 'page_namespace' => $this->title->getNamespace(), + 'page_title' => $this->title->getDBkey(), + 'page_id = rev_page', + 'rev_timestamp < ' . + $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ), + __METHOD__, + array( + 'ORDER BY' => 'rev_timestamp DESC', + 'LIMIT' => 1 ) ); + $prevLive = $row ? wfTimestamp( TS_MW, $row->rev_timestamp ) : false; + $prevLiveId = $row ? intval( $row->rev_id ) : null; + + if( $prevLive && $prevLive > $prevDeleted ) { + // Most prior revision was live + return Revision::newFromId( $prevLiveId ); + } elseif( $prevDeleted ) { + // Most prior revision was deleted + return $this->getRevision( $prevDeleted ); + } else { + // No prior revision on this page. + return null; + } + } /** * Get the text from an archive row containing ar_text, ar_flags and ar_text_id @@ -259,7 +312,8 @@ class PageArchive { * @param string $comment * @param array $fileVersions * - * @return true on success. + * @return array(number of file revisions restored, number of image revisions restored, log message) + * on success, false on failure */ function undelete( $timestamps, $comment = '', $fileVersions = array() ) { // If both the set of text revisions and file revisions are empty, @@ -279,6 +333,8 @@ class PageArchive { if( $restoreText ) { $textRestored = $this->undeleteRevisions( $timestamps ); + if($textRestored === false) // It must be one of UNDELETE_* + return false; } else { $textRestored = 0; } @@ -288,14 +344,14 @@ class PageArchive { $log = new LogPage( 'delete' ); if( $textRestored && $filesRestored ) { - $reason = wfMsgForContent( 'undeletedrevisions-files', + $reason = wfMsgExt( 'undeletedrevisions-files', array( 'content', 'parsemag' ), $wgContLang->formatNum( $textRestored ), $wgContLang->formatNum( $filesRestored ) ); } elseif( $textRestored ) { - $reason = wfMsgForContent( 'undeletedrevisions', + $reason = wfMsgExt( 'undeletedrevisions', array( 'content', 'parsemag' ), $wgContLang->formatNum( $textRestored ) ); } elseif( $filesRestored ) { - $reason = wfMsgForContent( 'undeletedfiles', + $reason = wfMsgExt( 'undeletedfiles', array( 'content', 'parsemag' ), $wgContLang->formatNum( $filesRestored ) ); } else { wfDebug( "Undelete: nothing undeleted...\n" ); @@ -306,11 +362,7 @@ class PageArchive { $reason .= ": {$comment}"; $log->addEntry( 'restore', $this->title, $reason ); - if ( $this->fileStatus && !$this->fileStatus->ok ) { - return false; - } else { - return true; - } + return array($textRestored, $filesRestored, $reason); } /** @@ -322,9 +374,12 @@ class PageArchive { * @param string $comment * @param array $fileVersions * - * @return int number of revisions restored + * @return mixed number of revisions restored or false on failure */ private function undeleteRevisions( $timestamps ) { + if ( wfReadOnly() ) + return false; + $restoreAll = empty( $timestamps ); $dbw = wfGetDB( DB_MASTER ); @@ -376,6 +431,7 @@ class PageArchive { 'ar_minor_edit', 'ar_flags', 'ar_text_id', + 'ar_page_id', 'ar_len' ), /* WHERE */ array( 'ar_namespace' => $this->title->getNamespace(), @@ -420,7 +476,12 @@ class PageArchive { ) ); $revision->insertOn( $dbw ); $restored++; + + wfRunHooks( 'ArticleRevisionUndeleted', array( &$this->title, $revision, $row->ar_page_id ) ); } + // Was anything restored at all? + if($restored == 0) + return 0; if( $revision ) { // Attach the latest revision to the page... @@ -438,8 +499,14 @@ class PageArchive { wfRunHooks( 'ArticleUndelete', array( &$this->title, false ) ); Article::onArticleEdit( $this->title ); } + + if( $this->title->getNamespace() == NS_IMAGE ) { + $update = new HTMLCacheUpdate( $this->title, 'imagelinks' ); + $update->doUpdate(); + } } else { - # Something went terribly wrong! + // Revision couldn't be created. This is very weird + return self::UNDELETE_UNKNOWNERR; } # Now that it's safely stored, take it out of the archive @@ -478,12 +545,13 @@ class UndeleteForm { $wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) ); $this->mRestore = $request->getCheck( 'restore' ) && $posted; $this->mPreview = $request->getCheck( 'preview' ) && $posted; + $this->mDiff = $request->getCheck( 'diff' ); $this->mComment = $request->getText( 'wpComment' ); if( $par != "" ) { $this->mTarget = $par; } - if ( $wgUser->isAllowed( 'delete' ) && !$wgUser->isBlocked() ) { + if ( $wgUser->isAllowed( 'undelete' ) && !$wgUser->isBlocked() ) { $this->mAllowed = true; } else { $this->mAllowed = false; @@ -546,7 +614,7 @@ class UndeleteForm { function showSearchForm() { global $wgOut, $wgScript; - $wgOut->addWikiText( wfMsg( 'undelete-header' ) ); + $wgOut->addWikiMsg( 'undelete-header' ); $wgOut->addHtml( Xml::openElement( 'form', array( @@ -569,11 +637,11 @@ class UndeleteForm { global $wgLang, $wgContLang, $wgUser, $wgOut; if( $result->numRows() == 0 ) { - $wgOut->addWikiText( wfMsg( 'undelete-no-results' ) ); + $wgOut->addWikiMsg( 'undelete-no-results' ); return; } - $wgOut->addWikiText( wfMsg( "undeletepagetext" ) ); + $wgOut->addWikiMsg( "undeletepagetext" ); $sk = $wgUser->getSkin(); $undelete = SpecialPage::getTitleFor( 'Undelete' ); @@ -604,21 +672,34 @@ class UndeleteForm { $rev = $archive->getRevision( $timestamp ); if( !$rev ) { - $wgOut->addWikiTexT( wfMsg( 'undeleterevision-missing' ) ); + $wgOut->addWikiMsg( 'undeleterevision-missing' ); return; } $wgOut->setPageTitle( wfMsg( 'undeletepage' ) ); $link = $skin->makeKnownLinkObj( - $self, - htmlspecialchars( $this->mTargetObj->getPrefixedText() ), - 'target=' . $this->mTargetObj->getPrefixedUrl() + SpecialPage::getTitleFor( 'Undelete', $this->mTargetObj->getPrefixedDBkey() ), + htmlspecialchars( $this->mTargetObj->getPrefixedText() ) ); - $time = htmlspecialchars( $wgLang->timeAndDate( $timestamp ) ); + $time = htmlspecialchars( $wgLang->timeAndDate( $timestamp, true ) ); $user = $skin->userLink( $rev->getUser(), $rev->getUserText() ) . $skin->userToolLinks( $rev->getUser(), $rev->getUserText() ); - + + if( $this->mDiff ) { + $previousRev = $archive->getPreviousRevision( $timestamp ); + if( $previousRev ) { + $this->showDiff( $previousRev, $rev ); + if( $wgUser->getOption( 'diffonly' ) ) { + return; + } else { + $wgOut->addHtml( '<hr />' ); + } + } else { + $wgOut->addHtml( wfMsgHtml( 'undelete-nodiff' ) ); + } + } + $wgOut->addHtml( '<p>' . wfMsgHtml( 'undelete-revision', $link, $time, $user ) . '</p>' ); wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ); @@ -651,17 +732,84 @@ class UndeleteForm { 'name' => 'wpEditToken', 'value' => $wgUser->editToken() ) ) . wfElement( 'input', array( - 'type' => 'hidden', + 'type' => 'submit', 'name' => 'preview', - 'value' => '1' ) ) . + 'value' => wfMsg( 'showpreview' ) ) ) . wfElement( 'input', array( + 'name' => 'diff', 'type' => 'submit', - 'value' => wfMsg( 'showpreview' ) ) ) . + 'value' => wfMsg( 'showdiff' ) ) ) . wfCloseElement( 'form' ) . wfCloseElement( 'div' ) ); } /** + * Build a diff display between this and the previous either deleted + * or non-deleted edit. + * @param Revision $previousRev + * @param Revision $currentRev + * @return string HTML + */ + function showDiff( $previousRev, $currentRev ) { + global $wgOut, $wgUser; + + $diffEngine = new DifferenceEngine(); + $diffEngine->showDiffStyle(); + $wgOut->addHtml( + "<div>" . + "<table border='0' width='98%' cellpadding='0' cellspacing='4' class='diff'>" . + "<col class='diff-marker' />" . + "<col class='diff-content' />" . + "<col class='diff-marker' />" . + "<col class='diff-content' />" . + "<tr>" . + "<td colspan='2' width='50%' align='center' class='diff-otitle'>" . + $this->diffHeader( $previousRev ) . + "</td>" . + "<td colspan='2' width='50%' align='center' class='diff-ntitle'>" . + $this->diffHeader( $currentRev ) . + "</td>" . + "</tr>" . + $diffEngine->generateDiffBody( + $previousRev->getText(), $currentRev->getText() ) . + "</table>" . + "</div>\n" ); + + } + + private function diffHeader( $rev ) { + global $wgUser, $wgLang, $wgLang; + $sk = $wgUser->getSkin(); + $isDeleted = !( $rev->getId() && $rev->getTitle() ); + if( $isDeleted ) { + /// @fixme $rev->getTitle() is null for deleted revs...? + $targetPage = SpecialPage::getTitleFor( 'Undelete' ); + $targetQuery = 'target=' . + $this->mTargetObj->getPrefixedUrl() . + '×tamp=' . + wfTimestamp( TS_MW, $rev->getTimestamp() ); + } else { + /// @fixme getId() may return non-zero for deleted revs... + $targetPage = $rev->getTitle(); + $targetQuery = 'oldid=' . $rev->getId(); + } + return + '<div id="mw-diff-otitle1"><strong>' . + $sk->makeLinkObj( $targetPage, + wfMsgHtml( 'revisionasof', + $wgLang->timeanddate( $rev->getTimestamp(), true ) ), + $targetQuery ) . + ( $isDeleted ? ' ' . wfMsgHtml( 'deletedrev' ) : '' ) . + '</strong></div>' . + '<div id="mw-diff-otitle2">' . + $sk->revUserTools( $rev ) . '<br/>' . + '</div>' . + '<div id="mw-diff-otitle3">' . + $sk->revComment( $rev ) . '<br/>' . + '</div>'; + } + + /** * Show a deleted file version requested by the visitor. */ function showFile( $key ) { @@ -694,14 +842,14 @@ class UndeleteForm { /* $text = $archive->getLastRevisionText(); if( is_null( $text ) ) { - $wgOut->addWikiText( wfMsg( "nohistory" ) ); + $wgOut->addWikiMsg( "nohistory" ); return; } */ if ( $this->mAllowed ) { - $wgOut->addWikiText( wfMsg( "undeletehistory" ) ); + $wgOut->addWikiMsg( "undeletehistory" ); } else { - $wgOut->addWikiText( wfMsg( "undeletehistorynoadmin" ) ); + $wgOut->addWikiMsg( "undeletehistorynoadmin" ); } # List all stored revisions @@ -792,16 +940,32 @@ class UndeleteForm { # The page's stored (deleted) history: $wgOut->addHTML("<ul>"); $target = urlencode( $this->mTarget ); + $remaining = $revisions->numRows(); + $earliestLiveTime = $this->getEarliestTime( $this->mTargetObj ); + while( $row = $revisions->fetchObject() ) { + $remaining--; $ts = wfTimestamp( TS_MW, $row->ar_timestamp ); if ( $this->mAllowed ) { $checkBox = Xml::check( "ts$ts" ); $pageLink = $sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), "target=$target×tamp=$ts" ); + if( ($remaining > 0) || + ($earliestLiveTime && $ts > $earliestLiveTime ) ) { + $diffLink = '(' . + $sk->makeKnownLinkObj( $titleObj, + wfMsgHtml( 'diff' ), + "target=$target×tamp=$ts&diff=prev" ) . + ')'; + } else { + // No older revision to diff against + $diffLink = ''; + } } else { $checkBox = ''; $pageLink = $wgLang->timeanddate( $ts, true ); + $diffLink = ''; } $userLink = $sk->userLink( $row->ar_user, $row->ar_user_text ) . $sk->userToolLinks( $row->ar_user, $row->ar_user_text ); $stxt = ''; @@ -813,13 +977,13 @@ class UndeleteForm { } } $comment = $sk->commentBlock( $row->ar_comment ); - $wgOut->addHTML( "<li>$checkBox $pageLink . . $userLink $stxt $comment</li>\n" ); + $wgOut->addHTML( "<li>$checkBox $pageLink $diffLink . . $userLink $stxt $comment</li>\n" ); } $revisions->free(); $wgOut->addHTML("</ul>"); } else { - $wgOut->addWikiText( wfMsg( "nohistory" ) ); + $wgOut->addWikiMsg( "nohistory" ); } if( $haveFiles ) { @@ -863,9 +1027,25 @@ class UndeleteForm { return true; } + + private function getEarliestTime( $title ) { + $dbr = wfGetDB( DB_SLAVE ); + if( $title->exists() ) { + $min = $dbr->selectField( 'revision', + 'MIN(rev_timestamp)', + array( 'rev_page' => $title->getArticleId() ), + __METHOD__ ); + return wfTimestampOrNull( TS_MW, $min ); + } + return null; + } function undelete() { global $wgOut, $wgUser; + if ( wfReadOnly() ) { + $wgOut->readOnlyPage(); + return; + } if( !is_null( $this->mTargetObj ) ) { $archive = new PageArchive( $this->mTargetObj ); @@ -874,7 +1054,7 @@ class UndeleteForm { $this->mComment, $this->mFileVersions ); - if( $ok ) { + if( is_array($ok) ) { $skin = $wgUser->getSkin(); $link = $skin->makeKnownLinkObj( $this->mTargetObj ); $wgOut->addHtml( wfMsgWikiHtml( 'undeletedpage', $link ) ); @@ -893,5 +1073,3 @@ class UndeleteForm { return false; } } - - |