X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fspecials%2FSpecialUndelete.php;h=e6137251b98834cc95758219243cb2231fdeff87;hb=90c703d61c485c633b214f78f48102c2848b82d8;hp=effa45ceae344efd5c9e30e7e9a4a83ae9d7bb7f;hpb=81e7adc6ad69fb34519da83fe90dba830c38e0a9;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php index effa45ceae..e6137251b9 100644 --- a/includes/specials/SpecialUndelete.php +++ b/includes/specials/SpecialUndelete.php @@ -1,25 +1,29 @@ execute(); -} - /** * Used to show archived pages and eventually restore them. + * * @ingroup SpecialPage */ class PageArchive { @@ -28,7 +32,7 @@ class PageArchive { function __construct( $title ) { if( is_null( $title ) ) { - throw new MWException( 'Archiver() given a null title.'); + throw new MWException( __METHOD__ . ' given a null title.' ); } $this->title = $title; } @@ -50,6 +54,7 @@ class PageArchive { * given title prefix. * Returns result wrapper with (ar_namespace, ar_title, count) fields. * + * @param $prefix String: title prefix * @return ResultWrapper */ public static function listPagesByPrefix( $prefix ) { @@ -58,16 +63,15 @@ class PageArchive { $title = Title::newFromText( $prefix ); if( $title ) { $ns = $title->getNamespace(); - $encPrefix = $dbr->escapeLike( $title->getDBkey() ); + $prefix = $title->getDBkey(); } else { // Prolly won't work too good // @todo handle bare namespace names cleanly? $ns = 0; - $encPrefix = $dbr->escapeLike( $prefix ); } $conds = array( 'ar_namespace' => $ns, - "ar_title LIKE '$encPrefix%'", + 'ar_title' . $dbr->buildLike( $prefix, $dbr->anyString() ), ); return self::listPages( $dbr, $conds ); } @@ -119,7 +123,7 @@ class PageArchive { * @todo Does this belong in Image for fuller encapsulation? */ function listFiles() { - if( $this->title->getNamespace() == NS_IMAGE ) { + if( $this->title->getNamespace() == NS_FILE ) { $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'filearchive', array( @@ -154,7 +158,8 @@ class PageArchive { * Fetch (and decompress if necessary) the stored text for the deleted * revision of the page with the given timestamp. * - * @return string + * @param $timestamp String + * @return String * @deprecated Use getRevision() for more flexible information */ function getRevisionText( $timestamp ) { @@ -165,7 +170,8 @@ class PageArchive { /** * Return a Revision object containing data for the deleted revision. * Note that the result *may* or *may not* have a null page ID. - * @param string $timestamp + * + * @param $timestamp String * @return Revision */ function getRevision( $timestamp ) { @@ -188,20 +194,7 @@ class PageArchive { 'ar_timestamp' => $dbr->timestamp( $timestamp ) ), __METHOD__ ); if( $row ) { - return new Revision( array( - 'page' => $this->title->getArticleId(), - 'id' => $row->ar_rev_id, - 'text' => ($row->ar_text_id - ? null - : Revision::getRevisionText( $row, 'ar_' ) ), - 'comment' => $row->ar_comment, - 'user' => $row->ar_user, - 'user_text' => $row->ar_user_text, - 'timestamp' => $row->ar_timestamp, - 'minor_edit' => $row->ar_minor_edit, - 'text_id' => $row->ar_text_id, - 'deleted' => $row->ar_deleted, - 'len' => $row->ar_len) ); + return Revision::newFromArchiveRow( $row, array( 'page' => $this->title->getArticleId() ) ); } else { return null; } @@ -214,7 +207,7 @@ class PageArchive { * May produce unexpected results in case of history merges or other * unusual time issues. * - * @param string $timestamp + * @param $timestamp String * @return Revision or null */ function getPreviousRevision( $timestamp ) { @@ -262,6 +255,9 @@ class PageArchive { /** * Get the text from an archive row containing ar_text, ar_flags and ar_text_id + * + * @param $row Object: database row + * @return Revision */ function getTextFromRow( $row ) { if( is_null( $row->ar_text_id ) ) { @@ -286,7 +282,7 @@ class PageArchive { * * If there are no archived revisions for the page, returns NULL. * - * @return string + * @return String */ function getLastRevisionText() { $dbr = wfGetDB( DB_SLAVE ); @@ -294,18 +290,19 @@ class PageArchive { array( 'ar_text', 'ar_flags', 'ar_text_id' ), array( 'ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey() ), - 'PageArchive::getLastRevisionText', + __METHOD__, array( 'ORDER BY' => 'ar_timestamp DESC' ) ); if( $row ) { return $this->getTextFromRow( $row ); } else { - return NULL; + return null; } } /** * Quick check if any archived revisions are present for the page. - * @return bool + * + * @return Boolean */ function isDeleted() { $dbr = wfGetDB( DB_SLAVE ); @@ -320,10 +317,10 @@ class PageArchive { * Once restored, the items will be removed from the archive tables. * The deletion log will be updated with an undeletion notice. * - * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. - * @param string $comment - * @param array $fileVersions - * @param bool $unsuppress + * @param $timestamps Array: pass an empty array to restore all revisions, otherwise list the ones to undelete. + * @param $comment String + * @param $fileVersions Array + * @param $unsuppress Boolean * * @return array(number of file revisions restored, number of image revisions restored, log message) * on success, false on failure @@ -336,7 +333,7 @@ class PageArchive { $restoreText = $restoreAll || !empty( $timestamps ); $restoreFiles = $restoreAll || !empty( $fileVersions ); - if( $restoreFiles && $this->title->getNamespace() == NS_IMAGE ) { + if( $restoreFiles && $this->title->getNamespace() == NS_FILE ) { $img = wfLocalFile( $this->title ); $this->fileStatus = $img->restore( $fileVersions, $unsuppress ); $filesRestored = $this->fileStatus->successCount; @@ -345,7 +342,7 @@ class PageArchive { } if( $restoreText ) { - $textRestored = $this->undeleteRevisions( $timestamps, $unsuppress ); + $textRestored = $this->undeleteRevisions( $timestamps, $unsuppress, $comment ); if($textRestored === false) // It must be one of UNDELETE_* return false; } else { @@ -372,7 +369,7 @@ class PageArchive { } if( trim( $comment ) != '' ) - $reason .= ": {$comment}"; + $reason .= wfMsgForContent( 'colon-separator' ) . $comment; $log->addEntry( 'restore', $this->title, $reason ); return array($textRestored, $filesRestored, $reason); @@ -383,14 +380,13 @@ class PageArchive { * to the cur/old tables. If the page currently exists, all revisions will * be stuffed into old, otherwise the most recent will go into cur. * - * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. - * @param string $comment - * @param array $fileVersions - * @param bool $unsuppress, remove all ar_deleted/fa_deleted restrictions of seletected revs + * @param $timestamps Array: pass an empty array to restore all revisions, otherwise list the ones to undelete. + * @param $comment String + * @param $unsuppress Boolean: remove all ar_deleted/fa_deleted restrictions of seletected revs * - * @return mixed number of revisions restored or false on failure + * @return Mixed: number of revisions restored or false on failure */ - private function undeleteRevisions( $timestamps, $unsuppress = false ) { + private function undeleteRevisions( $timestamps, $unsuppress = false, $comment = '' ) { if ( wfReadOnly() ) return false; $restoreAll = empty( $timestamps ); @@ -399,13 +395,14 @@ class PageArchive { # Does this page already exist? We'll have to update it... $article = new Article( $this->title ); - $options = 'FOR UPDATE'; + $options = 'FOR UPDATE'; // lock page $page = $dbw->selectRow( 'page', array( 'page_id', 'page_latest' ), array( 'page_namespace' => $this->title->getNamespace(), 'page_title' => $this->title->getDBkey() ), __METHOD__, - $options ); + $options + ); if( $page ) { $makepage = false; # Page already exists. Import the history, and if necessary @@ -461,66 +458,54 @@ class PageArchive { 'ar_title' => $this->title->getDBkey(), $oldones ), __METHOD__, - /* options */ array( - 'ORDER BY' => 'ar_timestamp' ) - ); + /* options */ array( 'ORDER BY' => 'ar_timestamp' ) + ); $ret = $dbw->resultObject( $result ); - $rev_count = $dbw->numRows( $result ); - if( $rev_count ) { - # We need to seek around as just using DESC in the ORDER BY - # would leave the revisions inserted in the wrong order - $first = $ret->fetchObject(); - $ret->seek( $rev_count - 1 ); - $last = $ret->fetchObject(); - // We don't handle well changing the top revision's settings - if( !$unsuppress && $last->ar_deleted && $last->ar_timestamp > $previousTimestamp ) { - wfDebug( __METHOD__.": restoration would result in a deleted top revision\n" ); - return false; - } - $ret->seek( 0 ); + if( !$rev_count ) { + wfDebug( __METHOD__.": no revisions to restore\n" ); + return false; // ??? } + $ret->seek( $rev_count - 1 ); // move to last + $row = $ret->fetchObject(); // get newest archived rev + $ret->seek( 0 ); // move back + if( $makepage ) { + // Check the state of the newest to-be version... + if( !$unsuppress && ($row->ar_deleted & Revision::DELETED_TEXT) ) { + return false; // we can't leave the current revision like this! + } + // Safe to insert now... $newid = $article->insertOn( $dbw ); $pageId = $newid; + } else { + // Check if a deleted revision will become the current revision... + if( $row->ar_timestamp > $previousTimestamp ) { + // Check the state of the newest to-be version... + if( !$unsuppress && ($row->ar_deleted & Revision::DELETED_TEXT) ) { + return false; // we can't leave the current revision like this! + } + } } $revision = null; $restored = 0; - while( $row = $ret->fetchObject() ) { - if( $row->ar_text_id ) { - // Revision was deleted in 1.5+; text is in - // the regular text table, use the reference. - // Specify null here so the so the text is - // dereferenced for page length info if needed. - $revText = null; - } else { - // Revision was deleted in 1.4 or earlier. - // Text is squashed into the archive row, and - // a new text table entry will be created for it. - $revText = Revision::getRevisionText( $row, 'ar_' ); - } + foreach ( $ret as $row ) { // Check for key dupes due to shitty archive integrity. if( $row->ar_rev_id ) { $exists = $dbw->selectField( 'revision', '1', array('rev_id' => $row->ar_rev_id), __METHOD__ ); if( $exists ) continue; // don't throw DB errors } - - $revision = new Revision( array( - 'page' => $pageId, - 'id' => $row->ar_rev_id, - 'text' => $revText, - 'comment' => $row->ar_comment, - 'user' => $row->ar_user, - 'user_text' => $row->ar_user_text, - 'timestamp' => $row->ar_timestamp, - 'minor_edit' => $row->ar_minor_edit, - 'text_id' => $row->ar_text_id, - 'deleted' => $unsuppress ? 0 : $row->ar_deleted, - 'len' => $row->ar_len + // Insert one revision at a time...maintaining deletion status + // unless we are specifically removing all restrictions... + $revision = Revision::newFromArchiveRow( $row, + array( + 'page' => $pageId, + 'deleted' => $unsuppress ? 0 : $row->ar_deleted ) ); + $revision->insertOn( $dbw ); $restored++; @@ -533,7 +518,7 @@ class PageArchive { 'ar_title' => $this->title->getDBkey(), $oldones ), __METHOD__ ); - + // Was anything restored at all? if( $restored == 0 ) return 0; @@ -541,27 +526,27 @@ class PageArchive { if( $revision ) { // Attach the latest revision to the page... $wasnew = $article->updateIfNewerOn( $dbw, $revision, $previousRevId ); - if( $newid || $wasnew ) { // Update site stats, link tables, etc $article->createUpdates( $revision ); } if( $newid ) { - wfRunHooks( 'ArticleUndelete', array( &$this->title, true ) ); + wfRunHooks( 'ArticleUndelete', array( &$this->title, true, $comment ) ); Article::onArticleCreate( $this->title ); } else { - wfRunHooks( 'ArticleUndelete', array( &$this->title, false ) ); + wfRunHooks( 'ArticleUndelete', array( &$this->title, false, $comment ) ); Article::onArticleEdit( $this->title ); } - if( $this->title->getNamespace() == NS_IMAGE ) { + if( $this->title->getNamespace() == NS_FILE ) { $update = new HTMLCacheUpdate( $this->title, 'imagelinks' ); $update->doUpdate(); } } else { // Revision couldn't be created. This is very weird - return self::UNDELETE_UNKNOWNERR; + wfDebug( "Undelete: unknown error...\n" ); + return false; } return $restored; @@ -571,47 +556,59 @@ class PageArchive { } /** - * The HTML form for Special:Undelete, which allows users with the appropriate - * permissions to view and restore deleted content. + * Special page allowing users with the appropriate permissions to view + * and restore deleted content. + * * @ingroup SpecialPage */ -class UndeleteForm { - var $mAction, $mTarget, $mTimestamp, $mRestore, $mTargetObj; - var $mTargetTimestamp, $mAllowed, $mComment; +class SpecialUndelete extends SpecialPage { + var $mAction, $mTarget, $mTimestamp, $mRestore, $mInvert, $mTargetObj; + var $mTargetTimestamp, $mAllowed, $mCanView, $mComment, $mToken, $mRequest; + + function __construct( $request = null ) { + parent::__construct( 'Undelete', 'deletedhistory' ); + + if ( $request === null ) { + global $wgRequest; + $this->mRequest = $wgRequest; + } else { + $this->mRequest = $request; + } + } - function UndeleteForm( $request, $par = "" ) { + function loadRequest() { global $wgUser; - $this->mAction = $request->getVal( 'action' ); - $this->mTarget = $request->getVal( 'target' ); - $this->mSearchPrefix = $request->getText( 'prefix' ); - $time = $request->getVal( 'timestamp' ); + $this->mAction = $this->mRequest->getVal( 'action' ); + $this->mTarget = $this->mRequest->getVal( 'target' ); + $this->mSearchPrefix = $this->mRequest->getText( 'prefix' ); + $time = $this->mRequest->getVal( 'timestamp' ); $this->mTimestamp = $time ? wfTimestamp( TS_MW, $time ) : ''; - $this->mFile = $request->getVal( 'file' ); + $this->mFile = $this->mRequest->getVal( 'file' ); + + $posted = $this->mRequest->wasPosted() && + $wgUser->matchEditToken( $this->mRequest->getVal( 'wpEditToken' ) ); + $this->mRestore = $this->mRequest->getCheck( 'restore' ) && $posted; + $this->mInvert = $this->mRequest->getCheck( 'invert' ) && $posted; + $this->mPreview = $this->mRequest->getCheck( 'preview' ) && $posted; + $this->mDiff = $this->mRequest->getCheck( 'diff' ); + $this->mComment = $this->mRequest->getText( 'wpComment' ); + $this->mUnsuppress = $this->mRequest->getVal( 'wpUnsuppress' ) && $wgUser->isAllowed( 'suppressrevision' ); + $this->mToken = $this->mRequest->getVal( 'token' ); - $posted = $request->wasPosted() && - $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' ); - $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $wgUser->isAllowed( 'suppressrevision' ); - - if( $par != "" ) { - $this->mTarget = $par; - } if ( $wgUser->isAllowed( 'undelete' ) && !$wgUser->isBlocked() ) { - $this->mAllowed = true; - } else { + $this->mAllowed = true; // user can restore + $this->mCanView = true; // user can view content + } elseif ( $wgUser->isAllowed( 'deletedtext' ) ) { + $this->mAllowed = false; // user cannot restore + $this->mCanView = true; // user can view content + } else { // user can only view the list of revisions $this->mAllowed = false; + $this->mCanView = false; $this->mTimestamp = ''; $this->mRestore = false; } - if ( $this->mTarget !== "" ) { - $this->mTargetObj = Title::newFromURL( $this->mTarget ); - } else { - $this->mTargetObj = NULL; - } - if( $this->mRestore ) { + + if( $this->mRestore || $this->mInvert ) { $timestamps = array(); $this->mFileVersions = array(); foreach( $_REQUEST as $key => $val ) { @@ -629,14 +626,34 @@ class UndeleteForm { } } - function execute() { + function execute( $par ) { global $wgOut, $wgUser; + + $this->setHeaders(); + if ( !$this->userCanExecute( $wgUser ) ) { + $this->displayRestrictionError(); + return; + } + $this->outputHeader(); + + $this->loadRequest(); + if ( $this->mAllowed ) { $wgOut->setPagetitle( wfMsg( "undeletepage" ) ); } else { $wgOut->setPagetitle( wfMsg( "viewdeletedpage" ) ); } + if( $par != '' ) { + $this->mTarget = $par; + } + if ( $this->mTarget !== '' ) { + $this->mTargetObj = Title::newFromURL( $this->mTarget ); + $wgUser->getSkin()->setRelevantTitle( $this->mTargetObj ); + } else { + $this->mTargetObj = null; + } + if( is_null( $this->mTargetObj ) ) { # Not all users can just browse every deleted page from the list if( $wgUser->isAllowed( 'browsearchive' ) ) { @@ -648,7 +665,7 @@ class UndeleteForm { $this->showList( $result ); } } else { - $wgOut->addWikiText( wfMsgHtml( 'undelete-header' ) ); + $wgOut->addWikiMsg( 'undelete-header' ); } return; } @@ -658,16 +675,34 @@ class UndeleteForm { if( $this->mFile !== null ) { $file = new ArchivedFile( $this->mTargetObj, '', $this->mFile ); // Check if user is allowed to see this file - if( !$file->userCan( File::DELETED_FILE ) ) { - $wgOut->permissionRequired( 'suppressrevision' ); + if ( !$file->exists() ) { + $wgOut->addWikiMsg( 'filedelete-nofile', $this->mFile ); + return; + } else if( !$file->userCan( File::DELETED_FILE ) ) { + if( $file->isDeleted( File::DELETED_RESTRICTED ) ) { + $wgOut->permissionRequired( 'suppressrevision' ); + } else { + $wgOut->permissionRequired( 'deletedtext' ); + } + return false; + } elseif ( !$wgUser->matchEditToken( $this->mToken, $this->mFile ) ) { + $this->showFileConfirmationForm( $this->mFile ); return false; } else { return $this->showFile( $this->mFile ); } } if( $this->mRestore && $this->mAction == "submit" ) { + global $wgUploadMaintenance; + if( $wgUploadMaintenance && $this->mTargetObj && $this->mTargetObj->getNamespace() == NS_FILE ) { + $wgOut->wrapWikiMsg( "
\n$1\n
\n", array( 'filedelete-maintenance' ) ); + return; + } return $this->undelete(); } + if( $this->mInvert && $this->mAction == "submit" ) { + return $this->showHistory( ); + } return $this->showHistory(); } @@ -675,46 +710,48 @@ class UndeleteForm { global $wgOut, $wgScript; $wgOut->addWikiMsg( 'undelete-header' ); - $wgOut->addHtml( + $wgOut->addHTML( Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . - '
' . - Xml::element( 'legend', array(), - wfMsg( 'undelete-search-box' ) ) . - Xml::hidden( 'title', - SpecialPage::getTitleFor( 'Undelete' )->getPrefixedDbKey() ) . + Xml::fieldset( wfMsg( 'undelete-search-box' ) ) . + Html::hidden( 'title', + $this->getTitle()->getPrefixedDbKey() ) . Xml::inputLabel( wfMsg( 'undelete-search-prefix' ), 'prefix', 'prefix', 20, - $this->mSearchPrefix ) . + $this->mSearchPrefix ) . ' ' . Xml::submitButton( wfMsg( 'undelete-search-submit' ) ) . - '
' . - '' ); + Xml::closeElement( 'fieldset' ) . + Xml::closeElement( 'form' ) + ); } // Generic list of deleted pages private function showList( $result ) { - global $wgLang, $wgContLang, $wgUser, $wgOut; + global $wgLang, $wgUser, $wgOut; if( $result->numRows() == 0 ) { $wgOut->addWikiMsg( 'undelete-no-results' ); return; } - $wgOut->addWikiMsg( "undeletepagetext" ); + $wgOut->addWikiMsg( 'undeletepagetext', $wgLang->formatNum( $result->numRows() ) ); $sk = $wgUser->getSkin(); - $undelete = SpecialPage::getTitleFor( 'Undelete' ); + $undelete = $this->getTitle(); $wgOut->addHTML( "\n" ); @@ -724,7 +761,7 @@ class UndeleteForm { private function showRevision( $timestamp ) { global $wgLang, $wgUser, $wgOut; - $self = SpecialPage::getTitleFor( 'Undelete' ); + $skin = $wgUser->getSkin(); if(!preg_match("/[0-9]{14}/",$timestamp)) return 0; @@ -739,19 +776,19 @@ class UndeleteForm { if( $rev->isDeleted(Revision::DELETED_TEXT) ) { if( !$rev->userCan(Revision::DELETED_TEXT) ) { - $wgOut->addWikiText( wfMsg( 'rev-deleted-text-permission' ) ); + $wgOut->wrapWikiMsg( "\n", 'rev-deleted-text-permission' ); return; } else { - $wgOut->addWikiText( wfMsg( 'rev-deleted-text-view' ) ); - $wgOut->addHTML( '
' ); + $wgOut->wrapWikiMsg( "\n", 'rev-deleted-text-view' ); + $wgOut->addHTML( '
' ); // and we are allowed to see... } } $wgOut->setPageTitle( wfMsg( 'undeletepage' ) ); - $link = $skin->makeKnownLinkObj( - SpecialPage::getTitleFor( 'Undelete', $this->mTargetObj->getPrefixedDBkey() ), + $link = $skin->linkKnown( + $this->getTitle( $this->mTargetObj->getPrefixedDBkey() ), htmlspecialchars( $this->mTargetObj->getPrefixedText() ) ); @@ -762,10 +799,10 @@ class UndeleteForm { if( $wgUser->getOption( 'diffonly' ) ) { return; } else { - $wgOut->addHtml( '
' ); + $wgOut->addHTML( '
' ); } } else { - $wgOut->addHtml( wfMsgHtml( 'undelete-nodiff' ) ); + $wgOut->addWikiMsg( 'undelete-nodiff' ); } } @@ -776,67 +813,91 @@ class UndeleteForm { $t = htmlspecialchars( $wgLang->time( $timestamp, true ) ); $user = $skin->revUserTools( $rev ); - $wgOut->addHtml( '

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

' ); + if( $this->mPreview ) { + $openDiv = '
'; + } else { + $openDiv = '
'; + } + + // Revision delete links + $canHide = $wgUser->isAllowed( 'deleterevision' ); + if( $this->mDiff ) { + $revdlink = ''; // diffs already have revision delete links + } else if( $canHide || ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) { + if( !$rev->userCan(Revision::DELETED_RESTRICTED ) ) { + $revdlink = $skin->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops + } else { + $query = array( + 'type' => 'archive', + 'target' => $this->mTargetObj->getPrefixedDBkey(), + 'ids' => $rev->getTimestamp() + ); + $revdlink = $skin->revDeleteLink( $query, + $rev->isDeleted( File::DELETED_RESTRICTED ), $canHide ); + } + } else { + $revdlink = ''; + } + $wgOut->addHTML( $openDiv . $revdlink . wfMsgWikiHtml( 'undelete-revision', $link, $time, $user, $d, $t ) . '
' ); wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ); if( $this->mPreview ) { - $wgOut->addHtml( "
\n" ); - //Hide [edit]s $popts = $wgOut->parserOptions(); $popts->setEditSection( false ); $wgOut->parserOptions( $popts ); - $wgOut->addWikiTextTitleTidy( $rev->getText( false ), $this->mTargetObj, true ); + $wgOut->addWikiTextTitleTidy( $rev->getText( Revision::FOR_THIS_USER ), $this->mTargetObj, true ); } - $wgOut->addHtml( - wfElement( 'textarea', array( + $wgOut->addHTML( + Xml::element( 'textarea', array( 'readonly' => 'readonly', 'cols' => intval( $wgUser->getOption( 'cols' ) ), 'rows' => intval( $wgUser->getOption( 'rows' ) ) ), - $rev->getText( false ) . "\n" ) . - wfOpenElement( 'div' ) . - wfOpenElement( 'form', array( + $rev->getText( Revision::FOR_THIS_USER ) . "\n" ) . + Xml::openElement( 'div' ) . + Xml::openElement( 'form', array( 'method' => 'post', - 'action' => $self->getLocalURL( "action=submit" ) ) ) . - wfElement( 'input', array( + 'action' => $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) ) ) ) . + Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'target', 'value' => $this->mTargetObj->getPrefixedDbKey() ) ) . - wfElement( 'input', array( + Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'timestamp', 'value' => $timestamp ) ) . - wfElement( 'input', array( + Xml::element( 'input', array( 'type' => 'hidden', 'name' => 'wpEditToken', 'value' => $wgUser->editToken() ) ) . - wfElement( 'input', array( + Xml::element( 'input', array( 'type' => 'submit', 'name' => 'preview', 'value' => wfMsg( 'showpreview' ) ) ) . - wfElement( 'input', array( + Xml::element( 'input', array( 'name' => 'diff', 'type' => 'submit', 'value' => wfMsg( 'showdiff' ) ) ) . - wfCloseElement( 'form' ) . - wfCloseElement( 'div' ) ); + Xml::closeElement( 'form' ) . + Xml::closeElement( '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 + * + * @param $previousRev Revision + * @param $currentRev Revision + * @return String: HTML */ function showDiff( $previousRev, $currentRev ) { - global $wgOut, $wgUser; + global $wgOut; - $diffEngine = new DifferenceEngine(); + $diffEngine = new DifferenceEngine( $previousRev->getTitle() ); $diffEngine->showDiffStyle(); - $wgOut->addHtml( + $wgOut->addHTML( "
" . "" . "" . @@ -845,51 +906,99 @@ class UndeleteForm { "" . "" . "" . + $this->diffHeader( $previousRev, 'o' ) . + "\n" . "" . + $this->diffHeader( $currentRev, 'n' ) . + "\n" . "" . $diffEngine->generateDiffBody( $previousRev->getText(), $currentRev->getText() ) . "
" . - $this->diffHeader( $previousRev ) . - "" . - $this->diffHeader( $currentRev ) . - "
" . - "
\n" ); - + "
\n" + ); } - private function diffHeader( $rev ) { - global $wgUser, $wgLang, $wgLang; + private function diffHeader( $rev, $prefix ) { + global $wgUser, $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() ); + /// @todo Fixme: $rev->getTitle() is null for deleted revs...? + $targetPage = $this->getTitle(); + $targetQuery = array( + 'target' => $this->mTargetObj->getPrefixedText(), + 'timestamp' => wfTimestamp( TS_MW, $rev->getTimestamp() ) + ); } else { - /// @fixme getId() may return non-zero for deleted revs... + /// @todo Fixme getId() may return non-zero for deleted revs... $targetPage = $rev->getTitle(); - $targetQuery = 'oldid=' . $rev->getId(); + $targetQuery = array( 'oldid' => $rev->getId() ); + } + // Add show/hide deletion links if available + $canHide = $wgUser->isAllowed( 'deleterevision' ); + if( $canHide || ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) { + $del = ' '; + if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) { + $del .= $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops + } else { + $query = array( + 'type' => 'archive', + 'target' => $this->mTargetObj->getPrefixedDbkey(), + 'ids' => $rev->getTimestamp() + ); + $del .= $sk->revDeleteLink( $query, + $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide ); + } + } else { + $del = ''; } return - '
' . - $sk->makeLinkObj( $targetPage, - wfMsgHtml( 'revisionasof', - $wgLang->timeanddate( $rev->getTimestamp(), true ) ), - $targetQuery ) . - ( $isDeleted ? ' ' . wfMsgHtml( 'deletedrev' ) : '' ) . + '
' . + $sk->link( + $targetPage, + wfMsgHtml( + 'revisionasof', + htmlspecialchars( $wgLang->timeanddate( $rev->getTimestamp(), true ) ), + htmlspecialchars( $wgLang->date( $rev->getTimestamp(), true ) ), + htmlspecialchars( $wgLang->time( $rev->getTimestamp(), true ) ) + ), + array(), + $targetQuery + ) . '
' . - '
' . - $sk->revUserTools( $rev ) . '
' . + '
' . + $sk->revUserTools( $rev ) . '
' . '
' . - '
' . - $sk->revComment( $rev ) . '
' . + '
' . + $sk->revComment( $rev ) . $del . '
' . '
'; } + /** + * Show a form confirming whether a tokenless user really wants to see a file + */ + private function showFileConfirmationForm( $key ) { + global $wgOut, $wgUser, $wgLang; + $file = new ArchivedFile( $this->mTargetObj, '', $this->mFile ); + $wgOut->addWikiMsg( 'undelete-show-file-confirm', + $this->mTargetObj->getText(), + $wgLang->date( $file->getTimestamp() ), + $wgLang->time( $file->getTimestamp() ) ); + $wgOut->addHTML( + Xml::openElement( 'form', array( + 'method' => 'POST', + 'action' => $this->getTitle()->getLocalUrl( + 'target=' . urlencode( $this->mTarget ) . + '&file=' . urlencode( $key ) . + '&token=' . urlencode( $wgUser->editToken( $key ) ) ) + ) + ) . + Xml::submitButton( wfMsg( 'undelete-show-file-submit' ) ) . + '' + ); + } + /** * Show a deleted file version requested by the visitor. */ @@ -905,12 +1014,15 @@ class UndeleteForm { $wgRequest->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' ); $wgRequest->response()->header( 'Pragma: no-cache' ); - $store = FileStore::get( 'deleted' ); - $store->stream( $key ); + global $IP; + require_once( "$IP/includes/StreamFile.php" ); + $repo = RepoGroup::singleton()->getLocalRepo(); + $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key; + wfStreamFile( $path ); } - private function showHistory() { - global $wgLang, $wgUser, $wgOut; + private function showHistory( ) { + global $wgUser, $wgOut; $sk = $wgUser->getSkin(); if( $this->mAllowed ) { @@ -919,7 +1031,7 @@ class UndeleteForm { $wgOut->setPagetitle( wfMsg( 'viewdeletedpage' ) ); } - $wgOut->addWikiText( wfMsgHtml( 'undeletepagetitle', $this->mTargetObj->getPrefixedText()) ); + $wgOut->wrapWikiMsg( "
\n$1\n
\n", array ( 'undeletepagetitle', $this->mTargetObj->getPrefixedText() ) ); $archive = new PageArchive( $this->mTargetObj ); /* @@ -929,12 +1041,14 @@ class UndeleteForm { return; } */ + $wgOut->addHTML( '
' ); if ( $this->mAllowed ) { $wgOut->addWikiMsg( "undeletehistory" ); $wgOut->addWikiMsg( "undeleterevdel" ); } else { $wgOut->addWikiMsg( "undeletehistorynoadmin" ); } + $wgOut->addHTML( '
' ); # List all stored revisions $revisions = $archive->listRevisions(); @@ -946,7 +1060,7 @@ class UndeleteForm { # Batch existence check on user and talk pages if( $haveRevisions ) { $batch = new LinkBatch(); - while( $row = $revisions->fetchObject() ) { + foreach ( $revisions as $row ) { $batch->addObj( Title::makeTitleSafe( NS_USER, $row->ar_user_text ) ); $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->ar_user_text ) ); } @@ -955,7 +1069,7 @@ class UndeleteForm { } if( $haveFiles ) { $batch = new LinkBatch(); - while( $row = $files->fetchObject() ) { + foreach ( $files as $row ) { $batch->addObj( Title::makeTitleSafe( NS_USER, $row->fa_user_text ) ); $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->fa_user_text ) ); } @@ -964,16 +1078,20 @@ class UndeleteForm { } if ( $this->mAllowed ) { - $titleObj = SpecialPage::getTitleFor( "Undelete" ); - $action = $titleObj->getLocalURL( "action=submit" ); + $action = $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) ); # Start the form here $top = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $action, 'id' => 'undelete' ) ); - $wgOut->addHtml( $top ); + $wgOut->addHTML( $top ); } # Show relevant lines from the deletion log: $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) . "\n" ); LogEventsList::showLogExtract( $wgOut, 'delete', $this->mTargetObj->getPrefixedText() ); + # Show relevant lines from the suppression log: + if( $wgUser->isAllowed( 'suppressionlog' ) ) { + $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'suppress' ) ) . "\n" ); + LogEventsList::showLogExtract( $wgOut, 'suppress', $this->mTargetObj->getPrefixedText() ); + } if( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) { # Format the user-visible controls (comment field, submission button) @@ -981,7 +1099,7 @@ class UndeleteForm { if( $wgUser->isAllowed( 'suppressrevision' ) ) { $unsuppressBox = " -   +   " . Xml::checkLabel( wfMsg('revdelete-unsuppress'), 'wpUnsuppress', 'mw-undelete-unsuppress', $this->mUnsuppress ). @@ -991,11 +1109,10 @@ class UndeleteForm { $unsuppressBox = ""; } $table = - Xml::openElement( 'fieldset' ) . - Xml::element( 'legend', null, wfMsg( 'undelete-fieldset-title' ) ). + Xml::fieldset( wfMsg( 'undelete-fieldset-title' ) ) . Xml::openElement( 'table', array( 'id' => 'mw-undelete-table' ) ) . " - " . + " . wfMsgWikiHtml( 'undeleteextrahelp' ) . " @@ -1008,17 +1125,18 @@ class UndeleteForm { " -   +   " . - Xml::submitButton( wfMsg( 'undeletebtn' ), array( 'name' => 'restore', 'id' => 'mw-undelete-submit' ) ) . - Xml::element( 'input', array( 'type' => 'reset', 'value' => wfMsg( 'undeletereset' ), 'id' => 'mw-undelete-reset' ) ) . + Xml::submitButton( wfMsg( 'undeletebtn' ), array( 'name' => 'restore', 'id' => 'mw-undelete-submit' ) ) . ' ' . + Xml::element( 'input', array( 'type' => 'reset', 'value' => wfMsg( 'undeletereset' ), 'id' => 'mw-undelete-reset' ) ) . ' ' . + Xml::submitButton( wfMsg( 'undeleteinvert' ), array( 'name' => 'invert', 'id' => 'mw-undelete-invert' ) ) . " " . $unsuppressBox . Xml::closeElement( 'table' ) . Xml::closeElement( 'fieldset' ); - $wgOut->addHtml( $table ); + $wgOut->addHTML( $table ); } $wgOut->addHTML( Xml::element( 'h2', null, wfMsg( 'history' ) ) . "\n" ); @@ -1026,11 +1144,10 @@ class UndeleteForm { if( $haveRevisions ) { # The page's stored (deleted) history: $wgOut->addHTML("
    "); - $target = urlencode( $this->mTarget ); $remaining = $revisions->numRows(); - $earliestLiveTime = $this->getEarliestTime( $this->mTargetObj ); + $earliestLiveTime = $this->mTargetObj->getEarliestRevTime(); - while( $row = $revisions->fetchObject() ) { + foreach ( $revisions as $row ) { $remaining--; $wgOut->addHTML( $this->formatRevisionRow( $row, $earliestLiveTime, $remaining, $sk ) ); } @@ -1041,9 +1158,9 @@ class UndeleteForm { } if( $haveFiles ) { - $wgOut->addHtml( Xml::element( 'h2', null, wfMsg( 'filehist' ) ) . "\n" ); - $wgOut->addHtml( "
      " ); - while( $row = $files->fetchObject() ) { + $wgOut->addHTML( Xml::element( 'h2', null, wfMsg( 'filehist' ) ) . "\n" ); + $wgOut->addHTML( "
        " ); + foreach ( $files as $row ) { $wgOut->addHTML( $this->formatFileRow( $row, $sk ) ); } $files->free(); @@ -1052,10 +1169,10 @@ class UndeleteForm { if ( $this->mAllowed ) { # Slip in the hidden controls here - $misc = Xml::hidden( 'target', $this->mTarget ); - $misc .= Xml::hidden( 'wpEditToken', $wgUser->editToken() ); + $misc = Html::hidden( 'target', $this->mTarget ); + $misc .= Html::hidden( 'wpEditToken', $wgUser->editToken() ); $misc .= Xml::closeElement( 'form' ); - $wgOut->addHtml( $misc ); + $wgOut->addHTML( $misc ); } return true; @@ -1064,60 +1181,76 @@ class UndeleteForm { private function formatRevisionRow( $row, $earliestLiveTime, $remaining, $sk ) { global $wgUser, $wgLang; - $rev = new Revision( array( - 'page' => $this->mTargetObj->getArticleId(), - 'comment' => $row->ar_comment, - 'user' => $row->ar_user, - 'user_text' => $row->ar_user_text, - 'timestamp' => $row->ar_timestamp, - 'minor_edit' => $row->ar_minor_edit, - 'deleted' => $row->ar_deleted, - 'len' => $row->ar_len ) ); - + $rev = Revision::newFromArchiveRow( $row, + array( 'page' => $this->mTargetObj->getArticleId() ) ); $stxt = ''; $ts = wfTimestamp( TS_MW, $row->ar_timestamp ); + // Build checkboxen... if( $this->mAllowed ) { - $checkBox = Xml::check( "ts$ts" ); - $titleObj = SpecialPage::getTitleFor( "Undelete" ); - $pageLink = $this->getPageLink( $rev, $titleObj, $ts, $sk ); + if( $this->mInvert ) { + if( in_array( $ts, $this->mTargetTimestamp ) ) { + $checkBox = Xml::check( "ts$ts"); + } else { + $checkBox = Xml::check( "ts$ts", true ); + } + } else { + $checkBox = Xml::check( "ts$ts" ); + } + } else { + $checkBox = ''; + } + // Build page & diff links... + if( $this->mCanView ) { + $titleObj = $this->getTitle(); # Last link if( !$rev->userCan( Revision::DELETED_TEXT ) ) { + $pageLink = htmlspecialchars( $wgLang->timeanddate( $ts, true ) ); $last = wfMsgHtml('diff'); } else if( $remaining > 0 || ($earliestLiveTime && $ts > $earliestLiveTime) ) { - $last = $sk->makeKnownLinkObj( $titleObj, wfMsgHtml('diff'), - "target=" . $this->mTargetObj->getPrefixedUrl() . "×tamp=$ts&diff=prev" ); + $pageLink = $this->getPageLink( $rev, $titleObj, $ts, $sk ); + $last = $sk->linkKnown( + $titleObj, + wfMsgHtml('diff'), + array(), + array( + 'target' => $this->mTargetObj->getPrefixedText(), + 'timestamp' => $ts, + 'diff' => 'prev' + ) + ); } else { + $pageLink = $this->getPageLink( $rev, $titleObj, $ts, $sk ); $last = wfMsgHtml('diff'); } } else { - $checkBox = ''; - $pageLink = $wgLang->timeanddate( $ts, true ); + $pageLink = htmlspecialchars( $wgLang->timeanddate( $ts, true ) ); $last = wfMsgHtml('diff'); } + // User links $userLink = $sk->revUserTools( $rev ); - - if(!is_null($size = $row->ar_len)) { + // Revision text size + if( !is_null($size = $row->ar_len) ) { $stxt = $sk->formatRevisionSize( $size ); } + // Edit summary $comment = $sk->revComment( $rev ); - $revdlink = ''; - if( $wgUser->isAllowed( 'deleterevision' ) ) { - $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); + // Revision delete links + $canHide = $wgUser->isAllowed( 'deleterevision' ); + if( $canHide || ($rev->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) { if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) { - // If revision was hidden from sysops - $del = wfMsgHtml('rev-delundel'); + $revdlink = $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops } else { - $ts = wfTimestamp( TS_MW, $row->ar_timestamp ); - $del = $sk->makeKnownLinkObj( $revdel, - wfMsgHtml('rev-delundel'), - 'target=' . $this->mTargetObj->getPrefixedUrl() . "&artimestamp=$ts" ); - // Bolden oversighted content - if( $rev->isDeleted( Revision::DELETED_RESTRICTED ) ) - $del = "$del"; + $query = array( + 'type' => 'archive', + 'target' => $this->mTargetObj->getPrefixedDBkey(), + 'ids' => $ts + ); + $revdlink = $sk->revDeleteLink( $query, + $rev->isDeleted( Revision::DELETED_RESTRICTED ), $canHide ); } - $revdlink = "($del)"; + } else { + $revdlink = ''; } - return "
      • $checkBox $revdlink ($last) $pageLink . . $userLink $stxt $comment
      • "; } @@ -1130,14 +1263,12 @@ class UndeleteForm { if( $this->mAllowed && $row->fa_storage_key ) { $checkBox = Xml::check( "fileid" . $row->fa_id ); $key = urlencode( $row->fa_storage_key ); - $target = urlencode( $this->mTarget ); - $titleObj = SpecialPage::getTitleFor( "Undelete" ); - $pageLink = $this->getFileLink( $file, $titleObj, $ts, $key, $sk ); + $pageLink = $this->getFileLink( $file, $this->getTitle(), $ts, $key, $sk ); } else { $checkBox = ''; $pageLink = $wgLang->timeanddate( $ts, true ); } - $userLink = $this->getFileUser( $file, $sk ); + $userLink = $this->getFileUser( $file, $sk ); $data = wfMsg( 'widthheight', $wgLang->formatNum( $row->fa_width ), @@ -1147,38 +1278,26 @@ class UndeleteForm { ')'; $data = htmlspecialchars( $data ); $comment = $this->getFileComment( $file, $sk ); - $revdlink = ''; - if( $wgUser->isAllowed( 'deleterevision' ) ) { - $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); + // Add show/hide deletion links if available + $canHide = $wgUser->isAllowed( 'deleterevision' ); + if( $canHide || ($file->getVisibility() && $wgUser->isAllowed('deletedhistory')) ) { if( !$file->userCan(File::DELETED_RESTRICTED ) ) { - // If revision was hidden from sysops - $del = wfMsgHtml('rev-delundel'); + $revdlink = $sk->revDeleteLinkDisabled( $canHide ); // revision was hidden from sysops } else { - $del = $sk->makeKnownLinkObj( $revdel, - wfMsgHtml('rev-delundel'), - 'target=' . $this->mTargetObj->getPrefixedUrl() . - '&fileid=' . $row->fa_id ); - // Bolden oversighted content - if( $file->isDeleted( File::DELETED_RESTRICTED ) ) - $del = "$del"; + $query = array( + 'type' => 'filearchive', + 'target' => $this->mTargetObj->getPrefixedDBkey(), + 'ids' => $row->fa_id + ); + $revdlink = $sk->revDeleteLink( $query, + $file->isDeleted( File::DELETED_RESTRICTED ), $canHide ); } - $revdlink = "($del)"; + } else { + $revdlink = ''; } return "
      • $checkBox $revdlink $pageLink . . $userLink $data $comment
      • \n"; } - 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; - } - /** * Fetch revision text link if it's available to all users * @return string @@ -1186,11 +1305,20 @@ class UndeleteForm { function getPageLink( $rev, $titleObj, $ts, $sk ) { global $wgLang; + $time = htmlspecialchars( $wgLang->timeanddate( $ts, true ) ); + if( !$rev->userCan(Revision::DELETED_TEXT) ) { - return '' . $wgLang->timeanddate( $ts, true ) . ''; + return '' . $time . ''; } else { - $link = $sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), - "target=".$this->mTargetObj->getPrefixedUrl()."×tamp=$ts" ); + $link = $sk->linkKnown( + $titleObj, + $time, + array(), + array( + 'target' => $this->mTargetObj->getPrefixedText(), + 'timestamp' => $ts + ) + ); if( $rev->isDeleted(Revision::DELETED_TEXT) ) $link = '' . $link . ''; return $link; @@ -1199,16 +1327,25 @@ class UndeleteForm { /** * Fetch image view link if it's available to all users - * @return string + * + * @return String: HTML fragment */ function getFileLink( $file, $titleObj, $ts, $key, $sk ) { - global $wgLang; + global $wgLang, $wgUser; if( !$file->userCan(File::DELETED_FILE) ) { return '' . $wgLang->timeanddate( $ts, true ) . ''; } else { - $link = $sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), - "target=".$this->mTargetObj->getPrefixedUrl()."&file=$key" ); + $link = $sk->linkKnown( + $titleObj, + $wgLang->timeanddate( $ts, true ), + array(), + array( + 'target' => $this->mTargetObj->getPrefixedText(), + 'file' => $key, + 'token' => $wgUser->editToken( $key ) + ) + ); if( $file->isDeleted(File::DELETED_FILE) ) $link = '' . $link . ''; return $link; @@ -1217,7 +1354,8 @@ class UndeleteForm { /** * Fetch file's user id if it's available to this user - * @return string + * + * @return String: HTML fragment */ function getFileUser( $file, $sk ) { if( !$file->userCan(File::DELETED_USER) ) { @@ -1233,7 +1371,8 @@ class UndeleteForm { /** * Fetch file upload comment if it's available to this user - * @return string + * + * @return String: HTML fragment */ function getFileComment( $file, $sk ) { if( !$file->userCan(File::DELETED_COMMENT) ) { @@ -1267,11 +1406,11 @@ class UndeleteForm { $wgUser, $this->mComment) ); $skin = $wgUser->getSkin(); - $link = $skin->makeKnownLinkObj( $this->mTargetObj ); - $wgOut->addHtml( wfMsgWikiHtml( 'undeletedpage', $link ) ); + $link = $skin->linkKnown( $this->mTargetObj ); + $wgOut->addHTML( wfMsgWikiHtml( 'undeletedpage', $link ) ); } else { $wgOut->showFatalError( wfMsg( "cannotundelete" ) ); - $wgOut->addHtml( '

        ' . wfMsgHtml( "undeleterevdel" ) . '

        ' ); + $wgOut->addHTML( '

        ' . wfMsgHtml( "undeleterevdel" ) . '

        ' ); } // Show file deletion warnings and errors