From 90ce609ab648292ad9077925cdd53fc3b939c161 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 11 Oct 2007 21:07:20 +0000 Subject: [PATCH] * (bug 7872) Deleted revisions can now be viewed as diffs showing changes against the previous revision, whether currently deleted or live. In cases of mixed or merged histories this may not produce ideal results. Currently only auto-selected previous revision is available to diff against; in future could potentially allow diffing against any other revision. 'Show changes' button may currently display on the individual revision view form even if there's no prior revision available. Should be correct in the list view though. --- RELEASE-NOTES | 2 + includes/SpecialUndelete.php | 168 ++++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 4 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index b7b4ff4d15..25b3252ca1 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -35,6 +35,8 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN * Clarify instructions given when an exception is thrown * AuthPlugin added strictUserAuth() method to allow per-user override of the strict() authentication behavior. +* (bug 7872) Deleted revisions can now be viewed as diffs showing changes + against the previous revision, whether currently deleted or live. === Bug fixes in 1.12 === diff --git a/includes/SpecialUndelete.php b/includes/SpecialUndelete.php index 5678a81e72..3dfc5c8a76 100644 --- a/includes/SpecialUndelete.php +++ b/includes/SpecialUndelete.php @@ -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 @@ -478,6 +531,7 @@ 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 != "" ) { @@ -619,6 +673,17 @@ class UndeleteForm { $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 ); + $wgOut->addHtml( '
' ); + } else { + $wgOut->addHtml( 'No previous revision found.' ); + } + } + $wgOut->addHtml( '

' . wfMsgHtml( 'undelete-revision', $link, $time, $user ) . '

' ); wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ); @@ -651,16 +716,83 @@ 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( + "
" . + "" . + "" . + "" . + "" . + "" . + "" . + "" . + "" . + "" . + $diffEngine->generateDiffBody( + $previousRev->getText(), $currentRev->getText() ) . + "
" . + $this->diffHeader( $previousRev ) . + "" . + $this->diffHeader( $currentRev ) . + "
" . + "
\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 + '
' . + $sk->makeLinkObj( $targetPage, + wfMsgHtml( 'revisionasof', + $wgLang->timeanddate( $rev->getTimestamp() ) ), + $targetQuery ) . + ( $isDeleted ? ' ' . wfMsgHtml( 'deletedrev' ) : '' ) . + '
' . + '
' . + $sk->revUserTools( $rev ) . '
' . + '
' . + '
' . + $sk->revComment( $rev ) . '
' . + '
'; + } + /** * Show a deleted file version requested by the visitor. */ @@ -792,16 +924,32 @@ class UndeleteForm { # The page's stored (deleted) history: $wgOut->addHTML("