r91284 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r91283‎ | r91284 | r91285 >
Date:20:07, 1 July 2011
Author:ialex
Status:resolved (Comments)
Tags:
Comment:
* Changed action=revert to use a subclass of Action
* Added WikiPage::getActionOverrides() to be able to execute different actions depending on the namespace (obviously needed for action=revert). This is only used when the value of $wgActions for the corresponding action is true; so extension can still override this.
* Added Action::getDescription() to ease the change of the page header and the <title> element
Modified paths:
  • /trunk/phase3/includes/Action.php (modified) (history)
  • /trunk/phase3/includes/Article.php (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/FileRevertForm.php (deleted) (history)
  • /trunk/phase3/includes/ImagePage.php (modified) (history)
  • /trunk/phase3/includes/Wiki.php (modified) (history)
  • /trunk/phase3/includes/WikiFilePage.php (modified) (history)
  • /trunk/phase3/includes/WikiPage.php (modified) (history)
  • /trunk/phase3/includes/actions/RevertAction.php (added) (history)

Diff [purge]

Index: trunk/phase3/includes/FileRevertForm.php
@@ -1,180 +0,0 @@
2 -<?php
3 -
4 -/**
5 - * File reversion user interface
6 - *
7 - * @ingroup Media
8 - * @author Rob Church <robchur@gmail.com>
9 - */
10 -class FileRevertForm {
11 -
12 - protected $title = null;
13 - protected $file = null;
14 - protected $archiveName = '';
15 - protected $timestamp = false;
16 - protected $oldFile;
17 -
18 - /**
19 - * Constructor
20 - *
21 - * @param $file File we're reverting
22 - */
23 - public function __construct( $file ) {
24 - $this->title = $file->getTitle();
25 - $this->file = $file;
26 - }
27 -
28 - /**
29 - * Fulfil the request; shows the form or reverts the file,
30 - * pending authentication, confirmation, etc.
31 - */
32 - public function execute() {
33 - global $wgOut, $wgRequest, $wgUser, $wgLang;
34 - $this->setHeaders();
35 -
36 - if( wfReadOnly() ) {
37 - $wgOut->readOnlyPage();
38 - return;
39 - } elseif( !$wgUser->isLoggedIn() ) {
40 - $wgOut->showErrorPage( 'uploadnologin', 'uploadnologintext' );
41 - return;
42 - } elseif( !$this->title->userCan( 'edit' ) || !$this->title->userCan( 'upload' ) ) {
43 - // The standard read-only thing doesn't make a whole lot of sense
44 - // here; surely it should show the image or something? -- RC
45 - $article = new Article( $this->title );
46 - $wgOut->readOnlyPage( $article->getContent(), true );
47 - return;
48 - } elseif( $wgUser->isBlocked() ) {
49 - $wgOut->blockedPage();
50 - return;
51 - }
52 -
53 - $this->archiveName = $wgRequest->getText( 'oldimage' );
54 - $token = $wgRequest->getText( 'wpEditToken' );
55 - if( !$this->isValidOldSpec() ) {
56 - $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars( $this->archiveName ) );
57 - return;
58 - }
59 -
60 - if( !$this->haveOldVersion() ) {
61 - $wgOut->addHTML( wfMsgExt( 'filerevert-badversion', 'parse' ) );
62 - $wgOut->returnToMain( false, $this->title );
63 - return;
64 - }
65 -
66 - // Perform the reversion if appropriate
67 - if( $wgRequest->wasPosted() && $wgUser->matchEditToken( $token, $this->archiveName ) ) {
68 - $source = $this->file->getArchiveVirtualUrl( $this->archiveName );
69 - $comment = $wgRequest->getText( 'wpComment' );
70 - // TODO: Preserve file properties from database instead of reloading from file
71 - $status = $this->file->upload( $source, $comment, $comment );
72 - if( $status->isGood() ) {
73 - $wgOut->addHTML( wfMsgExt( 'filerevert-success', 'parse', $this->title->getText(),
74 - $wgLang->date( $this->getTimestamp(), true ),
75 - $wgLang->time( $this->getTimestamp(), true ),
76 - wfExpandUrl( $this->file->getArchiveUrl( $this->archiveName ) ) ) );
77 - $wgOut->returnToMain( false, $this->title );
78 - } else {
79 - $wgOut->addWikiText( $status->getWikiText() );
80 - }
81 - return;
82 - }
83 -
84 - // Show the form
85 - $this->showForm();
86 - }
87 -
88 - /**
89 - * Show the confirmation form
90 - */
91 - protected function showForm() {
92 - global $wgOut, $wgUser, $wgLang, $wgContLang;
93 - $timestamp = $this->getTimestamp();
94 -
95 - $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->getAction() ) );
96 - $form .= Html::hidden( 'wpEditToken', $wgUser->editToken( $this->archiveName ) );
97 - $form .= '<fieldset><legend>' . wfMsgHtml( 'filerevert-legend' ) . '</legend>';
98 - $form .= wfMsgExt( 'filerevert-intro', 'parse', $this->title->getText(),
99 - $wgLang->date( $timestamp, true ), $wgLang->time( $timestamp, true ),
100 - wfExpandUrl( $this->file->getArchiveUrl( $this->archiveName ) ) );
101 - $form .= '<p>' . Xml::inputLabel( wfMsg( 'filerevert-comment' ), 'wpComment', 'wpComment',
102 - 60, wfMsgForContent( 'filerevert-defaultcomment',
103 - $wgContLang->date( $timestamp, false, false ), $wgContLang->time( $timestamp, false, false ) ) ) . '</p>';
104 - $form .= '<p>' . Xml::submitButton( wfMsg( 'filerevert-submit' ) ) . '</p>';
105 - $form .= '</fieldset>';
106 - $form .= '</form>';
107 -
108 - $wgOut->addHTML( $form );
109 - }
110 -
111 - /**
112 - * Set headers, titles and other bits
113 - */
114 - protected function setHeaders() {
115 - global $wgOut, $wgUser;
116 - $wgOut->setPageTitle( wfMsg( 'filerevert', $this->title->getText() ) );
117 - $wgOut->setRobotPolicy( 'noindex,nofollow' );
118 - $wgOut->setSubtitle( wfMsg(
119 - 'filerevert-backlink',
120 - $wgUser->getSkin()->link(
121 - $this->title,
122 - null,
123 - array(),
124 - array(),
125 - array( 'known', 'noclasses' )
126 - )
127 - ) );
128 - }
129 -
130 - /**
131 - * Is the provided `oldimage` value valid?
132 - *
133 - * @return bool
134 - */
135 - protected function isValidOldSpec() {
136 - return strlen( $this->archiveName ) >= 16
137 - && strpos( $this->archiveName, '/' ) === false
138 - && strpos( $this->archiveName, '\\' ) === false;
139 - }
140 -
141 - /**
142 - * Does the provided `oldimage` value correspond
143 - * to an existing, local, old version of this file?
144 - *
145 - * @return bool
146 - */
147 - protected function haveOldVersion() {
148 - return $this->getOldFile()->exists();
149 - }
150 -
151 - /**
152 - * Prepare the form action
153 - *
154 - * @return string
155 - */
156 - protected function getAction() {
157 - $q = array();
158 - $q[] = 'action=revert';
159 - $q[] = 'oldimage=' . urlencode( $this->archiveName );
160 - return $this->title->getLocalUrl( implode( '&', $q ) );
161 - }
162 -
163 - /**
164 - * Extract the timestamp of the old version
165 - *
166 - * @return string
167 - */
168 - protected function getTimestamp() {
169 - if( $this->timestamp === false ) {
170 - $this->timestamp = $this->getOldFile()->getTimestamp();
171 - }
172 - return $this->timestamp;
173 - }
174 -
175 - protected function getOldFile() {
176 - if ( !isset( $this->oldFile ) ) {
177 - $this->oldFile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $this->title, $this->archiveName );
178 - }
179 - return $this->oldFile;
180 - }
181 -}
Index: trunk/phase3/includes/Article.php
@@ -1233,6 +1233,14 @@
12341234 }
12351235
12361236 /**
 1237+ * Overriden by ImagePage class, only present here to avoid a fatal error
 1238+ * Called for ?action=revert
 1239+ */
 1240+ public function revert() {
 1241+ Action::factory( 'revert', $this )->show();
 1242+ }
 1243+
 1244+ /**
12371245 * Output a redirect back to the article.
12381246 * This is typically used after an edit.
12391247 *
@@ -1906,15 +1914,6 @@
19071915 /**#@-*/
19081916
19091917 /**
1910 - * Overriden by ImagePage class, only present here to avoid a fatal error
1911 - * Called for ?action=revert
1912 - */
1913 - public function revert() {
1914 - global $wgOut;
1915 - $wgOut->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
1916 - }
1917 -
1918 - /**
19191918 * Add the primary page-view wikitext to the output buffer
19201919 * Saves the text into the parser cache if possible.
19211920 * Updates templatelinks if it is out of date.
Index: trunk/phase3/includes/WikiFilePage.php
@@ -16,6 +16,10 @@
1717 $this->mRepo = null;
1818 }
1919
 20+ public function getActionOverrides() {
 21+ return array( 'revert' => 'RevertFileAction' );
 22+ }
 23+
2024 /**
2125 * @param $file File:
2226 * @return void
Index: trunk/phase3/includes/ImagePage.php
@@ -787,15 +787,6 @@
788788 }
789789
790790 /**
791 - * Revert the file to an earlier version
792 - */
793 - public function revert() {
794 - $this->loadFile();
795 - $reverter = new FileRevertForm( $this->mPage->getFile() );
796 - $reverter->execute();
797 - }
798 -
799 - /**
800791 * Override handling of action=purge
801792 */
802793 public function doPurge() {
Index: trunk/phase3/includes/actions/RevertAction.php
@@ -0,0 +1,136 @@
 2+<?php
 3+/**
 4+ * File reversion user interface
 5+ *
 6+ * This program is free software; you can redistribute it and/or modify
 7+ * it under the terms of the GNU General Public License as published by
 8+ * the Free Software Foundation; either version 2 of the License, or
 9+ * (at your option) any later version.
 10+ *
 11+ * This program is distributed in the hope that it will be useful,
 12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14+ * GNU General Public License for more details.
 15+ *
 16+ * You should have received a copy of the GNU General Public License
 17+ * along with this program; if not, write to the Free Software
 18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 19+ *
 20+ * @file
 21+ * @ingroup Action
 22+ * @ingroup Media
 23+ * @author Alexandre Emsenhuber
 24+ * @author Rob Church <robchur@gmail.com>
 25+ */
 26+
 27+/**
 28+ * Dummy class for pages not in NS_FILE
 29+ *
 30+ * @ingroup Action
 31+ */
 32+class RevertAction extends Action {
 33+
 34+ public function getName() {
 35+ return 'revert';
 36+ }
 37+
 38+ public function getRestriction() {
 39+ return 'read';
 40+ }
 41+
 42+ public function show() {
 43+ $this->getOutput()->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
 44+ }
 45+
 46+ public function execute() {}
 47+}
 48+
 49+/**
 50+ * Class for pages in NS_FILE
 51+ *
 52+ * @ingroup Action
 53+ */
 54+class RevertFileAction extends FormAction {
 55+ protected $oldFile;
 56+
 57+ public function getName() {
 58+ return 'revert';
 59+ }
 60+
 61+ public function getRestriction() {
 62+ return 'upload';
 63+ }
 64+
 65+ protected function checkCanExecute( User $user ) {
 66+ parent::checkCanExecute( $user );
 67+
 68+ $oldimage = $this->getRequest()->getText( 'oldimage' );
 69+ if ( strlen( $oldimage ) < 16
 70+ || strpos( $oldimage, '/' ) !== false
 71+ || strpos( $oldimage, '\\' ) !== false )
 72+ {
 73+ throw new ErrorPageError( 'internalerror', 'unexpected', array( 'oldimage', $oldimage ) );
 74+ }
 75+
 76+ $this->oldFile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $this->getTitle(), $oldimage );
 77+ if ( !$this->oldFile->exists() ) {
 78+ throw new ErrorPageError( '', 'filerevert-badversion' );
 79+ }
 80+ }
 81+
 82+ protected function alterForm( HTMLForm $form ) {
 83+ $form->setWrapperLegend( wfMsgHtml( 'filerevert-legend' ) );
 84+ $form->setSubmitText( wfMsg( 'filerevert-submit' ) );
 85+ $form->addHiddenField( 'oldimage', $this->getRequest()->getText( 'oldimage' ) );
 86+ }
 87+
 88+ protected function getFormFields() {
 89+ global $wgContLang;
 90+
 91+ $timestamp = $this->oldFile->getTimestamp();
 92+
 93+ return array(
 94+ 'intro' => array(
 95+ 'type' => 'info',
 96+ 'vertical-label' => true,
 97+ 'raw' => true,
 98+ 'default' => wfMsgExt( 'filerevert-intro', 'parse', $this->getTitle()->getText(),
 99+ $this->getLang()->date( $timestamp, true ), $this->getLang()->time( $timestamp, true ),
 100+ wfExpandUrl( $this->page->getFile()->getArchiveUrl( $this->getRequest()->getText( 'oldimage' ) ) ) )
 101+ ),
 102+ 'comment' => array(
 103+ 'type' => 'text',
 104+ 'label-message' => 'filerevert-comment',
 105+ 'default' => wfMsgForContent( 'filerevert-defaultcomment',
 106+ $wgContLang->date( $timestamp, false, false ), $wgContLang->time( $timestamp, false, false ) ),
 107+ )
 108+ );
 109+ }
 110+
 111+ public function onSubmit( $data ) {
 112+ $source = $this->page->getFile()->getArchiveVirtualUrl( $this->getRequest()->getText( 'oldimage' ) );
 113+ $comment = $data['comment'];
 114+ // TODO: Preserve file properties from database instead of reloading from file
 115+ return $this->page->getFile()->upload( $source, $comment, $comment );
 116+ }
 117+
 118+ public function onSuccess() {
 119+ $timestamp = $this->oldFile->getTimestamp();
 120+ $this->getOutput()->addHTML( wfMsgExt( 'filerevert-success', 'parse', $this->getTitle()->getText(),
 121+ $this->getLang()->date( $timestamp, true ),
 122+ $this->getLang()->time( $timestamp, true ),
 123+ wfExpandUrl( $this->page->getFile()->getArchiveUrl( $this->getRequest()->getText( 'oldimage' ) ) ) ) );
 124+ $this->getOutput()->returnToMain( false, $this->getTitle() );
 125+ }
 126+
 127+ protected function getPageTitle() {
 128+ return wfMsg( 'filerevert', $this->getTitle()->getText() );
 129+ }
 130+
 131+ protected function getDescription() {
 132+ return wfMsg(
 133+ 'filerevert-backlink',
 134+ Linker::linkKnown( $this->getTitle() )
 135+ );
 136+ }
 137+}
