Merge "ApiUpload: Better handle ApiMessage errors from UploadVerifyFile hook"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 11 Jul 2016 19:34:49 +0000 (19:34 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 11 Jul 2016 19:34:49 +0000 (19:34 +0000)
1  2 
docs/hooks.txt
includes/api/ApiUpload.php
includes/upload/UploadBase.php

diff --combined docs/hooks.txt
@@@ -371,8 -371,7 +371,8 @@@ $user: Current use
  &$message: API usage message to die with, as a message key or array
    as accepted by ApiBase::dieUsageMsg.
  
 -'APIEditBeforeSave': Before saving a page with api.php?action=edit, after
 +'APIEditBeforeSave': DEPRECATED! Use EditFilterMergedContent instead.
 +Before saving a page with api.php?action=edit, after
  processing request parameters. Return false to let the request fail, returning
  an error message or an <edit result="Failure"> tag if $resultArr was filled.
  Unlike for example 'EditFilterMergedContent' this also being run on undo.
@@@ -444,15 -443,6 +444,15 @@@ an exception is thrown during API actio
  $apiMain: Calling ApiMain instance.
  $e: Exception object.
  
 +'ApiMakeParserOptions': Called from ApiParse and ApiExpandTemplates to allow
 +extensions to adjust the ParserOptions before parsing.
 +$options: ParserOptions object
 +$title: Title to be parsed
 +$params: Parameter array for the API module
 +$module: API module (which is also a ContextSource)
 +&$reset: Set to a ScopedCallback used to reset any hooks after the parse is done.
 +&$suppressCache: Set true if cache should be suppressed.
 +
  'ApiOpenSearchSuggest': Called when constructing the OpenSearch results. Hooks
  can alter or append to the array.
  &$results: array with integer keys to associative arrays. Keys in associative
@@@ -683,10 -673,6 +683,10 @@@ $oldPageID: the page ID of the revisio
  revisions of an article.
  $title: Title object of the article
  $ids: Ids to set the visibility for
 +$visibilityChangeMap: Map of revision id to oldBits and newBits.  This array can be
 +  examined to determine exactly what visibility bits have changed for each
 +  revision.  This array is of the form
 +  [id => ['oldBits' => $oldBits, 'newBits' => $newBits], ... ]
  
  'ArticleRollbackComplete': After an article rollback is completed.
  $wikiPage: the WikiPage that was edited
@@@ -933,7 -919,6 +933,7 @@@ $wikiPage: WikiPage that was adde
  'CategoryAfterPageRemoved': After a page is removed from a category.
  $category: Category that page was removed from
  $wikiPage: WikiPage that was removed
 +$id: the page ID (original ID in case of page deletions)
  
  'CategoryPageView': Before viewing a categorypage in CategoryPage::view.
  &$catpage: CategoryPage instance
@@@ -2881,12 -2866,6 +2881,12 @@@ $id: User id number, only provided for 
  $user: User object representing user contributions are being fetched for
  $sp: SpecialPage instance, providing context
  
 +'SpecialContributions::formatRow::flags': Called before rendering a
 +Special:Contributions row.
 +$context: IContextSource object
 +$row: Revision information from the database
 +&$flags: List of flags on this row
 +
  'SpecialContributions::getForm::filters': Called with a list of filters to render
  on Special:Contributions.
  $sp: SpecialContributions object, for context
@@@ -3289,8 -3268,8 +3289,8 @@@ added to the descripto
  &$radio: Boolean, if source type should be shown as radio button
  $selectedSourceType: The selected source type
  
 -'UploadVerification': Additional chances to reject an uploaded file. Consider
 -using UploadVerifyFile instead.
 +'UploadVerification': DEPRECATED! Use UploadVerifyFile instead.
 +Additional chances to reject an uploaded file.
  $saveName: (string) destination file name
  $tempName: (string) filesystem path to the temporary file for checks
  &$error: (string) output: message key for message to show if upload canceled by
@@@ -3302,9 -3281,10 +3302,10 @@@ in most cases over UploadVerification
  $upload: (object) an instance of UploadBase, with all info about the upload
  $mime: (string) The uploaded file's MIME type, as detected by MediaWiki.
    Handlers will typically only apply for specific MIME types.
- &$error: (object) output: true if the file is valid. Otherwise, an indexed array
-   representing the problem with the file, where the first element is the message
-   key and the remaining elements are used as parameters to the message.
+ &$error: (object) output: true if the file is valid. Otherwise, set this to the reason
+   in the form of array( messagename, param1, param2, ... ) or a MessageSpecifier
+   instance (you might want to use ApiMessage to provide machine-readable details
+   for the API).
  
  'UploadVerifyUpload': Upload verification, based on both file properties like
  MIME type (same as UploadVerifyFile) and the information entered by the user
@@@ -347,7 -347,7 +347,7 @@@ class ApiUpload extends ApiBase 
         * Throw an error that the user can recover from by providing a better
         * value for $parameter
         *
 -       * @param array $error Error array suitable for passing to dieUsageMsg()
 +       * @param array|string|MessageSpecifier $error Error suitable for passing to dieUsageMsg()
         * @param string $parameter Parameter that needs revising
         * @param array $data Optional extra data to pass to the user
         * @param string $code Error code to use if the error is unknown
                                $this->dieUsage( $msg, 'filetype-banned', 0, $extradata );
                                break;
                        case UploadBase::VERIFICATION_ERROR:
-                               $params = $verification['details'];
-                               $key = array_shift( $params );
-                               $msg = $this->msg( $key, $params )->inLanguage( 'en' )->useDatabase( false )->text();
-                               ApiResult::setIndexedTagName( $verification['details'], 'detail' );
-                               $this->dieUsage( "This file did not pass file verification: $msg", 'verification-error',
-                                       0, [ 'details' => $verification['details'] ] );
+                               $parsed = $this->parseMsg( $verification['details'] );
+                               $info = "This file did not pass file verification: {$parsed['info']}";
+                               if ( $verification['details'][0] instanceof IApiMessage ) {
+                                       $code = $parsed['code'];
+                               } else {
+                                       // For backwards-compatibility, all of the errors from UploadBase::verifyFile() are
+                                       // reported as 'verification-error', and the real error code is reported in 'details'.
+                                       $code = 'verification-error';
+                               }
+                               if ( $verification['details'][0] instanceof IApiMessage ) {
+                                       $msg = $verification['details'][0];
+                                       $details = array_merge( [ $msg->getKey() ], $msg->getParams() );
+                               } else {
+                                       $details = $verification['details'];
+                               }
+                               ApiResult::setIndexedTagName( $details, 'detail' );
+                               $data = [ 'details' => $details ];
+                               if ( isset( $parsed['data'] ) ) {
+                                       $data = array_merge( $data, $parsed['data'] );
+                               }
+                               $this->dieUsage( $info, $code, 0, $data );
                                break;
                        case UploadBase::HOOK_ABORTED:
                                if ( is_array( $verification['error'] ) ) {
@@@ -353,7 -353,7 +353,7 @@@ abstract class UploadBase 
  
                $error = '';
                if ( !Hooks::run( 'UploadVerification',
 -                      [ $this->mDestName, $this->mTempPath, &$error ] )
 +                      [ $this->mDestName, $this->mTempPath, &$error ], '1.28' )
                ) {
                        return [ 'status' => self::HOOK_ABORTED, 'error' => $error ];
                }
                        }
                }
  
-               Hooks::run( 'UploadVerifyFile', [ $this, $mime, &$status ] );
-               if ( $status !== true ) {
-                       return $status;
+               $error = true;
+               Hooks::run( 'UploadVerifyFile', [ $this, $mime, &$error ] );
+               if ( $error !== true ) {
+                       if ( !is_array( $error ) ) {
+                               $error = [ $error ];
+                       }
+                       return $error;
                }
  
                wfDebug( __METHOD__ . ": all clear; passing.\n" );
                                return [ 'uploaded-event-handler-on-svg', $attrib, $value ];
                        }
  
 -                      # href with non-local target (don't allow http://, javascript:, etc)
 +                      # Do not allow relative links, or unsafe url schemas.
 +                      # For <a> tags, only data:, http: and https: and same-document
 +                      # fragment links are allowed. For all other tags, only data:
 +                      # and fragment are allowed.
                        if ( $stripped == 'href'
                                && strpos( $value, 'data:' ) !== 0
                                && strpos( $value, '#' ) !== 0