r72475 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r72474‎ | r72475 | r72476 >
Date:10:18, 6 September 2010
Author:btongminh
Status:resolved (Comments)
Tags:
Comment:
Follow-up r70137: Made asynchronous upload working a bit more. It now fully works from the API; works still needs to be done for the normal UI. PHPUnit tests are updated and should cover most code paths that can be called from the API.

ApiUpload:
* Added "statuskey" parameter; this is the key that is returned by an async upload
* Refactored warnings transformation into its own function
* filename is no longer required on all uploads

UploadFromUrlJob:
* Moved upload results to its own entry in $_SESSION, instead of using the one from upload
* Fix storing in session by calling wfSetupSession and session_write_close where needed

Tests:
* Set $wgUser in ApiSetup, so that individual tests don't have to do this for themselves
* Added tests to cover most code paths from the API
* Fixed UploadFromUrlTestSuite so that its tests are included in a regular phpunit invocation (something strange with the AutoLoader; not sure what)

Other files:
* Allow passing session id to wfSetupSession
* Explicitly close the session before doing jobs, so that jobs can't manipulate the current session
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/GlobalFunctions.php (modified) (history)
  • /trunk/phase3/includes/Wiki.php (modified) (history)
  • /trunk/phase3/includes/api/ApiUpload.php (modified) (history)
  • /trunk/phase3/includes/job/UploadFromUrlJob.php (modified) (history)
  • /trunk/phase3/includes/upload/UploadFromUrl.php (modified) (history)
  • /trunk/phase3/maintenance/tests/ApiSetup.php (modified) (history)
  • /trunk/phase3/maintenance/tests/UploadFromUrlTest.php (modified) (history)
  • /trunk/phase3/maintenance/tests/UploadFromUrlTestSuite.php (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/tests/UploadFromUrlTestSuite.php
@@ -170,6 +170,10 @@
171171 }
172172
173173 public static function suite() {
174 - return new UploadFromUrlTestSuite( 'UploadFromUrlTest' );
 174+ // Hack to invoke the autoloader required to get phpunit to recognize
 175+ // the UploadFromUrlTest class
 176+ class_exists( 'UploadFromUrlTest' );
 177+ $suite = new UploadFromUrlTestSuite( 'UploadFromUrlTest' );
 178+ return $suite;
175179 }
176180 }
Index: trunk/phase3/maintenance/tests/ApiSetup.php
@@ -22,7 +22,7 @@
2323 static function setupUser() {
2424 if ( self::$user == NULL ) {
2525 self::$userName = "Useruser";
26 - self::$passWord = User::randomPassword();
 26+ self::$passWord = 'Passpass';
2727
2828 self::$user = User::newFromName( self::$userName );
2929 if ( !self::$user->getID() ) {
@@ -33,5 +33,7 @@
3434 self::$user->setPassword( self::$passWord );
3535 self::$user->saveSettings();
3636 }
 37+
 38+ $GLOBALS['wgUser'] = self::$user;
3739 }
3840 }
Index: trunk/phase3/maintenance/tests/UploadFromUrlTest.php
@@ -1,44 +1,50 @@
22 <?php
33
4 -/* Force User.php include for EDIT_TOKEN_SUFFIX */
5 -require_once dirname(__FILE__) . "/../../includes/User.php";
64
7 -class nullClass {
8 - public function handleOutput() { }
9 - public function purgeRedundantText() { }
10 -}
11 -
125 class UploadFromUrlTest extends ApiTestSetup {
136
14 - function setUp() {
 7+ public function setUp() {
158 global $wgEnableUploads, $wgAllowCopyUploads;
 9+ parent::setup();
1610
1711 $wgEnableUploads = true;
1812 $wgAllowCopyUploads = true;
19 - parent::setup();
 13+ wfSetupSession();
2014
2115 ini_set( 'log_errors', 1 );
2216 ini_set( 'error_reporting', 1 );
2317 ini_set( 'display_errors', 1 );
 18+
 19+ if ( wfLocalFile( 'UploadFromUrlTest.png' )->exists() ) {
 20+ $this->deleteFile( 'UploadFromUrlTest.png' );
 21+ }
2422 }
2523
26 - function doApiRequest( $params, $data = null ) {
27 - $session = isset( $data[2] ) ? $data[2] : array();
28 - $_SESSION = $session;
29 -
30 - $req = new FauxRequest( $params, true, $session );
 24+ protected function doApiRequest( $params ) {
 25+ $sessionId = session_id();
 26+ session_write_close();
 27+
 28+ $req = new FauxRequest( $params, true, $_SESSION );
3129 $module = new ApiMain( $req, true );
3230 $module->execute();
3331
34 - return array( $module->getResultData(), $req, $_SESSION );
 32+ wfSetupSession( $sessionId );
 33+ return array( $module->getResultData(), $req );
3534 }
3635
37 - function testClearQueue() {
 36+ /**
 37+ * Ensure that the job queue is empty before continuing
 38+ */
 39+ public function testClearQueue() {
3840 while ( $job = Job::pop() ) { }
3941 $this->assertFalse( $job );
4042 }
4143
42 - function testLogin() {
 44+ /**
 45+ * @todo Document why we test login, since the $wgUser hack used doesn't
 46+ * require login
 47+ */
 48+ public function testLogin() {
4349 $data = $this->doApiRequest( array(
4450 'action' => 'login',
4551 'lgname' => self::$userName,
@@ -64,19 +70,16 @@
6571
6672 /**
6773 * @depends testLogin
 74+ * @depends testClearQueue
6875 */
69 - function testSetupUrlDownload( $data ) {
70 - global $wgUser;
71 - $wgUser = User::newFromName( self::$userName );
72 - $wgUser->load();
73 - $data[2]['wsEditToken'] = $data[2]['wsToken'];
74 - $token = md5( $data[2]['wsToken'] ) . EDIT_TOKEN_SUFFIX;
 76+ public function testSetupUrlDownload( $data ) {
 77+ $token = self::$user->editToken();
7578 $exception = false;
7679
7780 try {
7881 $this->doApiRequest( array(
7982 'action' => 'upload',
80 - ), $data );
 83+ ) );
8184 } catch ( UsageException $e ) {
8285 $exception = true;
8386 $this->assertEquals( "The token parameter must be set", $e->getMessage() );
@@ -91,7 +94,7 @@
9295 ), $data );
9396 } catch ( UsageException $e ) {
9497 $exception = true;
95 - $this->assertEquals( "One of the parameters sessionkey, file, url is required",
 98+ $this->assertEquals( "One of the parameters sessionkey, file, url, statuskey is required",
9699 $e->getMessage() );
97100 }
98101 $this->assertTrue( $exception, "Got exception" );
@@ -109,7 +112,7 @@
110113 }
111114 $this->assertTrue( $exception, "Got exception" );
112115
113 - $wgUser->removeGroup( 'sysop' );
 116+ self::$user->removeGroup( 'sysop' );
114117 $exception = false;
115118 try {
116119 $this->doApiRequest( array(
@@ -124,8 +127,8 @@
125128 }
126129 $this->assertTrue( $exception, "Got exception" );
127130
128 - $wgUser->addGroup( '*' );
129 - $wgUser->addGroup( 'sysop' );
 131+ self::$user->addGroup( '*' );
 132+ self::$user->addGroup( 'sysop' );
130133 $exception = false;
131134 $data = $this->doApiRequest( array(
132135 'action' => 'upload',
@@ -143,45 +146,65 @@
144147
145148 /**
146149 * @depends testLogin
 150+ * @depends testClearQueue
147151 */
148 - function testDoDownload( $data ) {
149 - global $wgUser;
150 - $data[2]['wsEditToken'] = $data[2]['wsToken'];
151 - $token = md5( $data[2]['wsToken'] ) . EDIT_TOKEN_SUFFIX;
 152+ public function testAsyncUpload( $data ) {
 153+ $token = self::$user->editToken();
152154
153 - $wgUser->addGroup( 'users' );
154 - $data = $this->doApiRequest( array(
 155+ self::$user->addGroup( 'users' );
 156+
 157+ $data = $this->doAsyncUpload( $token, true );
 158+ $this->assertEquals( $data[0]['upload']['result'], 'Success' );
 159+ $this->assertEquals( $data[0]['upload']['filename'], 'UploadFromUrlTest.png' );
 160+ $this->assertTrue( wfLocalFile( $data[0]['upload']['filename'] )->exists() );
 161+
 162+ $this->deleteFile( 'UploadFromUrlTest.png' );
 163+
 164+ return $data;
 165+ }
 166+
 167+ /**
 168+ * @depends testLogin
 169+ * @depends testClearQueue
 170+ */
 171+ public function testAsyncUploadWarning( $data ) {
 172+ $token = self::$user->editToken();
 173+
 174+ self::$user->addGroup( 'users' );
 175+
 176+
 177+ $data = $this->doAsyncUpload( $token );
 178+
 179+ $this->assertEquals( $data[0]['upload']['result'], 'Warning' );
 180+ $this->assertTrue( isset( $data[0]['upload']['sessionkey'] ) );
 181+
 182+ $data = $this->doApiRequest( array(
155183 'action' => 'upload',
 184+ 'sessionkey' => $data[0]['upload']['sessionkey'],
156185 'filename' => 'UploadFromUrlTest.png',
157 - 'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
158 - 'asyncdownload' => 1,
 186+ 'ignorewarnings' => 1,
159187 'token' => $token,
160 - ), $data );
 188+ ) );
 189+ $this->assertEquals( $data[0]['upload']['result'], 'Success' );
 190+ $this->assertEquals( $data[0]['upload']['filename'], 'UploadFromUrlTest.png' );
 191+ $this->assertTrue( wfLocalFile( $data[0]['upload']['filename'] )->exists() );
 192+
 193+ $this->deleteFile( 'UploadFromUrlTest.png' );
161194
162 - $job = Job::pop();
163 - $this->assertEquals( 'UploadFromUrlJob', get_class( $job ) );
164 -
165 - $status = $job->run();
166 -
167 - $this->assertTrue( $status );
168 -
169195 return $data;
170196 }
171197
172198 /**
173199 * @depends testLogin
 200+ * @depends testClearQueue
174201 */
175 - function testSyncDownload( $data ) {
176 - global $wgUser;
177 - $data[2]['wsEditToken'] = $data[2]['wsToken'];
178 - $token = md5( $data[2]['wsToken'] ) . EDIT_TOKEN_SUFFIX;
 202+ public function testSyncDownload( $data ) {
 203+ $token = self::$user->editToken();
179204
180205 $job = Job::pop();
181206 $this->assertFalse( $job, 'Starting with an empty jobqueue' );
182207
183 - //$this->deleteFile( 'UploadFromUrlTest.png' );
184 -
185 - $wgUser->addGroup( 'users' );
 208+ self::$user->addGroup( 'users' );
186209 $data = $this->doApiRequest( array(
187210 'action' => 'upload',
188211 'filename' => 'UploadFromUrlTest.png',
@@ -194,25 +217,121 @@
195218 $this->assertFalse( $job );
196219
197220 $this->assertEquals( 'Success', $data[0]['upload']['result'] );
 221+ $this->deleteFile( 'UploadFromUrlTest.png' );
198222
199223 return $data;
200224 }
 225+
 226+ public function testLeaveMessage() {
 227+ $token = self::$user->editToken();
 228+
 229+ $talk = self::$user->getTalkPage();
 230+ if ( $talk->exists() ) {
 231+ $a = new Article( $talk );
 232+ $a->doDeleteArticle( '' );
 233+ }
 234+
 235+ $this->assertFalse( (bool)$talk->getArticleId( GAID_FOR_UPDATE ), 'User talk does not exist' );
 236+
 237+ $data = $this->doApiRequest( array(
 238+ 'action' => 'upload',
 239+ 'filename' => 'UploadFromUrlTest.png',
 240+ 'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
 241+ 'asyncdownload' => 1,
 242+ 'token' => $token,
 243+ 'leavemessage' => 1,
 244+ 'ignorewarnings' => 1,
 245+ ) );
 246+
 247+ $job = Job::pop();
 248+ $job->run();
 249+
 250+ $this->assertTrue( wfLocalFile( 'UploadFromUrlTest.png' )->exists() );
 251+ $this->assertTrue( (bool)$talk->getArticleId( GAID_FOR_UPDATE ), 'User talk exists' );
 252+
 253+ $this->deleteFile( 'UploadFromUrlTest.png' );
 254+
 255+ $talkRev = Revision::newFromTitle( $talk );
 256+ $talkSize = $talkRev->getSize();
 257+
 258+ $exception = false;
 259+ try {
 260+ $data = $this->doApiRequest( array(
 261+ 'action' => 'upload',
 262+ 'filename' => 'UploadFromUrlTest.png',
 263+ 'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
 264+ 'asyncdownload' => 1,
 265+ 'token' => $token,
 266+ 'leavemessage' => 1,
 267+ ) );
 268+ } catch ( UsageException $e ) {
 269+ $exception = true;
 270+ $this->assertEquals( 'Using leavemessage without ignorewarnings is not supported', $e->getMessage() );
 271+ }
 272+ $this->assertTrue( $exception );
 273+
 274+ $job = Job::pop();
 275+ $this->assertFalse( $job );
 276+
 277+ return;
 278+
 279+ // Broken until using leavemessage with ignorewarnings is supported
 280+ $job->run();
 281+
 282+ $this->assertFalse( wfLocalFile( 'UploadFromUrlTest.png' )->exists() );
 283+
 284+ $talkRev = Revision::newFromTitle( $talk );
 285+ $this->assertTrue( $talkRev->getSize() > $talkSize, 'New message left' );
201286
 287+
 288+ }
 289+
202290 /**
203 - * @depends testDoDownload
 291+ * Helper function to perform an async upload, execute the job and fetch
 292+ * the status
 293+ *
 294+ * @return array The result of action=upload&statuskey=key
204295 */
205 - function testVerifyDownload( $data ) {
206 - $t = Title::newFromText( "UploadFromUrlTest.png", NS_FILE );
 296+ private function doAsyncUpload( $token, $ignoreWarnings = false, $leaveMessage = false ) {
 297+ $params = array(
 298+ 'action' => 'upload',
 299+ 'filename' => 'UploadFromUrlTest.png',
 300+ 'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png',
 301+ 'asyncdownload' => 1,
 302+ 'token' => $token,
 303+ );
 304+ if ( $ignoreWarnings ) {
 305+ $params['ignorewarnings'] = 1;
 306+ }
 307+ if ( $leaveMessage ) {
 308+ $params['leavemessage'] = 1;
 309+ }
 310+
 311+ $data = $this->doApiRequest( $params );
 312+ $this->assertEquals( $data[0]['upload']['result'], 'Queued' );
 313+ $this->assertTrue( isset( $data[0]['upload']['statuskey'] ) );
 314+ $statusKey = $data[0]['upload']['statuskey'];
 315+
 316+ $job = Job::pop();
 317+ $this->assertEquals( 'UploadFromUrlJob', get_class( $job ) );
 318+
 319+ $status = $job->run();
 320+ $this->assertTrue( $status );
 321+
 322+ $data = $this->doApiRequest( array(
 323+ 'action' => 'upload',
 324+ 'statuskey' => $statusKey,
 325+ 'token' => $token,
 326+ ) );
 327+
 328+ return $data;
 329+ }
 330+
207331
208 - $this->assertTrue( $t->exists() );
209 -
210 - $this->deleteFile( 'UploadFromUrlTest.png' );
211 - }
212 -
213332 /**
214333 *
215334 */
216 - function deleteFile( $name ) {
 335+ protected function deleteFile( $name ) {
217336 $t = Title::newFromText( $name, NS_FILE );
218337 $this->assertTrue($t->exists(), "File '$name' exists");
219338
Index: trunk/phase3/includes/upload/UploadFromUrl.php
@@ -197,8 +197,10 @@
198198 'userName' => $user->getName(),
199199 'leaveMessage' => $this->mAsync == 'async-leavemessage',
200200 'ignoreWarnings' => $this->mIgnoreWarnings,
 201+ 'sessionId' => session_id(),
201202 'sessionKey' => $sessionKey,
202203 ) );
 204+ $job->initializeSessionData();
203205 $job->insert();
204206 return $sessionKey;
205207 }
Index: trunk/phase3/includes/GlobalFunctions.php
@@ -2918,7 +2918,7 @@
29192919 /**
29202920 * Initialise php session
29212921 */
2922 -function wfSetupSession() {
 2922+function wfSetupSession( $sessionId = false ) {
29232923 global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain,
29242924 $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler;
29252925 if( $wgSessionsInMemcached ) {
@@ -2944,6 +2944,9 @@
29452945 session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
29462946 }
29472947 session_cache_limiter( 'private, must-revalidate' );
 2948+ if ( $sessionId ) {
 2949+ session_id( $sessionId );
 2950+ }
29482951 wfSuppressWarnings();
29492952 session_start();
29502953 wfRestoreWarnings();
Index: trunk/phase3/includes/api/ApiUpload.php
@@ -55,7 +55,10 @@
5656 $this->mParams['file'] = $request->getFileName( 'file' );
5757
5858 // Select an upload module
59 - $this->selectUploadModule();
 59+ if ( !$this->selectUploadModule() ) {
 60+ // This is not a true upload, but a status request or similar
 61+ return;
 62+ }
6063 if ( !isset( $this->mUpload ) ) {
6164 $this->dieUsage( 'No upload module set', 'nomodule' );
6265 }
@@ -96,15 +99,39 @@
97100 }
98101
99102 /**
100 - * Select an upload module and set it to mUpload. Dies on failure.
 103+ * Select an upload module and set it to mUpload. Dies on failure. If the
 104+ * request was a status request and not a true upload, returns false;
 105+ * otherwise true
 106+ *
 107+ * @return bool
101108 */
102109 protected function selectUploadModule() {
103110 $request = $this->getMain()->getRequest();
104111
105112 // One and only one of the following parameters is needed
106113 $this->requireOnlyOneParameter( $this->mParams,
107 - 'sessionkey', 'file', 'url' );
 114+ 'sessionkey', 'file', 'url', 'statuskey' );
108115
 116+ if ( $this->mParams['statuskey'] ) {
 117+ // Status request for an async upload
 118+ $sessionData = UploadFromUrlJob::getSessionData( $this->mParams['statuskey'] );
 119+ if ( !isset( $sessionData['result'] ) ) {
 120+ $this->dieUsage();
 121+ }
 122+ if ( $sessionData['result'] == 'Warning' ) {
 123+ $sessionData['warnings'] = $this->transformWarnings( $sessionData['warnings'] );
 124+ $sessionData['sessionkey'] = $this->mParams['statuskey'];
 125+ }
 126+ $this->getResult()->addValue( null, $this->getModuleName(), $sessionData );
 127+ return false;
 128+
 129+ }
 130+
 131+ // The following modules all require the filename parameter to be set
 132+ if ( is_null( $this->mParams['filename'] ) ) {
 133+ $this->dieUsageMsg( array( 'missingparam', 'filename' ) );
 134+ }
 135+
109136 if ( $this->mParams['sessionkey'] ) {
110137 // Upload stashed in a previous request
111138 $sessionData = $request->getSessionData( UploadBase::getSessionKeyName() );
@@ -132,6 +159,11 @@
133160
134161 $async = false;
135162 if ( $this->mParams['asyncdownload'] ) {
 163+ if ( $this->mParams['leavemessage'] && !$this->mParams['ignorewarnings'] ) {
 164+ $this->dieUsage( 'Using leavemessage without ignorewarnings is not supported',
 165+ 'missing-ignorewarnings' );
 166+ }
 167+
136168 if ( $this->mParams['leavemessage'] ) {
137169 $async = 'async-leavemessage';
138170 } else {
@@ -143,6 +175,8 @@
144176 $this->mParams['url'], $async );
145177
146178 }
 179+
 180+ return true;
147181 }
148182
149183 /**
@@ -225,25 +259,8 @@
226260 if ( !$this->mParams['ignorewarnings'] ) {
227261 $warnings = $this->mUpload->checkWarnings();
228262 if ( $warnings ) {
229 - // Add indices
230 - $this->getResult()->setIndexedTagName( $warnings, 'warning' );
231 -
232 - if ( isset( $warnings['duplicate'] ) ) {
233 - $dupes = array();
234 - foreach ( $warnings['duplicate'] as $key => $dupe )
235 - $dupes[] = $dupe->getName();
236 - $this->getResult()->setIndexedTagName( $dupes, 'duplicate' );
237 - $warnings['duplicate'] = $dupes;
238 - }
239 -
240 - if ( isset( $warnings['exists'] ) ) {
241 - $warning = $warnings['exists'];
242 - unset( $warnings['exists'] );
243 - $warnings[$warning['warning']] = $warning['file']->getName();
244 - }
245 -
246263 $result['result'] = 'Warning';
247 - $result['warnings'] = $warnings;
 264+ $result['warnings'] = $this->transformWarnings( $warnings );
248265
249266 $sessionKey = $this->mUpload->stashSession();
250267 if ( !$sessionKey ) {
@@ -257,7 +274,33 @@
258275 }
259276 return;
260277 }
 278+
 279+ /**
 280+ * Transforms a warnings array returned by mUpload->checkWarnings() into
 281+ * something that can be directly used as API result
 282+ */
 283+ protected function transformWarnings( $warnings ) {
 284+ // Add indices
 285+ $this->getResult()->setIndexedTagName( $warnings, 'warning' );
261286
 287+ if ( isset( $warnings['duplicate'] ) ) {
 288+ $dupes = array();
 289+ foreach ( $warnings['duplicate'] as $key => $dupe ) {
 290+ $dupes[] = $dupe->getName();
 291+ }
 292+ $this->getResult()->setIndexedTagName( $dupes, 'duplicate' );
 293+ $warnings['duplicate'] = $dupes;
 294+ }
 295+
 296+ if ( isset( $warnings['exists'] ) ) {
 297+ $warning = $warnings['exists'];
 298+ unset( $warnings['exists'] );
 299+ $warnings[$warning['warning']] = $warning['file']->getName();
 300+ }
 301+
 302+ return $warnings;
 303+ }
 304+
262305 /**
263306 * Perform the actual upload. Returns a suitable result array on success;
264307 * dies on failure.
@@ -290,7 +333,7 @@
291334 // requested so
292335 return array(
293336 'result' => 'Queued',
294 - 'sessionkey' => $error[0][1],
 337+ 'statuskey' => $error[0][1],
295338 );
296339 } else {
297340 $this->getResult()->setIndexedTagName( $error, 'error' );
@@ -320,7 +363,6 @@
321364 $params = array(
322365 'filename' => array(
323366 ApiBase::PARAM_TYPE => 'string',
324 - ApiBase::PARAM_REQUIRED => true
325367 ),
326368 'comment' => array(
327369 ApiBase::PARAM_DFLT => ''
@@ -351,6 +393,7 @@
352394 $params += array(
353395 'asyncdownload' => false,
354396 'leavemessage' => false,
 397+ 'statuskey' => null,
355398 );
356399 }
357400 return $params;
@@ -375,6 +418,7 @@
376419 $params += array(
377420 'asyncdownload' => 'Make fetching a URL asynchronous',
378421 'leavemessage' => 'If asyncdownload is used, leave a message on the user talk page if finished',
 422+ 'statuskey' => 'Fetch the upload status for this session key',
379423 );
380424 }
381425
Index: trunk/phase3/includes/Wiki.php
@@ -379,6 +379,8 @@
380380 $output->output();
381381 // Do any deferred jobs
382382 $this->doUpdates( $deferredUpdates );
 383+ // Close the session so that jobs don't access the current session
 384+ session_write_close();
383385 $this->doJobs();
384386 wfProfileOut( __METHOD__ );
385387 }
Index: trunk/phase3/includes/job/UploadFromUrlJob.php
@@ -16,6 +16,8 @@
1717 * @ingroup JobQueue
1818 */
1919 class UploadFromUrlJob extends Job {
 20+ const SESSION_KEYNAME = 'wsUploadFromUrlJobData';
 21+
2022 public $upload;
2123 protected $user;
2224
@@ -24,14 +26,6 @@
2527 }
2628
2729 public function run() {
28 - # Until we find a way to store data in sessions, set leaveMessage to
29 - # true unconditionally
30 - $this->params['leaveMessage'] = true;
31 - # Similar for ignorewarnings. This is not really a good fallback, but
32 - # there is no easy way to get a wikitext formatted warning message to
33 - # show to the user
34 - $this->params['ignoreWarnings'] = true;
35 -
3630 # Initialize this object and the upload object
3731 $this->upload = new UploadFromUrl();
3832 $this->upload->initialize(
@@ -60,6 +54,8 @@
6155 if ( !$this->params['ignoreWarnings'] ) {
6256 $warnings = $this->upload->checkWarnings();
6357 if ( $warnings ) {
 58+ wfSetupSession( $this->params['sessionId'] );
 59+
6460 if ( $this->params['leaveMessage'] ) {
6561 $this->user->leaveUserMessage(
6662 wfMsg( 'upload-warning-subj' ),
@@ -72,7 +68,10 @@
7369 'warnings', $warnings );
7470 }
7571
76 - // FIXME: stash in session
 72+ # Stash the upload in the session
 73+ $this->upload->stashSession( $this->params['sessionKey'] );
 74+ session_write_close();
 75+
7776 return true;
7877 }
7978 }
@@ -111,28 +110,44 @@
112111 ) );
113112 }
114113 } else {
 114+ wfSetupSession( $this->params['sessionId'] );
115115 if ( $status->isOk() ) {
116116 $this->storeResultInSession( 'Success',
117 - 'filename', $this->getLocalFile()->getName() );
 117+ 'filename', $this->upload->getLocalFile()->getName() );
118118 } else {
119119 $this->storeResultInSession( 'Failure',
120120 'errors', $status->getErrorsArray() );
121121 }
122 -
 122+ session_write_close();
123123 }
124124 }
125125
126126 /**
127 - * Store a result in the session data
128 - * THIS IS BROKEN. $_SESSION does not exist when using runJobs.php
 127+ * Store a result in the session data. Note that the caller is responsible
 128+ * for appropriate session_start and session_write_close calls.
129129 *
130130 * @param $result String: the result (Success|Warning|Failure)
131131 * @param $dataKey String: the key of the extra data
132132 * @param $dataValue Mixed: the extra data itself
133133 */
134134 protected function storeResultInSession( $result, $dataKey, $dataValue ) {
135 - $session &= $_SESSION[UploadBase::getSessionKeyname()][$this->params['sessionKey']];
 135+ $session =& self::getSessionData( $this->params['sessionKey'] );
136136 $session['result'] = $result;
137137 $session[$dataKey] = $dataValue;
138138 }
 139+
 140+ /**
 141+ * Initialize the session data. Sets the intial result to queued.
 142+ */
 143+ public function initializeSessionData() {
 144+ $session =& self::getSessionData( $this->params['sessionKey'] );
 145+ $$session['result'] = 'Queued';
 146+ }
 147+
 148+ public static function &getSessionData( $key ) {
 149+ if ( !isset( $_SESSION[self::SESSION_KEYNAME][$key] ) ) {
 150+ $_SESSION[self::SESSION_KEYNAME][$key] = array();
 151+ }
 152+ return $_SESSION[self::SESSION_KEYNAME][$key];
 153+ }
139154 }
Index: trunk/phase3/RELEASE-NOTES
@@ -380,6 +380,8 @@
381381 missing
382382 * (bug 24724) list=allusers is out by 1 (shows total users - 1)
383383 * (bug 24166) API error when using rvprop=tags
 384+* Introduced "asynchronous download" mode for upload-by-url. Requires
 385+ $wgAllowAsyncCopyUploads to be true.
384386
385387 === Languages updated in 1.17 ===
386388

Follow-up revisions

RevisionCommit summaryAuthorDate
r72578Followup r72475: assert that a job has been popped to avoid fatalsbtongminh11:25, 8 September 2010
r72710Follow-up r72475: Set $wgAllowAsyncCopyUploads in the testbtongminh11:17, 10 September 2010
r75588Add feature to block common (weak) passwords....platonides22:26, 27 October 2010
r75589Do NOT use hardcoded passwords! Not even if the user agreed to run destructiv...platonides22:27, 27 October 2010
r87235Remove the session_write_close() from r72475 since it apparently causes bug 2...tstarling04:21, 2 May 2011
r88904(bug 27891) Follow-up r72475: destroy the LBFactory singleton before doing an...btongminh17:11, 26 May 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r70137Made asynchronous upload by URL working, partly. Hid it behind $wgAllowAsyncC...btongminh13:53, 29 July 2010

Comments

#Comment by 😂 (talk | contribs)   15:42, 7 September 2010
PHP Fatal error:  Call to a member function run() on a non-object in /opt/local/apache2/htdocs/phase3/maintenance/tests/UploadFromUrlTest.php on line 247
PHP Stack trace:
PHP   1. {main}() /opt/local/apache2/htdocs/phase3/maintenance/tests/phpunit:0
PHP   2. PHPUnit_TextUI_Command->run() /opt/local/apache2/htdocs/phase3/maintenance/tests/phpunit:53
PHP   3. PHPUnit_TextUI_TestRunner->doRun() /opt/local/PEAR/PHPUnit/TextUI/Command.php:213
PHP   4. PHPUnit_Framework_TestSuite->run() /opt/local/PEAR/PHPUnit/TextUI/TestRunner.php:349
PHP   5. PHPUnit_Framework_TestSuite->run() /opt/local/PEAR/PHPUnit/Framework/TestSuite.php:674
PHP   6. PHPUnit_Framework_TestSuite->runTest() /opt/local/PEAR/PHPUnit/Framework/TestSuite.php:731
PHP   7. PHPUnit_Framework_TestCase->run() /opt/local/PEAR/PHPUnit/Framework/TestSuite.php:756
PHP   8. PHPUnit_Framework_TestResult->run() /opt/local/PEAR/PHPUnit/Framework/TestCase.php:652
PHP   9. PHPUnit_Framework_TestCase->runBare() /opt/local/PEAR/PHPUnit/Framework/TestResult.php:686
PHP  10. PHPUnit_Framework_TestCase->runTest() /opt/local/PEAR/PHPUnit/Framework/TestCase.php:705
PHP  11. ReflectionMethod->invokeArgs() /opt/local/PEAR/PHPUnit/Framework/TestCase.php:822
PHP  12. UploadFromUrlTest->testLeaveMessage() /opt/local/apache2/htdocs/phase3/maintenance/tests/UploadFromUrlTest.php:0
#Comment by 😂 (talk | contribs)   18:07, 7 September 2010

Also ending up with some new rows in recentchanges.

#Comment by Bryan (talk | contribs)   11:30, 8 September 2010

I added an assertion in r72578. This should fix the fatal, but will probably cause the test to fail for you. (It doesn't for me) Could you check?

#Comment by 😂 (talk | contribs)   15:10, 8 September 2010

Fatal is gone, but I'm getting some exceptions now. Full output from $ phpunit --configuration suite.xml --filter "UploadFromUrl*" at http://dpaste.org/AwFp/

#Comment by 😂 (talk | contribs)   15:11, 8 September 2010

Code Review url parsing is retarded. Put a / on the end of the URL

#Comment by Bryan (talk | contribs)   11:18, 10 September 2010

Fixed in r72578.

#Comment by Bryan (talk | contribs)   11:18, 10 September 2010

Actually r72710.

#Comment by 😂 (talk | contribs)   11:31, 10 September 2010

Confirmed that works now. Thanks :)

#Comment by NeilK (talk | contribs)   21:20, 24 September 2010

If I don't have the global $wgAllowAsyncCopyUploads set to true, this error message can occur:

  Notice: Undefined index: statuskey in /Users/neilk/Sites/wiki/includes/api/ApiUpload.php on line 191

I'm not sure about this idea of adding parameters conditionally... one of the main assumptions throughout the API code is that all potential parameters are initialized, even if it's just to null. This makes coding a lot simpler.

I quickly grepped through all the api/Api*.php modules and I don't see any other conditionally added parameters.[1]

I'm in the same boat as you with UploadWizard, I have to add parameters too, but I was thinking of doing so via a hook from an extension (but the parameters would then always be present and defined even if the extension was not turned on).


[1] neilk@ivy:~/Sites/trunk/includes/api$ perl -wlne 'print if (/^(\s*).*function\s+getAllowedParams/ .. /$1}/)' *.php | less

#Comment by NeilK (talk | contribs)   21:27, 24 September 2010

oh, this was actually added in r70137. Well, anyway same comment.

#Comment by Tim Starling (talk | contribs)   04:13, 2 May 2011

Moving the session_write_close() up completely broke ChronologyProtector and so caused bug 27891.

#Comment by Bryan (talk | contribs)   17:12, 26 May 2011

Fixed in r88904.

Status & tagging log