Index: trunk/phase3/maintenance/language/messages.inc |
— | — | @@ -877,6 +877,16 @@ |
878 | 878 | 'imagelist_description', |
879 | 879 | 'imagelist_search_for', |
880 | 880 | ), |
| 881 | + 'filerevert' => array( |
| 882 | + 'filerevert', |
| 883 | + 'filerevert-legend', |
| 884 | + 'filerevert-intro', |
| 885 | + 'filerevert-comment', |
| 886 | + 'filerevert-defaultcomment', |
| 887 | + 'filerevert-submit', |
| 888 | + 'filerevert-success', |
| 889 | + 'filerevert-badversion', |
| 890 | + ), |
881 | 891 | 'mimesearch' => array( |
882 | 892 | 'mimesearch', |
883 | 893 | 'mimesearch-summary', |
— | — | @@ -1155,7 +1165,6 @@ |
1156 | 1166 | 'deletionlog', |
1157 | 1167 | 'reverted', |
1158 | 1168 | 'deletecomment', |
1159 | | - 'imagereverted', |
1160 | 1169 | 'rollback', |
1161 | 1170 | 'rollback_short', |
1162 | 1171 | 'rollbacklink', |
Index: trunk/phase3/includes/FileRevertForm.php |
— | — | @@ -0,0 +1,183 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * File reversion user interface |
| 6 | + * |
| 7 | + * @addtogroup Media |
| 8 | + * @author Rob Church <robchur@gmail.com> |
| 9 | + */ |
| 10 | +class FileRevertForm { |
| 11 | + |
| 12 | + private $title = null; |
| 13 | + private $file = null; |
| 14 | + private $oldimage = ''; |
| 15 | + |
| 16 | + /** |
| 17 | + * Constructor |
| 18 | + * |
| 19 | + * @param File $file File we're reverting |
| 20 | + */ |
| 21 | + public function __construct( $file ) { |
| 22 | + $this->title = $file->getTitle(); |
| 23 | + $this->file = $file; |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * Fulfil the request; shows the form or reverts the file, |
| 28 | + * pending authentication, confirmation, etc. |
| 29 | + */ |
| 30 | + public function execute() { |
| 31 | + global $wgOut, $wgRequest, $wgUser, $wgLang, $wgServer; |
| 32 | + $this->setHeaders(); |
| 33 | + |
| 34 | + if( wfReadOnly() ) { |
| 35 | + $wgOut->readOnlyPage(); |
| 36 | + return; |
| 37 | + } elseif( !$wgUser->isLoggedIn() ) { |
| 38 | + $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' ); |
| 39 | + return; |
| 40 | + } elseif( !$this->title->userCan( 'edit' ) ) { |
| 41 | + // The standard read-only thing doesn't make a whole lot of sense |
| 42 | + // here; surely it should show the image or something? -- RC |
| 43 | + $article = new Article( $this->title ); |
| 44 | + $wgOut->readOnlyPage( $article->getContent(), true ); |
| 45 | + //$wgOut->readOnlyPage( new Article( $this->title )->getContent(), true ); |
| 46 | + return; |
| 47 | + } elseif( $wgUser->isBlocked() ) { |
| 48 | + $wgOut->blockedPage(); |
| 49 | + return; |
| 50 | + } |
| 51 | + |
| 52 | + $this->oldimage = $wgRequest->getText( 'oldimage' ); |
| 53 | + $token = $wgRequest->getText( 'wpEditToken' ); |
| 54 | + if( !$this->isValidOldSpec() ) { |
| 55 | + $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars( $this->oldimage ) ); |
| 56 | + return; |
| 57 | + } |
| 58 | + |
| 59 | + if( !$this->haveOldVersion() ) { |
| 60 | + $wgOut->addHtml( wfMsgExt( 'filerevert-badversion', 'parse' ) ); |
| 61 | + $wgOut->returnToMain( false, $this->title ); |
| 62 | + return; |
| 63 | + } |
| 64 | + |
| 65 | + // Perform the reversion if appropriate |
| 66 | + if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->oldimage ) ) { |
| 67 | + $source = $this->file->getArchiveVirtualUrl( $this->oldimage ); |
| 68 | + $comment = $wgRequest->getText( 'wpComment' ); |
| 69 | + // TODO: Preserve file properties from database instead of reloading from file |
| 70 | + $status = $this->file->upload( $source, $comment, $comment ); |
| 71 | + if( $status->isGood() ) { |
| 72 | + $wgOut->addHtml( wfMsgExt( 'filerevert-success', 'parse', $this->title->getText(), |
| 73 | + $wgLang->timeAndDate( $this->getTimestamp() ), |
| 74 | + $wgServer . $this->file->getArchiveUrl( $this->oldimage ) ) ); |
| 75 | + $wgOut->returnToMain( false, $this->title ); |
| 76 | + } else { |
| 77 | + $wgOut->addWikiText( $status->getWikiText() ); |
| 78 | + } |
| 79 | + return; |
| 80 | + } |
| 81 | + |
| 82 | + // Show the form |
| 83 | + $this->showForm(); |
| 84 | + } |
| 85 | + |
| 86 | + /** |
| 87 | + * Show the confirmation form |
| 88 | + */ |
| 89 | + private function showForm() { |
| 90 | + global $wgOut, $wgUser, $wgRequest, $wgLang, $wgContLang, $wgServer; |
| 91 | + |
| 92 | + /* |
| 93 | + $cur = wfFindFile( $this->title ); |
| 94 | + $old = wfFindFile( $this->title, substr( $this->oldimage, 0, 14 ) ); |
| 95 | + */ |
| 96 | + $timestamp = $this->getTimestamp(); |
| 97 | + |
| 98 | + $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction() ) ); |
| 99 | + $form .= Xml::hidden( 'wpEditToken', $wgUser->editToken( $this->oldimage ) ); |
| 100 | + $form .= '<fieldset><legend>' . wfMsgHtml( 'filerevert-legend' ) . '</legend>'; |
| 101 | + $form .= wfMsgExt( 'filerevert-intro', 'parse', $this->title->getText(), |
| 102 | + $wgLang->timeAndDate( $timestamp ), $wgServer . $this->file->getArchiveUrl( $this->oldimage ) ); |
| 103 | + |
| 104 | + /* |
| 105 | + * I was going to do a little comparison (current vs. old) here, |
| 106 | + * but realised it wasn't too straightforward to do a media transform |
| 107 | + * with an *old* file version using the current mechanism. Leaving |
| 108 | + * this here in case it becomes possible in the future. -- RC |
| 109 | + * |
| 110 | + $form .= '<table class="compare-files">'; |
| 111 | + $form .= '<tr>'; |
| 112 | + $form .= '<th>' . wfMsgHtml( 'filerevert-current' ) . '</th>'; |
| 113 | + $form .= '<th>' . wfMsgHtml( 'filerevert-old', $old->getTimestamp() ) . '</th>'; |
| 114 | + $form .= '</tr><tr>'; |
| 115 | + // FIXME: Hard-coding magic numbers makes baby Jesus cry... |
| 116 | + $form .= '<td>' . $this->getThumbnail( $cur, 180 ) . '</td>'; |
| 117 | + $form .= '<td>' . $this->getThumbnail( $old, 180 ) . '</td>'; |
| 118 | + $form .= '</tr>'; |
| 119 | + $form .= '</table>'; |
| 120 | + */ |
| 121 | + |
| 122 | + $form .= '<p>' . Xml::inputLabel( wfMsg( 'filerevert-comment' ), 'wpComment', 'wpComment', |
| 123 | + 40, wfMsgForContent( 'filerevert-defaultcomment', |
| 124 | + $wgContLang->timeAndDate( $timestamp, false, false ) ) ) . '</p>'; |
| 125 | + $form .= '<p>' . Xml::submitButton( wfMsg( 'filerevert-submit' ) ) . '</p>'; |
| 126 | + $form .= '</fieldset>'; |
| 127 | + $form .= '</form>'; |
| 128 | + |
| 129 | + $wgOut->addHtml( $form ); |
| 130 | + } |
| 131 | + |
| 132 | + /** |
| 133 | + * Set headers, titles and other bits |
| 134 | + */ |
| 135 | + private function setHeaders() { |
| 136 | + global $wgOut; |
| 137 | + $wgOut->setPageTitle( wfMsg( 'filerevert', $this->title->getText() ) ); |
| 138 | + $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
| 139 | + } |
| 140 | + |
| 141 | + /** |
| 142 | + * Is the provided `oldimage` value valid? |
| 143 | + * |
| 144 | + * @return bool |
| 145 | + */ |
| 146 | + private function isValidOldSpec() { |
| 147 | + return strlen( $this->oldimage ) >= 16 |
| 148 | + && strpos( $this->oldimage, '/' ) === false |
| 149 | + && strpos( $this->oldimage, '\\' ) === false; |
| 150 | + } |
| 151 | + |
| 152 | + /** |
| 153 | + * Does the provided `oldimage` value correspond |
| 154 | + * to an existing, local, old version of this file? |
| 155 | + * |
| 156 | + * @return bool |
| 157 | + */ |
| 158 | + private function haveOldVersion() { |
| 159 | + $file = wfFindFile( $this->title, $this->oldimage ); |
| 160 | + return $file && $file->exists() && $file->isLocal(); |
| 161 | + } |
| 162 | + |
| 163 | + /** |
| 164 | + * Prepare the form action |
| 165 | + * |
| 166 | + * @return string |
| 167 | + */ |
| 168 | + private function getAction() { |
| 169 | + $q = array(); |
| 170 | + $q[] = 'action=revert'; |
| 171 | + $q[] = 'oldimage=' . urlencode( $this->oldimage ); |
| 172 | + return $this->title->getLocalUrl( implode( '&', $q ) ); |
| 173 | + } |
| 174 | + |
| 175 | + /** |
| 176 | + * Extract the timestamp of the old version |
| 177 | + * |
| 178 | + * @return string |
| 179 | + */ |
| 180 | + private function getTimestamp() { |
| 181 | + return substr( $this->oldimage, 0, 14 ); |
| 182 | + } |
| 183 | + |
| 184 | +} |
\ No newline at end of file |
Property changes on: trunk/phase3/includes/FileRevertForm.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 185 | + native |
Index: trunk/phase3/includes/ImagePage.php |
— | — | @@ -610,56 +610,12 @@ |
611 | 611 | return $status; |
612 | 612 | } |
613 | 613 | |
| 614 | + /** |
| 615 | + * Revert the file to an earlier version |
| 616 | + */ |
614 | 617 | function revert() { |
615 | | - global $wgOut, $wgRequest, $wgUser; |
616 | | - |
617 | | - $oldimage = $wgRequest->getText( 'oldimage' ); |
618 | | - if ( strlen( $oldimage ) < 16 ) { |
619 | | - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) ); |
620 | | - return; |
621 | | - } |
622 | | - if ( strstr( $oldimage, "/" ) || strstr( $oldimage, "\\" ) ) { |
623 | | - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) ); |
624 | | - return; |
625 | | - } |
626 | | - |
627 | | - if ( wfReadOnly() ) { |
628 | | - $wgOut->readOnlyPage(); |
629 | | - return; |
630 | | - } |
631 | | - if( $wgUser->isAnon() ) { |
632 | | - $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' ); |
633 | | - return; |
634 | | - } |
635 | | - if ( ! $this->mTitle->userCan( 'edit' ) ) { |
636 | | - $wgOut->readOnlyPage( $this->getContent(), true ); |
637 | | - return; |
638 | | - } |
639 | | - if ( $wgUser->isBlocked() ) { |
640 | | - $wgOut->blockedPage(); |
641 | | - return; |
642 | | - } |
643 | | - if( !$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) { |
644 | | - $wgOut->showErrorPage( 'internalerror', 'sessionfailure' ); |
645 | | - return; |
646 | | - } |
647 | | - |
648 | | - $sourcePath = $this->img->getArchiveVirtualUrl( $oldimage ); |
649 | | - $comment = wfMsg( "reverted" ); |
650 | | - // TODO: preserve file properties from DB instead of reloading from file |
651 | | - $status = $this->img->upload( $sourcePath, $comment, $comment ); |
652 | | - |
653 | | - if ( !$status->isGood() ) { |
654 | | - $this->showError( $status->getWikiText() ); |
655 | | - return; |
656 | | - } |
657 | | - |
658 | | - $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); |
659 | | - $wgOut->setRobotpolicy( 'noindex,nofollow' ); |
660 | | - $wgOut->addHTML( wfMsg( 'imagereverted' ) ); |
661 | | - |
662 | | - $descTitle = $this->img->getTitle(); |
663 | | - $wgOut->returnToMain( false, $descTitle->getPrefixedText() ); |
| 618 | + $reverter = new FileRevertForm( $this->img ); |
| 619 | + $reverter->execute(); |
664 | 620 | } |
665 | 621 | |
666 | 622 | /** |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -101,6 +101,7 @@ |
102 | 102 | 'ImagePage' => 'includes/ImagePage.php', |
103 | 103 | 'ImageHistoryList' => 'includes/ImagePage.php', |
104 | 104 | 'ImageRemote' => 'includes/ImageRemote.php', |
| 105 | + 'FileRevertForm' => 'includes/FileRevertForm.php', |
105 | 106 | 'Job' => 'includes/JobQueue.php', |
106 | 107 | 'EmaillingJob' => 'includes/EmaillingJob.php', |
107 | 108 | 'EnotifNotifyJob' => 'includes/EnotifNotifyJob.php', |
Index: trunk/phase3/languages/messages/MessagesEn.php |
— | — | @@ -1467,6 +1467,16 @@ |
1468 | 1468 | 'imagelist_description' => 'Description', |
1469 | 1469 | 'imagelist_search_for' => 'Search for image name:', |
1470 | 1470 | |
| 1471 | +# File reversion |
| 1472 | +'filerevert' => 'Revert $1', |
| 1473 | +'filerevert-legend' => 'Revert file', |
| 1474 | +'filerevert-intro' => "<span class=\"plainlinks\">You are reverting '''[[Media:$1|$1]]''' to the [$3 version as of $2].</span>", |
| 1475 | +'filerevert-comment' => 'Comment:', |
| 1476 | +'filerevert-defaultcomment' => 'Reverted to version as of $1', |
| 1477 | +'filerevert-submit' => 'Revert', |
| 1478 | +'filerevert-success' => "<span class=\"plainlinks\">'''[[Media:$1|$1]]''' has been reverted to the [$3 version as of $2].</span>", |
| 1479 | +'filerevert-badversion' => 'There is no previous local version of this file with the provided timestamp.', |
| 1480 | + |
1471 | 1481 | # MIME search |
1472 | 1482 | 'mimesearch' => 'MIME search', |
1473 | 1483 | 'mimesearch-summary' => 'This page enables the filtering of files for its MIME-type. Input: contenttype/subtype, e.g. <tt>image/jpeg</tt>.', |
— | — | @@ -1793,7 +1803,6 @@ |
1794 | 1804 | 'deletionlog' => 'deletion log', |
1795 | 1805 | 'reverted' => 'Reverted to earlier revision', |
1796 | 1806 | 'deletecomment' => 'Reason for deletion', |
1797 | | -'imagereverted' => 'Revert to earlier version was successful.', |
1798 | 1807 | 'rollback' => 'Roll back edits', |
1799 | 1808 | 'rollback_short' => 'Rollback', |
1800 | 1809 | 'rollbacklink' => 'rollback', |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -160,6 +160,7 @@ |
161 | 161 | a difference page, to allow refreshing the cache in case of errors |
162 | 162 | * (bug 10701) Link to Special:Listusers in default Special:Statistics messages |
163 | 163 | * Improved file history presentation |
| 164 | +* (bug 10739) Users can now enter comments when reverting files |
164 | 165 | |
165 | 166 | == Bugfixes since 1.10 == |
166 | 167 | |