Property changes on: trunk/phase3/includes/actions/RevertAction.php
___________________________________________________________________
Added: svn:eol-style
1138 + native
Index: trunk/phase3/includes/AutoLoader.php
@@ -83,7 +83,6 @@
8484 'FeedItem' => 'includes/Feed.php',
8585 'FeedUtils' => 'includes/FeedUtils.php',
8686 'FileDeleteForm' => 'includes/FileDeleteForm.php',
87 - 'FileRevertForm' => 'includes/FileRevertForm.php',
8887 'ForkController' => 'includes/ForkController.php',
8988 'FormlessAction' => 'includes/Action.php',
9089 'FormAction' => 'includes/Action.php',
@@ -259,6 +258,8 @@
260259 'InfoAction' => 'includes/actions/InfoAction.php',
261260 'MarkpatrolledAction' => 'includes/actions/MarkpatrolledAction.php',
262261 'PurgeAction' => 'includes/actions/PurgeAction.php',
 262+ 'RevertAction' => 'includes/actions/RevertAction.php',
 263+ 'RevertFileAction' => 'includes/actions/RevertAction.php',
263264 'RevisiondeleteAction' => 'includes/actions/RevisiondeleteAction.php',
264265 'UnwatchAction' => 'includes/actions/WatchAction.php',
265266 'WatchAction' => 'includes/actions/WatchAction.php',
Index: trunk/phase3/includes/Wiki.php
@@ -464,7 +464,6 @@
465465 wfProfileOut( __METHOD__ . '-raw' );
466466 break;
467467 case 'delete':
468 - case 'revert':
469468 case 'rollback':
470469 case 'protect':
471470 case 'unprotect':
Index: trunk/phase3/includes/WikiPage.php
@@ -62,6 +62,18 @@
6363 }
6464
6565 /**
 66+ * Returns overrides for action handlers.
 67+ * Classes listed here will be used instead of the default one when
 68+ * (and only when) $wgActions[$action] === true. This allows subclasses
 69+ * to override the default behavior.
 70+ *
 71+ * @return Array
 72+ */
 73+ public function getActionOverrides() {
 74+ return array();
 75+ }
 76+
 77+ /**
6678 * If this page is a redirect, get its target
6779 *
6880 * The target will be fetched from the redirect table if possible.
Index: trunk/phase3/includes/DefaultSettings.php
@@ -5049,6 +5049,9 @@
50505050 * Array of allowed values for the title=foo&action=<action> parameter. Syntax is:
50515051 * 'foo' => 'ClassName' Load the specified class which subclasses Action
50525052 * 'foo' => true Load the class FooAction which subclasses Action
 5053+ * If something is specified in the getActionOverrides()
 5054+ * of the relevant Page object it will be used
 5055+ * instead of the default class.
50535056 * 'foo' => false The action is disabled; show an error message
50545057 * Unsetting core actions will probably cause things to complain loudly.
50555058 */
@@ -5058,6 +5061,7 @@
50595062 'info' => true,
50605063 'markpatrolled' => true,
50615064 'purge' => true,
 5065+ 'revert' => true,
