(bug 18726) Fixed double URL escaping in the links to Special:RevisionDelete in the...
[lhc/web/wiklou.git] / includes / specials / SpecialUndelete.php
index 69e8076..3a3e571 100644 (file)
@@ -119,7 +119,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(
@@ -336,7 +336,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;
@@ -461,25 +461,10 @@ 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( $makepage ) {
                        $newid  = $article->insertOn( $dbw );
@@ -541,10 +526,17 @@ 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 );
+                               // We don't handle well with top revision deleted
+                               if( $revision->getVisibility() ) {
+                                       $dbw->update( 'revision', 
+                                               array( 'rev_deleted' => 0 ),
+                                               array( 'rev_id' => $revision->getId() ),
+                                               __METHOD__
+                                       );
+                               }
                        }
 
                        if( $newid ) {
@@ -555,7 +547,7 @@ class PageArchive {
                                Article::onArticleEdit( $this->title );
                        }
 
-                       if( $this->title->getNamespace() == NS_IMAGE ) {
+                       if( $this->title->getNamespace() == NS_FILE ) {
                                $update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
                                $update->doUpdate();
                        }
@@ -577,7 +569,7 @@ class PageArchive {
  */
 class UndeleteForm {
        var $mAction, $mTarget, $mTimestamp, $mRestore, $mInvert, $mTargetObj;
-       var $mTargetTimestamp, $mAllowed, $mComment;
+       var $mTargetTimestamp, $mAllowed, $mComment, $mToken;
 
        function UndeleteForm( $request, $par = "" ) {
                global $wgUser;
@@ -596,6 +588,7 @@ class UndeleteForm {
                $this->mDiff = $request->getCheck( 'diff' );
                $this->mComment = $request->getText( 'wpComment' );
                $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $wgUser->isAllowed( 'suppressrevision' );
+               $this->mToken = $request->getVal( 'token' );
 
                if( $par != "" ) {
                        $this->mTarget = $par;
@@ -649,7 +642,7 @@ class UndeleteForm {
                                        $this->showList( $result );
                                }
                        } else {
-                               $wgOut->addWikiText( wfMsgHtml( 'undelete-header' ) );
+                               $wgOut->addWikiMsg( 'undelete-header' );
                        }
                        return;
                }
@@ -662,6 +655,9 @@ class UndeleteForm {
                        if( !$file->userCan( File::DELETED_FILE ) ) {
                                $wgOut->permissionRequired( 'suppressrevision' );
                                return false;
+                       } elseif ( !$wgUser->matchEditToken( $this->mToken, $this->mFile ) ) {
+                               $this->showFileConfirmationForm( $this->mFile );
+                               return false;
                        } else {
                                return $this->showFile( $this->mFile );
                        }
@@ -683,17 +679,16 @@ class UndeleteForm {
                        Xml::openElement( 'form', array(
                                'method' => 'get',
                                'action' => $wgScript ) ) .
-                       '<fieldset>' .
-                       Xml::element( 'legend', array(),
-                               wfMsg( 'undelete-search-box' ) ) .
+                       Xml::fieldset( wfMsg( 'undelete-search-box' ) ) .
                        Xml::hidden( 'title',
                                SpecialPage::getTitleFor( 'Undelete' )->getPrefixedDbKey() ) .
                        Xml::inputLabel( wfMsg( 'undelete-search-prefix' ),
                                'prefix', 'prefix', 20,
-                               $this->mSearchPrefix ) .
+                               $this->mSearchPrefix ) . ' ' .
                        Xml::submitButton( wfMsg( 'undelete-search-submit' ) ) .
-                       '</fieldset>' .
-                       '</form>' );
+                       Xml::closeElement( 'fieldset' ) .
+                       Xml::closeElement( 'form' )
+               );
        }
 
        // Generic list of deleted pages
@@ -705,7 +700,7 @@ class UndeleteForm {
                        return;
                }
 
-               $wgOut->addWikiMsg( "undeletepagetext" );
+               $wgOut->addWikiMsg( 'undeletepagetext', $wgLang->formatNum( $result->numRows() ) );
 
                $sk = $wgUser->getSkin();
                $undelete = SpecialPage::getTitleFor( 'Undelete' );
@@ -714,7 +709,6 @@ class UndeleteForm {
                        $title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
                        $link = $sk->makeKnownLinkObj( $undelete, htmlspecialchars( $title->getPrefixedText() ),
                                'target=' . $title->getPrefixedUrl() );
-                       #$revs = wfMsgHtml( 'undeleterevisions', $wgLang->formatNum( $row->count ) );
                        $revs = wfMsgExt( 'undeleterevisions',
                                array( 'parseinline' ),
                                $wgLang->formatNum( $row->count ) );
@@ -743,10 +737,10 @@ class UndeleteForm {
 
                if( $rev->isDeleted(Revision::DELETED_TEXT) ) {
                        if( !$rev->userCan(Revision::DELETED_TEXT) ) {
-                               $wgOut->addWikiText( wfMsg( 'rev-deleted-text-permission' ) );
+                               $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n", 'rev-deleted-text-permission' );
                                return;
                        } else {
-                               $wgOut->addWikiText( wfMsg( 'rev-deleted-text-view' ) );
+                               $wgOut->wrapWikiMsg( "<div class='mw-warning plainlinks'>\n$1</div>\n", 'rev-deleted-text-view' );
                                $wgOut->addHTML( '<br/>' );
                                // and we are allowed to see...
                        }
@@ -769,7 +763,7 @@ class UndeleteForm {
                                        $wgOut->addHTML( '<hr />' );
                                }
                        } else {
-                               $wgOut->addHTML( wfMsgHtml( 'undelete-nodiff' ) );
+                               $wgOut->addWikiMsg( 'undelete-nodiff' );
                        }
                }
 
@@ -780,13 +774,16 @@ class UndeleteForm {
                $t = htmlspecialchars( $wgLang->time( $timestamp, true ) );
                $user = $skin->revUserTools( $rev );
 
-               $wgOut->addHTML( '<p>' . wfMsgHtml( 'undelete-revision', $link, $time, $user, $d, $t ) . '</p>' );
+               if( $this->mPreview ) {
+                       $openDiv = '<div id="mw-undelete-revision" class="mw-warning">';
+               } else {
+                       $openDiv = '<div id="mw-undelete-revision">';
+               }
 
+               $wgOut->addHTML( $openDiv . wfMsgWikiHtml( 'undelete-revision', $link, $time, $user, $d, $t ) . '</div>' );
                wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) );
 
                if( $this->mPreview ) {
-                       $wgOut->addHTML( "<hr />\n" );
-
                        //Hide [edit]s
                        $popts = $wgOut->parserOptions();
                        $popts->setEditSection( false );
@@ -795,37 +792,37 @@ class UndeleteForm {
                }
 
                $wgOut->addHTML(
-                       wfElement( 'textarea', array(
+                       Xml::element( 'textarea', array(
                                        'readonly' => 'readonly',
                                        'cols' => intval( $wgUser->getOption( 'cols' ) ),
                                        'rows' => intval( $wgUser->getOption( 'rows' ) ) ),
                                $rev->getText( Revision::FOR_THIS_USER ) . "\n" ) .
-                       wfOpenElement( 'div' ) .
-                       wfOpenElement( 'form', array(
+                       Xml::openElement( 'div' ) .
+                       Xml::openElement( 'form', array(
                                'method' => 'post',
                                'action' => $self->getLocalURL( "action=submit" ) ) ) .
-                       wfElement( 'input', array(
+                       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' ) );
        }
 
        /**
@@ -836,7 +833,7 @@ class UndeleteForm {
         * @return string HTML
         */
        function showDiff( $previousRev, $currentRev ) {
-               global $wgOut, $wgUser;
+               global $wgOut;
 
                $diffEngine = new DifferenceEngine();
                $diffEngine->showDiffStyle();
@@ -869,31 +866,76 @@ class UndeleteForm {
                if( $isDeleted ) {
                        /// @fixme $rev->getTitle() is null for deleted revs...?
                        $targetPage = SpecialPage::getTitleFor( 'Undelete' );
-                       $targetQuery = 'target=' .
-                               $this->mTargetObj->getPrefixedUrl() .
-                               '&timestamp=' .
-                               wfTimestamp( TS_MW, $rev->getTimestamp() );
+                       $targetQuery = array(
+                               'target' => $this->mTargetObj->getPrefixedUrl(),
+                               'timestamp' => wfTimestamp( TS_MW, $rev->getTimestamp() )
+                       );
                } else {
                        /// @fixme getId() may return non-zero for deleted revs...
                        $targetPage = $rev->getTitle();
-                       $targetQuery = 'oldid=' . $rev->getId();
+                       $targetQuery = array( 'oldid' => $rev->getId() );
+               }
+               // Add show/hide link if available
+               if( $wgUser->isAllowed( 'deleterevision' ) ) {
+                       // If revision was hidden from sysops
+                       if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
+                               $del = ' ' . Xml::tags( 'span', array( 'class'=>'mw-revdelundel-link' ),
+                                       '(' . wfMsgHtml('rev-delundel') . ')' );
+                       // Otherwise, show the link...
+                       } else {
+                               $query = array( 'target' => $this->mTargetObj->getPrefixedDbkey(),
+                                       'artimestamp' => $rev->getTimestamp() );
+                               $del = ' ' . $sk->revDeleteLink( $query,
+                                       $rev->isDeleted( Revision::DELETED_RESTRICTED ) );
+                       }
+               } else {
+                       $del = '';
                }
                return
                        '<div id="mw-diff-'.$prefix.'title1"><strong>' .
-                               $sk->makeLinkObj( $targetPage,
-                                       wfMsgHtml( 'revisionasof',
-                                               $wgLang->timeanddate( $rev->getTimestamp(), true ) ),
-                                       $targetQuery ) .
+                               $sk->link(
+                                       $targetPage,
+                                       wfMsgHtml(
+                                               'revisionasof',
+                                               $wgLang->timeanddate( $rev->getTimestamp(), true )
+                                       ),
+                                       array(),
+                                       $targetQuery
+                               ) .
                                ( $isDeleted ? ' ' . wfMsgHtml( 'deletedrev' ) : '' ) .
                        '</strong></div>' .
                        '<div id="mw-diff-'.$prefix.'title2">' .
                                $sk->revUserTools( $rev ) . '<br/>' .
                        '</div>' .
                        '<div id="mw-diff-'.$prefix.'title3">' .
-                               $sk->revComment( $rev ) . '<br/>' .
+                               $sk->revComment( $rev ) . $del . '<br/>' .
                        '</div>';
        }
 
+       /**
+        * 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' => SpecialPage::getTitleFor( 'Undelete' )->getLocalUrl(
+                                       'target=' . urlencode( $this->mTarget ) .
+                                       '&file=' . urlencode( $key ) .
+                                       '&token=' . urlencode( $wgUser->editToken( $key ) ) )
+                               )
+                       ) .
+                       Xml::submitButton( wfMsg( 'undelete-show-file-submit' ) ) .
+                       '</form>'
+               );
+       }
+
        /**
         * Show a deleted file version requested by the visitor.
         */
@@ -923,7 +965,7 @@ class UndeleteForm {
                        $wgOut->setPagetitle( wfMsg( 'viewdeletedpage' ) );
                }
 
-               $wgOut->addWikiText( wfMsgHtml( 'undeletepagetitle', $this->mTargetObj->getPrefixedText()) );
+               $wgOut->addWikiMsg( 'undeletepagetitle', $this->mTargetObj->getPrefixedText() );
 
                $archive = new PageArchive( $this->mTargetObj );
                /*
@@ -978,6 +1020,11 @@ class UndeleteForm {
                # 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)
@@ -995,8 +1042,7 @@ 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' ) ) .
                                        "<tr>
                                                <td colspan='2'>" .
@@ -1014,8 +1060,8 @@ class UndeleteForm {
                                        <tr>
                                                <td>&nbsp;</td>
                                                <td class='mw-submit'>" .
-                                                       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' ) ) .
                                                "</td>
                                        </tr>" .
@@ -1115,19 +1161,16 @@ class UndeleteForm {
                $comment = $sk->revComment( $rev );
                $revdlink = '';
                if( $wgUser->isAllowed( 'deleterevision' ) ) {
-                       $revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
                        if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
                        // If revision was hidden from sysops
-                               $del = wfMsgHtml('rev-delundel');
+                               $revdlink = Xml::tags( 'span', array( 'class'=>'mw-revdelundel-link' ),
+                                       '('.wfMsgHtml('rev-delundel').')' );
                        } else {
-                               $del = $sk->makeKnownLinkObj( $revdel,
-                                       wfMsgHtml('rev-delundel'),
-                                       'target=' . $this->mTargetObj->getPrefixedUrl() . "&artimestamp=$ts" );
-                               // Bolden oversighted content
-                               if( $rev->isDeleted( Revision::DELETED_RESTRICTED ) )
-                                       $del = "<strong>$del</strong>";
+                               $query = array( 'target' => $this->mTargetObj->getPrefixedDBkey(),
+                                       'artimestamp' => $ts
+                               );
+                               $revdlink = $sk->revDeleteLink( $query, $rev->isDeleted( Revision::DELETED_RESTRICTED ) );
                        }
-                       $revdlink = "<tt>(<small>$del</small>)</tt>";
                }
 
                return "<li>$checkBox $revdlink ($last) $pageLink . . $userLink $stxt $comment</li>";
@@ -1161,20 +1204,15 @@ class UndeleteForm {
                $comment = $this->getFileComment( $file, $sk );
                $revdlink = '';
                if( $wgUser->isAllowed( 'deleterevision' ) ) {
-                       $revdel = SpecialPage::getTitleFor( 'Revisiondelete' );
                        if( !$file->userCan(File::DELETED_RESTRICTED ) ) {
                        // If revision was hidden from sysops
-                               $del = wfMsgHtml('rev-delundel');
+                               $revdlink = Xml::tags( 'span', array( 'class'=>'mw-revdelundel-link' ), '('.wfMsgHtml('rev-delundel').')' );
                        } 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 = "<strong>$del</strong>";
+                               $query = array( 'target' => $this->mTargetObj->getPrefixedDBkey(),
+                                       'fileid' => $row->fa_id
+                               );
+                               $revdlink = $sk->revDeleteLink( $query, $file->isDeleted( File::DELETED_RESTRICTED ) );
                        }
-                       $revdlink = "<tt>(<small>$del</small>)</tt>";
                }
                return "<li>$checkBox $revdlink $pageLink . . $userLink $data $comment</li>\n";
        }
@@ -1202,13 +1240,15 @@ class UndeleteForm {
         * @return string
         */
        function getFileLink( $file, $titleObj, $ts, $key, $sk ) {
-               global $wgLang;
+               global $wgLang, $wgUser;
 
                if( !$file->userCan(File::DELETED_FILE) ) {
                        return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>';
                } else {
                        $link = $sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ),
-                               "target=".$this->mTargetObj->getPrefixedUrl()."&file=$key" );
+                               "target=".$this->mTargetObj->getPrefixedUrl().
+                               "&file=$key" .
+                               "&token=" . urlencode( $wgUser->editToken( $key ) ) );
                        if( $file->isDeleted(File::DELETED_FILE) )
                                $link = '<span class="history-deleted">' . $link . '</span>';
                        return $link;