Index: trunk/phase3/languages/messages/MessagesEn.php |
— | — | @@ -2055,6 +2055,17 @@ |
2056 | 2056 | 'filetype-banned-type' => "'''\".\$1\"''' is not a permitted file type. |
2057 | 2057 | Permitted {{PLURAL:\$3|file type is|file types are}} \$2.", |
2058 | 2058 | 'filetype-missing' => 'The file has no extension (like ".jpg").', |
| 2059 | +'empty-file' => 'The file you submitted was empty', |
| 2060 | +'file-too-large' => 'The file you submitted was too large', |
| 2061 | +'filename-tooshort' => 'The filename is too short', |
| 2062 | +'filetype-banned' => 'This type of file is banned', |
| 2063 | +'verification-error' => 'This file did not pass file verification', |
| 2064 | +'hookaborted' => 'The modification you tried to make was aborted by an extension hook', |
| 2065 | +'illegal-filename' => 'The filename is not allowed', |
| 2066 | +'overwrite' => 'Overwriting an existing file is not allowed', |
| 2067 | +'unknown-error' => 'An unknown error occured', |
| 2068 | +'tmp-create-error' => 'Couldn\'t create temporary file', |
| 2069 | +'tmp-write-error' => 'Error writing temporary file', |
2059 | 2070 | 'large-file' => 'It is recommended that files are no larger than $1; |
2060 | 2071 | this file is $2.', |
2061 | 2072 | 'largefileserver' => 'This file is bigger than the server is configured to allow.', |
— | — | @@ -2094,6 +2105,7 @@ |
2095 | 2106 | 'uploadedimage' => 'uploaded "[[$1]]"', |
2096 | 2107 | 'overwroteimage' => 'uploaded a new version of "[[$1]]"', |
2097 | 2108 | 'uploaddisabled' => 'Uploads disabled', |
| 2109 | +'copyuploaddisabled' => 'Upload by URL disabled', |
2098 | 2110 | 'uploaddisabledtext' => 'File uploads are disabled.', |
2099 | 2111 | 'php-uploaddisabledtext' => 'File uploads are disabled in PHP. |
2100 | 2112 | Please check the file_uploads setting.', |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -1935,6 +1935,7 @@ |
1936 | 1936 | 'sendMail' => 'EmaillingJob', |
1937 | 1937 | 'enotifNotify' => 'EnotifNotifyJob', |
1938 | 1938 | 'fixDoubleRedirect' => 'DoubleRedirectJob', |
| 1939 | + 'uploadFromUrl' => 'UploadFromUrlJob', |
1939 | 1940 | ); |
1940 | 1941 | |
1941 | 1942 | /** |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -237,6 +237,7 @@ |
238 | 238 | 'UploadFromStash' => 'includes/upload/UploadFromStash.php', |
239 | 239 | 'UploadFromFile' => 'includes/upload/UploadFromFile.php', |
240 | 240 | 'UploadFromUrl' => 'includes/upload/UploadFromUrl.php', |
| 241 | + 'UploadFromUrlJob' => 'includes/UploadFromUrlJob.php', |
241 | 242 | 'User' => 'includes/User.php', |
242 | 243 | 'UserArray' => 'includes/UserArray.php', |
243 | 244 | 'UserArrayFromResult' => 'includes/UserArray.php', |
Index: trunk/phase3/includes/upload/UploadFromUrl.php |
— | — | @@ -10,6 +10,7 @@ |
11 | 11 | */ |
12 | 12 | class UploadFromUrl extends UploadBase { |
13 | 13 | protected $mTempDownloadPath; |
| 14 | + protected $comment, $watchList; |
14 | 15 | |
15 | 16 | /** |
16 | 17 | * Checks if the user is allowed to use the upload-by-URL feature. If the |
— | — | @@ -32,16 +33,56 @@ |
33 | 34 | /** |
34 | 35 | * Entry point for API upload |
35 | 36 | */ |
36 | | - public function initialize( $name, $url, $na, $nb = false ) { |
37 | | - global $wgTmpDirectory; |
| 37 | + public function initialize( $name, $url, $comment, $watchlist ) { |
| 38 | + global $wgUser; |
38 | 39 | |
39 | | - $localFile = tempnam( $wgTmpDirectory, 'WEBUPLOAD' ); |
40 | | - $this->initializePathInfo( $name, $localFile, 0, true ); |
| 40 | + if( !Http::isValidURI( $url ) ) { |
| 41 | + return Status::newFatal( 'http-invalid-url' ); |
| 42 | + } |
| 43 | + $params = array( |
| 44 | + "userName" => $wgUser->getName(), |
| 45 | + "userID" => $wgUser->getID(), |
| 46 | + "url" => trim( $url ), |
| 47 | + "timestamp" => wfTimestampNow(), |
| 48 | + "comment" => $comment, |
| 49 | + "watchlist" => $watchlist); |
41 | 50 | |
42 | | - $this->mUrl = trim( $url ); |
| 51 | + $title = Title::newFromText( $name ); |
| 52 | + /* // Check whether the user has the appropriate permissions to upload anyway */ |
| 53 | + /* $permission = $this->isAllowed( $wgUser ); */ |
| 54 | + |
| 55 | + /* if ( $permission !== true ) { */ |
| 56 | + /* if ( !$wgUser->isLoggedIn() ) { */ |
| 57 | + /* return Status::newFatal( 'uploadnologintext' ); */ |
| 58 | + /* } else { */ |
| 59 | + /* return Status::newFatal( 'badaccess-groups' ); */ |
| 60 | + /* } */ |
| 61 | + /* } */ |
| 62 | + |
| 63 | + /* $permErrors = $this->verifyPermissions( $wgUser ); */ |
| 64 | + /* if ( $permErrors !== true ) { */ |
| 65 | + /* return Status::newFatal( 'badaccess-groups' ); */ |
| 66 | + /* } */ |
| 67 | + |
| 68 | + |
| 69 | + $job = new UploadFromUrlJob( $title, $params ); |
| 70 | + $job->insert(); |
43 | 71 | } |
44 | 72 | |
45 | 73 | /** |
| 74 | + * Initialize a queued download |
| 75 | + * @param $job Job |
| 76 | + */ |
| 77 | + public function initializeFromJob( $job ) { |
| 78 | + $this->mUrl = $job->params['url']; |
| 79 | + $this->mTempPath = tempnam( $wgTmpDirectory, 'COPYUPLOAD' ); |
| 80 | + $this->mDesiredDestName = $job->title; |
| 81 | + $this->comment = $job->params['comment']; |
| 82 | + $this->watchList = $job->params['watchlist']; |
| 83 | + $this->getTitle(); |
| 84 | + } |
| 85 | + |
| 86 | + /** |
46 | 87 | * Entry point for SpecialUpload |
47 | 88 | * @param $request Object: WebRequest object |
48 | 89 | */ |
— | — | @@ -66,60 +107,63 @@ |
67 | 108 | return self::isValidUrl( $request->getVal( 'wpUploadFileURL' ) ); |
68 | 109 | } |
69 | 110 | |
70 | | - public static function isValidUrl( $url ) { |
71 | | - // Only allow HTTP or FTP for now |
72 | | - return (bool)preg_match( '!^(http://|ftp://)!', $url ); |
| 111 | + private function saveTempFile( $req ) { |
| 112 | + $filename = tempnam( wfTempDir(), 'URL' ); |
| 113 | + if ( $filename === false ) { |
| 114 | + return Status::newFatal( 'tmp-create-error' ); |
| 115 | + } |
| 116 | + if ( file_put_contents( $filename, $req->getContent() ) === false ) { |
| 117 | + return Status::newFatal( 'tmp-write-error' ); |
| 118 | + } |
| 119 | + |
| 120 | + $this->mTempPath = $filename; |
| 121 | + $this->mFileSize = filesize( $filename ); |
| 122 | + |
| 123 | + return Status::newGood(); |
73 | 124 | } |
74 | 125 | |
75 | | - /** |
76 | | - * Do the real fetching stuff |
77 | | - */ |
78 | | - function fetchFile() { |
79 | | - if( !self::isValidUrl( $this->mUrl ) ) { |
80 | | - return Status::newFatal( 'upload-proto-error' ); |
| 126 | + public function doUpload() { |
| 127 | + global $wgUser; |
| 128 | + |
| 129 | + $req = HttpRequest::factory($this->mUrl); |
| 130 | + $status = $req->execute(); |
| 131 | + |
| 132 | + if( !$status->isOk() ) { |
| 133 | + return $status; |
81 | 134 | } |
82 | 135 | |
83 | | - # Open temporary file |
84 | | - $this->mCurlDestHandle = @fopen( $this->mTempPath, "wb" ); |
85 | | - if( $this->mCurlDestHandle === false ) { |
86 | | - # Could not open temporary file to write in |
87 | | - return Status::newFatal( 'upload-file-error' ); |
| 136 | + $status = $this->saveTempFile( $req ); |
| 137 | + $this->mRemoveTempFile = true; |
| 138 | + |
| 139 | + if( !$status->isOk() ) { |
| 140 | + return $status; |
88 | 141 | } |
89 | | - |
90 | | - $options = array( |
91 | | - 'method' => 'GET', |
92 | | - 'timeout' => 10, |
93 | | - ); |
94 | | - $req = HttpRequest::factory( $this->mUrl, $options ); |
95 | | - $req->setCallback( array( $this, 'uploadCurlCallback' ) ); |
96 | | - $status = $req->execute(); |
97 | | - fclose( $this->mCurlDestHandle ); |
98 | | - unset( $this->mCurlDestHandle ); |
99 | 142 | |
100 | | - global $wgMaxUploadSize; |
101 | | - if ( $this->mFileSize > $wgMaxUploadSize ) { |
102 | | - # Just return an ok, so that the regular verifications can handle |
103 | | - # the file-too-large error |
104 | | - return Status::newGood(); |
| 143 | + $v = $this->verifyUpload(); |
| 144 | + if( $v['status'] !== UploadBase::OK ) { |
| 145 | + return $this->convertVerifyErrorToStatus( $v['status'], $v['details'] ); |
105 | 146 | } |
106 | 147 | |
107 | | - return $status; |
108 | | - } |
| 148 | + // This has to come from API |
| 149 | + /* $warnings = $this->checkForWarnings(); */ |
| 150 | + /* if( isset($warnings) ) return $warnings; */ |
109 | 151 | |
110 | | - /** |
111 | | - * Callback function for CURL-based web transfer |
112 | | - * Write data to file unless we've passed the length limit; |
113 | | - * if so, abort immediately. |
114 | | - * @access private |
115 | | - */ |
116 | | - function uploadCurlCallback( $ch, $data ) { |
117 | | - global $wgMaxUploadSize; |
118 | | - $length = strlen( $data ); |
119 | | - $this->mFileSize += $length; |
120 | | - if( $this->mFileSize > $wgMaxUploadSize ) { |
121 | | - return 0; |
| 152 | + // Use comment as initial page text by default |
| 153 | + if ( is_null( $this->mParams['text'] ) ) { |
| 154 | + $this->mParams['text'] = $this->mParams['comment']; |
122 | 155 | } |
123 | | - fwrite( $this->mCurlDestHandle, $data ); |
124 | | - return $length; |
| 156 | + |
| 157 | + $file = $this->getLocalFile(); |
| 158 | + // This comes from ApiBase |
| 159 | + /* $watch = $this->getWatchlistValue( $this->mParams['watchlist'], $file->getTitle() ); */ |
| 160 | + |
| 161 | + if ( !$status->isGood() ) { |
| 162 | + return $status; |
| 163 | + } |
| 164 | + |
| 165 | + $status = $this->getLocalFile()->upload( $this->mTempPath, $this->comment, |
| 166 | + $this->pageText, File::DELETE_SOURCE, $this->mFileProps, false, $wgUser ); |
| 167 | + |
| 168 | + return $status; |
125 | 169 | } |
126 | 170 | } |
Index: trunk/phase3/includes/upload/UploadBase.php |
— | — | @@ -29,6 +29,7 @@ |
30 | 30 | const FILETYPE_MISSING = 8; |
31 | 31 | const FILETYPE_BADTYPE = 9; |
32 | 32 | const VERIFICATION_ERROR = 10; |
| 33 | + |
33 | 34 | # HOOK_ABORTED is the new name of UPLOAD_VERIFICATION_ERROR |
34 | 35 | const UPLOAD_VERIFICATION_ERROR = 11; |
35 | 36 | const HOOK_ABORTED = 11; |
— | — | @@ -41,6 +42,24 @@ |
42 | 43 | return self::SESSION_KEYNAME; |
43 | 44 | } |
44 | 45 | |
| 46 | + public function getVerificationErrorCode( $error ) { |
| 47 | + $code_to_status = array(self::EMPTY_FILE => 'empty-file', |
| 48 | + self::FILE_TOO_LARGE => 'file-too-large', |
| 49 | + self::FILETYPE_MISSING => 'filetype-missing', |
| 50 | + self::FILETYPE_BADTYPE => 'filetype-banned', |
| 51 | + self::MIN_LENGTH_PARTNAME => 'filename-tooshort', |
| 52 | + self::ILLEGAL_FILENAME => 'illegal-filename', |
| 53 | + self::OVERWRITE_EXISTING_FILE => 'overwrite', |
| 54 | + self::VERIFICATION_ERROR => 'verification-error', |
| 55 | + self::HOOK_ABORTED => 'hookaborted', |
| 56 | + ); |
| 57 | + if( isset( $code_to_status[$error] ) ) { |
| 58 | + return $code_to_status[$error]; |
| 59 | + } |
| 60 | + |
| 61 | + return 'unknown-error'; |
| 62 | + } |
| 63 | + |
45 | 64 | /** |
46 | 65 | * Returns true if uploads are enabled. |
47 | 66 | * Can be override by subclasses. |
— | — | @@ -201,7 +220,7 @@ |
202 | 221 | if( $this->isEmptyFile() ) { |
203 | 222 | return array( 'status' => self::EMPTY_FILE ); |
204 | 223 | } |
205 | | - |
| 224 | + |
206 | 225 | /** |
207 | 226 | * Honor $wgMaxUploadSize |
208 | 227 | */ |
— | — | @@ -217,9 +236,6 @@ |
218 | 237 | */ |
219 | 238 | $verification = $this->verifyFile(); |
220 | 239 | if( $verification !== true ) { |
221 | | - if( !is_array( $verification ) ) { |
222 | | - $verification = array( $verification ); |
223 | | - } |
224 | 240 | return array( |
225 | 241 | 'status' => self::VERIFICATION_ERROR, |
226 | 242 | 'details' => $verification |
— | — | @@ -278,19 +294,12 @@ |
279 | 295 | } |
280 | 296 | |
281 | 297 | /** |
282 | | - * Verifies that it's ok to include the uploaded file |
283 | | - * |
284 | | - * @return mixed true of the file is verified, a string or array otherwise. |
| 298 | + * Verify the mime type |
| 299 | + * @param $magic MagicMime object |
| 300 | + * @param $mime string representing the mime |
| 301 | + * @return mixed true if the file is verified, an array otherwise |
285 | 302 | */ |
286 | | - protected function verifyFile() { |
287 | | - $this->mFileProps = File::getPropsFromPath( $this->mTempPath, $this->mFinalExtension ); |
288 | | - $this->checkMacBinary(); |
289 | | - |
290 | | - # magically determine mime type |
291 | | - $magic = MimeMagic::singleton(); |
292 | | - $mime = $magic->guessMimeType( $this->mTempPath, false ); |
293 | | - |
294 | | - # check mime type, if desired |
| 303 | + protected function verifyMimeType( $magic, $mime ) { |
295 | 304 | global $wgVerifyMimeType; |
296 | 305 | if ( $wgVerifyMimeType ) { |
297 | 306 | wfDebug ( "\n\nmime: <$mime> extension: <{$this->mFinalExtension}>\n\n"); |
— | — | @@ -316,13 +325,35 @@ |
317 | 326 | } |
318 | 327 | } |
319 | 328 | |
| 329 | + return true; |
| 330 | + } |
| 331 | + |
| 332 | + /** |
| 333 | + * Verifies that it's ok to include the uploaded file |
| 334 | + * |
| 335 | + * @return mixed true of the file is verified, array otherwise. |
| 336 | + */ |
| 337 | + protected function verifyFile() { |
| 338 | + $this->mFileProps = File::getPropsFromPath( $this->mTempPath, $this->mFinalExtension ); |
| 339 | + $this->checkMacBinary(); |
| 340 | + |
| 341 | + # magically determine mime type |
| 342 | + $magic = MimeMagic::singleton(); |
| 343 | + $mime = $magic->guessMimeType( $this->mTempPath, false ); |
| 344 | + |
| 345 | + # check mime type, if desired |
| 346 | + $status = $this->verifyMimeType( $magic, $mime ); |
| 347 | + if ( $status !== true ) { |
| 348 | + return $status; |
| 349 | + } |
| 350 | + |
320 | 351 | # check for htmlish code and javascript |
321 | 352 | if( self::detectScript( $this->mTempPath, $mime, $this->mFinalExtension ) ) { |
322 | | - return 'uploadscripted'; |
| 353 | + return array( 'uploadscripted' ); |
323 | 354 | } |
324 | 355 | if( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) { |
325 | 356 | if( self::detectScriptInSvg( $this->mTempPath ) ) { |
326 | | - return 'uploadscripted'; |
| 357 | + return array( 'uploadscripted' ); |
327 | 358 | } |
328 | 359 | } |
329 | 360 | |
— | — | @@ -354,7 +385,6 @@ |
355 | 386 | return true; |
356 | 387 | } |
357 | 388 | $permErrors = $nt->getUserPermissionsErrors( 'edit', $user ); |
358 | | - $permErrorsUpload = $nt->getUserPermissionsErrors( 'upload', $user ); |
359 | 389 | $permErrorsCreate = ( $nt->exists() ? array() : $nt->getUserPermissionsErrors( 'create', $user ) ); |
360 | 390 | if( $permErrors || $permErrorsUpload || $permErrorsCreate ) { |
361 | 391 | $permErrors = array_merge( $permErrors, wfArrayDiff2( $permErrorsUpload, $permErrors ) ); |
— | — | @@ -440,7 +470,8 @@ |
441 | 471 | * @return mixed Status indicating the whether the upload succeeded. |
442 | 472 | */ |
443 | 473 | public function performUpload( $comment, $pageText, $watch, $user ) { |
444 | | - wfDebug( "\n\n\performUpload: sum:" . $comment . ' c: ' . $pageText . ' w:' . $watch ); |
| 474 | + wfDebug( "\n\n\performUpload: sum: " . $comment . ' c: ' . $pageText . |
| 475 | + ' w: ' . $watch ); |
445 | 476 | $status = $this->getLocalFile()->upload( $this->mTempPath, $comment, $pageText, |
446 | 477 | File::DELETE_SOURCE, $this->mFileProps, false, $user ); |
447 | 478 | |
— | — | @@ -575,7 +606,8 @@ |
576 | 607 | } |
577 | 608 | |
578 | 609 | /** |
579 | | - * Generate a random session key from stash in cases where we want to start an upload without much information |
| 610 | + * Generate a random session key from stash in cases where we want |
| 611 | + * to start an upload without much information |
580 | 612 | */ |
581 | 613 | protected function getSessionKey() { |
582 | 614 | $key = mt_rand( 0, 0x7fffffff ); |
— | — | @@ -850,7 +882,8 @@ |
851 | 883 | |
852 | 884 | if ( !$wgAntivirusSetup[$wgAntivirus] ) { |
853 | 885 | wfDebug( __METHOD__ . ": unknown virus scanner: $wgAntivirus\n" ); |
854 | | - $wgOut->wrapWikiMsg( "<div class=\"error\">\n$1</div>", array( 'virus-badscanner', $wgAntivirus ) ); |
| 886 | + $wgOut->wrapWikiMsg( "<div class=\"error\">\n$1</div>", |
| 887 | + array( 'virus-badscanner', $wgAntivirus ) ); |
855 | 888 | return wfMsg( 'virus-unknownscanner' ) . " $wgAntivirus"; |
856 | 889 | } |
857 | 890 | |
— | — | @@ -1133,4 +1166,9 @@ |
1134 | 1167 | return ApiQueryImageInfo::getInfo( $file, array_flip( $imParam ), $result ); |
1135 | 1168 | } |
1136 | 1169 | |
| 1170 | + public function convertVerifyErrorToStatus( $error ) { |
| 1171 | + $args = func_get_args(); |
| 1172 | + array_shift($args); |
| 1173 | + return Status::newFatal( $this->getVerificationErrorCode( $error ), $args ); |
| 1174 | + } |
1137 | 1175 | } |
Index: trunk/phase3/includes/api/ApiUpload.php |
— | — | @@ -83,7 +83,7 @@ |
84 | 84 | } elseif ( isset( $this->mParams['url'] ) ) { |
85 | 85 | // make sure upload by URL is enabled: |
86 | 86 | if ( !$wgAllowCopyUploads ) { |
87 | | - $this->dieUsageMsg( array( 'uploaddisabled' ) ); |
| 87 | + $this->dieUsageMsg( array( 'copyuploaddisabled' ) ); |
88 | 88 | } |
89 | 89 | |
90 | 90 | // make sure the current user can upload |
— | — | @@ -91,14 +91,12 @@ |
92 | 92 | $this->dieUsageMsg( array( 'badaccess-groups' ) ); |
93 | 93 | } |
94 | 94 | |
95 | | - $this->mUpload = new UploadFromUrl(); |
96 | | - $this->mUpload->initialize( $this->mParams['filename'], |
97 | | - $this->mParams['url'] ); |
| 95 | + $this->mUpload = new UploadFromUrl; |
| 96 | + $this->mUpload->initialize( $this->mParams['filename'], $this->mParams['url'], |
| 97 | + $this->mParams['comment'] ); |
98 | 98 | |
99 | | - $status = $this->mUpload->fetchFile(); |
100 | | - if ( !$status->isOK() ) { |
101 | | - $this->dieUsage( $status->getWikiText(), 'fetchfileerror' ); |
102 | | - } |
| 99 | + $this->getResult()->addValue( null, $this->getModuleName(), Status::newGood() ); |
| 100 | + return; |
103 | 101 | } |
104 | 102 | } else { |
105 | 103 | $this->dieUsageMsg( array( 'missingparam', 'filename' ) ); |
Index: trunk/phase3/includes/api/ApiUserrights.php |
— | — | @@ -43,6 +43,7 @@ |
44 | 44 | |
45 | 45 | $user = $this->getUser(); |
46 | 46 | |
| 47 | + $form = new UserrightsPage; |
47 | 48 | $r['user'] = $user->getName(); |
48 | 49 | list( $r['added'], $r['removed'] ) = |
49 | 50 | $form->doSaveUserGroups( |
Index: trunk/phase3/includes/api/ApiBase.php |
— | — | @@ -989,6 +989,7 @@ |
990 | 990 | 'invalid-session-key' => array( 'code' => 'invalid-session-key', 'info' => 'Not a valid session key' ), |
991 | 991 | 'nouploadmodule' => array( 'code' => 'nouploadmodule', 'info' => 'No upload module set' ), |
992 | 992 | 'uploaddisabled' => array( 'code' => 'uploaddisabled', 'info' => 'Uploads are not enabled. Make sure $wgEnableUploads is set to true in LocalSettings.php and the PHP ini setting file_uploads is true' ), |
| 993 | + 'copyuploaddisabled' => array( 'code' => 'copyuploaddisabled', 'info' => 'Uploads by URL is not enabled. Make sure $wgAllowCopyUploads is set to true in LocalSettings.php.' ), |
993 | 994 | ); |
994 | 995 | |
995 | 996 | /** |
Index: trunk/phase3/includes/UploadFromUrlJob.php |
— | — | @@ -0,0 +1,30 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Job for email notification mails |
| 6 | + * |
| 7 | + * @ingroup JobQueue |
| 8 | + */ |
| 9 | +class UploadFromUrlJob extends Job { |
| 10 | + |
| 11 | + public function __construct( $title, $params, $id = 0 ) { |
| 12 | + parent::__construct( 'uploadFromUrl', $title, $params, $id ); |
| 13 | + } |
| 14 | + |
| 15 | + public function run() { |
| 16 | + global $wgUser; |
| 17 | + |
| 18 | + if ( $this->params['userID'] ) { |
| 19 | + $wgUser = User::newFromId( $this->params['userID'] ); |
| 20 | + } else { |
| 21 | + $wgUser = new User; |
| 22 | + } |
| 23 | + $wgUser->mEffectiveGroups[] = 'sysop'; |
| 24 | + $wgUser->mRights = null; |
| 25 | + |
| 26 | + $upload = new UploadFromUrl(); |
| 27 | + $upload->initializeFromJob( $this ); |
| 28 | + |
| 29 | + return $upload->doUpload(); |
| 30 | + } |
| 31 | +} |
Property changes on: trunk/phase3/includes/UploadFromUrlJob.php |
___________________________________________________________________ |
Added: svn:eol-syle |
1 | 32 | + native |
Index: trunk/phase3/maintenance/language/messages.inc |
— | — | @@ -1233,6 +1233,7 @@ |
1234 | 1234 | 'uploadedimage', |
1235 | 1235 | 'overwroteimage', |
1236 | 1236 | 'uploaddisabled', |
| 1237 | + 'copyuploaddisabled', |
1237 | 1238 | 'uploaddisabledtext', |
1238 | 1239 | 'php-uploaddisabledtext', |
1239 | 1240 | 'uploadscripted', |
Index: trunk/phase3/maintenance/tests/MediaWikiParserTest.php |
— | — | @@ -27,6 +27,7 @@ |
28 | 28 | $tables[] = 'filearchive'; |
29 | 29 | $tables[] = 'logging'; |
30 | 30 | $tables[] = 'updatelog'; |
| 31 | + $tables[] = 'iwlinks'; |
31 | 32 | return true; |
32 | 33 | } |
33 | 34 | |
Index: trunk/phase3/maintenance/tests/UploadFromUrlTest.php |
— | — | @@ -0,0 +1,191 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +global $IP; |
| 5 | +require_once( "ApiSetup.php" ); |
| 6 | +require_once( dirname( dirname( __FILE__ ) ) . "/deleteArchivedFiles.inc" ); |
| 7 | +require_once( dirname( dirname( __FILE__ ) ) . "/deleteArchivedRevisions.inc" ); |
| 8 | + |
| 9 | +class nullClass { |
| 10 | + public function handleOutput(){} |
| 11 | + public function purgeRedundantText(){} |
| 12 | +} |
| 13 | + |
| 14 | +class UploadFromUrlTest extends ApiSetup { |
| 15 | + |
| 16 | + function setUp() { |
| 17 | + global $wgEnableUploads, $wgLocalFileRepo; |
| 18 | + |
| 19 | + $wgEnableUploads = true; |
| 20 | + parent::setup(); |
| 21 | + $wgLocalFileRepo = array( |
| 22 | + 'class' => 'LocalRepo', |
| 23 | + 'name' => 'local', |
| 24 | + 'directory' => 'test-repo', |
| 25 | + 'url' => 'http://example.com/images', |
| 26 | + 'hashLevels' => 2, |
| 27 | + 'transformVia404' => false, |
| 28 | + ); |
| 29 | + |
| 30 | + ini_set( 'log_errors', 1 ); |
| 31 | + ini_set( 'error_reporting', 1 ); |
| 32 | + ini_set( 'display_errors', 1 ); |
| 33 | + } |
| 34 | + |
| 35 | + function doApiRequest( $params, $data = null ) { |
| 36 | + $session = isset( $data[2] ) ? $data[2] : array(); |
| 37 | + $_SESSION = $session; |
| 38 | + |
| 39 | + $req = new FauxRequest( $params, true, $session ); |
| 40 | + $module = new ApiMain( $req, true ); |
| 41 | + $module->execute(); |
| 42 | + |
| 43 | + return array( $module->getResultData(), $req, $_SESSION ); |
| 44 | + } |
| 45 | + |
| 46 | + function testClearQueue() { |
| 47 | + while ( $job = Job::pop() ) {} |
| 48 | + $this->assertFalse($job); |
| 49 | + } |
| 50 | + |
| 51 | + function testLogin() { |
| 52 | + $data = $this->doApiRequest( array( |
| 53 | + 'action' => 'login', |
| 54 | + 'lgname' => self::$userName, |
| 55 | + 'lgpassword' => self::$passWord ) ); |
| 56 | + $this->assertArrayHasKey( "login", $data[0] ); |
| 57 | + $this->assertArrayHasKey( "result", $data[0]['login'] ); |
| 58 | + $this->assertEquals( "NeedToken", $data[0]['login']['result'] ); |
| 59 | + $token = $data[0]['login']['token']; |
| 60 | + |
| 61 | + $data = $this->doApiRequest( array( |
| 62 | + 'action' => 'login', |
| 63 | + "lgtoken" => $token, |
| 64 | + "lgname" => self::$userName, |
| 65 | + "lgpassword" => self::$passWord ) ); |
| 66 | + |
| 67 | + $this->assertArrayHasKey( "login", $data[0] ); |
| 68 | + $this->assertArrayHasKey( "result", $data[0]['login'] ); |
| 69 | + $this->assertEquals( "Success", $data[0]['login']['result'] ); |
| 70 | + $this->assertArrayHasKey( 'lgtoken', $data[0]['login'] ); |
| 71 | + |
| 72 | + return $data; |
| 73 | + } |
| 74 | + |
| 75 | + /** |
| 76 | + * @depends testLogin |
| 77 | + */ |
| 78 | + function testSetupUrlDownload( $data ) { |
| 79 | + global $wgUser; |
| 80 | + $wgUser = User::newFromName( self::$userName ); |
| 81 | + $wgUser->load(); |
| 82 | + $data[2]['wsEditToken'] = $data[2]['wsToken']; |
| 83 | + $token = md5( $data[2]['wsToken'] ) . EDIT_TOKEN_SUFFIX; |
| 84 | + $exception = false; |
| 85 | + |
| 86 | + try { |
| 87 | + $this->doApiRequest( array( |
| 88 | + 'action' => 'upload', |
| 89 | + ), $data ); |
| 90 | + } catch ( UsageException $e ) { |
| 91 | + $exception = true; |
| 92 | + $this->assertEquals( "The token parameter must be set", $e->getMessage() ); |
| 93 | + } |
| 94 | + $this->assertTrue( $exception, "Got exception" ); |
| 95 | + |
| 96 | + $exception = false; |
| 97 | + try { |
| 98 | + $this->doApiRequest( array( |
| 99 | + 'action' => 'upload', |
| 100 | + 'token' => $token, |
| 101 | + ), $data ); |
| 102 | + } catch ( UsageException $e ) { |
| 103 | + $exception = true; |
| 104 | + $this->assertEquals( "One of the parameters sessionkey, file, url is required", |
| 105 | + $e->getMessage() ); |
| 106 | + } |
| 107 | + $this->assertTrue( $exception, "Got exception" ); |
| 108 | + |
| 109 | + $exception = false; |
| 110 | + try { |
| 111 | + $this->doApiRequest( array( |
| 112 | + 'action' => 'upload', |
| 113 | + 'url' => 'http://www.example.com/test.png', |
| 114 | + 'token' => $token, |
| 115 | + ), $data ); |
| 116 | + } catch ( UsageException $e ) { |
| 117 | + $exception = true; |
| 118 | + $this->assertEquals( "The filename parameter must be set", $e->getMessage() ); |
| 119 | + } |
| 120 | + $this->assertTrue( $exception, "Got exception" ); |
| 121 | + |
| 122 | + $wgUser->removeGroup('sysop'); |
| 123 | + $exception = false; |
| 124 | + try { |
| 125 | + $this->doApiRequest( array( |
| 126 | + 'action' => 'upload', |
| 127 | + 'url' => 'http://www.example.com/test.png', |
| 128 | + 'filename' => 'Test.png', |
| 129 | + 'token' => $token, |
| 130 | + ), $data ); |
| 131 | + } catch ( UsageException $e ) { |
| 132 | + $exception = true; |
| 133 | + $this->assertEquals( "Permission denied", $e->getMessage() ); |
| 134 | + } |
| 135 | + $this->assertTrue( $exception, "Got exception" ); |
| 136 | + |
| 137 | + $wgUser->addGroup('*'); |
| 138 | + $wgUser->addGroup('sysop'); |
| 139 | + $exception = false; |
| 140 | + $data = $this->doApiRequest( array( |
| 141 | + 'action' => 'upload', |
| 142 | + 'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png', |
| 143 | + 'filename' => 'Test.png', |
| 144 | + 'token' => $token, |
| 145 | + ), $data ); |
| 146 | + |
| 147 | + $this->assertThat( $data[0]['upload'], $this->isInstanceOf( 'Status' ), |
| 148 | + "Got Status Object" ); |
| 149 | + $this->assertTrue( $data[0]['upload']->isOk(), 'Job added'); |
| 150 | + |
| 151 | + $job = Job::pop(); |
| 152 | + $this->assertThat( $job, $this->isInstanceOf( 'UploadFromUrlJob' ), |
| 153 | + "Got Job Object" ); |
| 154 | + |
| 155 | + $job = Job::pop_type( 'upload' ); |
| 156 | + $this->assertFalse( $job ); |
| 157 | + } |
| 158 | + |
| 159 | + /** |
| 160 | + * @depends testLogin |
| 161 | + */ |
| 162 | + function testDoDownload( $data ) { |
| 163 | + global $wgUser; |
| 164 | + $data[2]['wsEditToken'] = $data[2]['wsToken']; |
| 165 | + $token = md5( $data[2]['wsToken'] ) . EDIT_TOKEN_SUFFIX; |
| 166 | + |
| 167 | + $wgUser->addGroup('users'); |
| 168 | + $data = $this->doApiRequest( array( |
| 169 | + 'action' => 'upload', |
| 170 | + 'filename' => 'Test.png', |
| 171 | + 'url' => 'http://bits.wikimedia.org/skins-1.5/common/images/poweredby_mediawiki_88x31.png', |
| 172 | + 'token' => $token, |
| 173 | + ), $data ); |
| 174 | + |
| 175 | + $job = Job::pop(); |
| 176 | + $this->assertEquals( 'UploadFromUrlJob', get_class($job) ); |
| 177 | + |
| 178 | + $status = $job->run(); |
| 179 | + $this->assertTrue( $status->isOk() ); |
| 180 | + |
| 181 | + return $data; |
| 182 | + } |
| 183 | + |
| 184 | + /** |
| 185 | + * @depends testDoDownload |
| 186 | + */ |
| 187 | + function testVerifyDownload( $data ) { |
| 188 | + $t = Title::newFromText("Test.png", NS_FILE); |
| 189 | + |
| 190 | + $this->assertTrue($t->exists()); |
| 191 | + } |
| 192 | +} |
Property changes on: trunk/phase3/maintenance/tests/UploadFromUrlTest.php |
___________________________________________________________________ |
Added: svn:eol-syle |
1 | 193 | + native |