50625066 'revisiondelete' => true,
50635067 'unwatch' => true,
50645068 'watch' => true,
Index: trunk/phase3/includes/Action.php
@@ -47,9 +47,10 @@
4848 * Get the Action subclass which should be used to handle this action, false if
4949 * the action is disabled, or null if it's not recognised
5050 * @param $action String
 51+ * @param $overrides Array
5152 * @return bool|null|string
5253 */
53 - private final static function getClass( $action ) {
 54+ private final static function getClass( $action, array $overrides ) {
5455 global $wgActions;
5556 $action = strtolower( $action );
5657
@@ -59,6 +60,8 @@
6061
6162 if ( $wgActions[$action] === false ) {
6263 return false;
 64+ } elseif ( $wgActions[$action] === true && isset( $overrides[$action] ) ) {
 65+ return $overrides[$action];
6366 } elseif ( $wgActions[$action] === true ) {
6467 return ucfirst( $action ) . 'Action';
6568 } else {
@@ -74,7 +77,7 @@
7578 * if it is not recognised
7679 */
7780 public final static function factory( $action, Page $page ) {
78 - $class = self::getClass( $action );
 81+ $class = self::getClass( $action, $page->getActionOverrides() );
7982 if ( $class ) {
8083 $obj = new $class( $page );
8184 return $obj;
@@ -223,7 +226,7 @@
224227 protected function setHeaders() {
225228 $out = $this->getOutput();
226229 $out->setRobotPolicy( "noindex,nofollow" );
227 - $out->setPageTitle( $this->getTitle()->getPrefixedText() );
 230+ $out->setPageTitle( $this->getPageTitle() );
228231 $this->getOutput()->setSubtitle( $this->getDescription() );
229232 $out->setArticleRelated( true );
230233 }
@@ -233,6 +236,15 @@
234237 *
235238 * @return String
236239 */
 240+ protected function getPageTitle() {
 241+ return $this->getTitle()->getPrefixedText();
 242+ }
 243+
 244+ /**
 245+ * Returns the description that goes below the \<h1\> tag
 246+ *
 247+ * @return String
 248+ */
237249 protected function getDescription() {
238250 return wfMsg( strtolower( $this->getName() ) );
239251 }

Follow-up revisions

RevisionCommit summaryAuthorDate
r94486* Follow-up to r91284: fix error in Action::exists by passing empty array as ...skizzerz04:02, 15 August 2011

Comments

#Comment by Aaron Schulz (talk | contribs)   21:09, 12 August 2011

It bothers me that action stuff (with is UI level) is in the WikiPage classes, which are supposed to just be DAOs (with a bit of business logic for now).

#Comment by Skizzerz (talk | contribs)   03:49, 15 August 2011

From IRC:

<johnduhart> Can a coder please mark r91284 as fixme? ialex added a parameter to Action::getClass but didn't update the reference on line 95

#Comment by Skizzerz (talk | contribs)   04:03, 15 August 2011

Should be fixed in r94486, grep didn't return any other instances of getClass only being called with one parameter (although I've been known to have some fail greps in the past).

Status & tagging log