Merge "Delete UIDGenerator cache files after unit tests"
[lhc/web/wiklou.git] / includes / api / ApiMain.php
index 5735b76..2e16312 100644 (file)
@@ -39,7 +39,6 @@
  * @ingroup API
  */
 class ApiMain extends ApiBase {
-
        /**
         * When no format parameter is given, this format will be used
         */
@@ -57,6 +56,7 @@ class ApiMain extends ApiBase {
                'parse' => 'ApiParse',
                'opensearch' => 'ApiOpenSearch',
                'feedcontributions' => 'ApiFeedContributions',
+               'feedrecentchanges' => 'ApiFeedRecentChanges',
                'feedwatchlist' => 'ApiFeedWatchlist',
                'help' => 'ApiHelp',
                'paraminfo' => 'ApiParamInfo',
@@ -84,6 +84,7 @@ class ApiMain extends ApiBase {
                'userrights' => 'ApiUserrights',
                'options' => 'ApiOptions',
                'imagerotate' => 'ApiImageRotate',
+               'revisiondelete' => 'ApiRevisionDelete',
        );
 
        /**
@@ -361,37 +362,7 @@ class ApiMain extends ApiBase {
                try {
                        $this->executeAction();
                } catch ( Exception $e ) {
-                       // Allow extra cleanup and logging
-                       wfRunHooks( 'ApiMain::onException', array( $this, $e ) );
-
-                       // Log it
-                       if ( !( $e instanceof UsageException ) ) {
-                               MWExceptionHandler::logException( $e );
-                       }
-
-                       // Handle any kind of exception by outputting properly formatted error message.
-                       // If this fails, an unhandled exception should be thrown so that global error
-                       // handler will process and log it.
-
-                       $errCode = $this->substituteResultWithError( $e );
-
-                       // Error results should not be cached
-                       $this->setCacheMode( 'private' );
-
-                       $response = $this->getRequest()->response();
-                       $headerStr = 'MediaWiki-API-Error: ' . $errCode;
-                       if ( $e->getCode() === 0 ) {
-                               $response->header( $headerStr );
-                       } else {
-                               $response->header( $headerStr, true, $e->getCode() );
-                       }
-
-                       // Reset and print just the error message
-                       ob_clean();
-
-                       // If the error occurred during printing, do a printer->profileOut()
-                       $this->mPrinter->safeProfileOut();
-                       $this->printResult( true );
+                       $this->handleException( $e );
                }
 
                // Log the request whether or not there was an error
@@ -408,6 +379,76 @@ class ApiMain extends ApiBase {
                ob_end_flush();
        }
 
+       /**
+        * Handle an exception as an API response
+        *
+        * @since 1.23
+        * @param Exception $e
+        */
+       protected function handleException( Exception $e ) {
+               // Bug 63145: Rollback any open database transactions
+               MWExceptionHandler::rollbackMasterChangesAndLog( $e );
+
+               // Allow extra cleanup and logging
+               wfRunHooks( 'ApiMain::onException', array( $this, $e ) );
+
+               // Log it
+               if ( !( $e instanceof UsageException ) ) {
+                       MWExceptionHandler::logException( $e );
+               }
+
+               // Handle any kind of exception by outputting properly formatted error message.
+               // If this fails, an unhandled exception should be thrown so that global error
+               // handler will process and log it.
+
+               $errCode = $this->substituteResultWithError( $e );
+
+               // Error results should not be cached
+               $this->setCacheMode( 'private' );
+
+               $response = $this->getRequest()->response();
+               $headerStr = 'MediaWiki-API-Error: ' . $errCode;
+               if ( $e->getCode() === 0 ) {
+                       $response->header( $headerStr );
+               } else {
+                       $response->header( $headerStr, true, $e->getCode() );
+               }
+
+               // Reset and print just the error message
+               ob_clean();
+
+               // If the error occurred during printing, do a printer->profileOut()
+               $this->mPrinter->safeProfileOut();
+               $this->printResult( true );
+       }
+
+       /**
+        * Handle an exception from the ApiBeforeMain hook.
+        *
+        * This tries to print the exception as an API response, to be more
+        * friendly to clients. If it fails, it will rethrow the exception.
+        *
+        * @since 1.23
+        * @param Exception $e
+        */
+       public static function handleApiBeforeMainException( Exception $e ) {
+               ob_start();
+
+               try {
+                       $main = new self( RequestContext::getMain(), false );
+                       $main->handleException( $e );
+               } catch ( Exception $e2 ) {
+                       // Nope, even that didn't work. Punt.
+                       throw $e;
+               }
+
+               // Log the request and reset cache headers
+               $main->logRequest( 0 );
+               $main->sendCacheHeaders();
+
+               ob_end_flush();
+       }
+
        /**
         * Check the &origin= query parameter against the Origin: HTTP header and respond appropriately.
         *
@@ -603,6 +644,7 @@ class ApiMain extends ApiBase {
                global $wgShowHostnames;
 
                $result = $this->getResult();
+
                // Printer may not be initialized if the extractRequestParams() fails for the main module
                if ( !isset( $this->mPrinter ) ) {
                        // The printer has not been created yet. Try to manually get formatter value.
@@ -612,11 +654,18 @@ class ApiMain extends ApiBase {
                        }
 
                        $this->mPrinter = $this->createPrinterByName( $value );
-                       if ( $this->mPrinter->getNeedsRawData() ) {
-                               $result->setRawMode();
-                       }
                }
 
+               // Printer may not be able to handle errors. This is particularly
+               // likely if the module returns something for getCustomPrinter().
+               if ( !$this->mPrinter->canPrintErrors() ) {
+                       $this->mPrinter->safeProfileOut();
+                       $this->mPrinter = $this->createPrinterByName( self::API_DEFAULT_FORMAT );
+               }
+
+               // Update raw mode flag for the selected printer.
+               $result->setRawMode( $this->mPrinter->getNeedsRawData() );
+
                if ( $e instanceof UsageException ) {
                        // User entered incorrect parameters - print usage screen
                        $errMessage = $e->getMessageArray();
@@ -790,6 +839,28 @@ class ApiMain extends ApiBase {
                }
        }
 
+       /**
+        * Check asserts of the user's rights
+        * @param $params array
+        */
+       protected function checkAsserts( $params ) {
+               if ( isset( $params['assert'] ) ) {
+                       $user = $this->getUser();
+                       switch ( $params['assert'] ) {
+                               case 'user':
+                                       if ( $user->isAnon() ) {
+                                               $this->dieUsage( 'Assertion that the user is logged in failed', 'assertuserfailed' );
+                                       }
+                                       break;
+                               case 'bot':
+                                       if ( !$user->isAllowed( 'bot' ) ) {
+                                               $this->dieUsage( 'Assertion that the user has the bot right failed', 'assertbotfailed' );
+                                       }
+                                       break;
+                       }
+               }
+       }
+
        /**
         * Check POST for external response and setup result printer
         * @param $module ApiBase An Api module
@@ -832,6 +903,8 @@ class ApiMain extends ApiBase {
                        $this->setupExternalResponse( $module, $params );
                }
 
+               $this->checkAsserts( $params );
+
                // Execute
                $module->profileIn();
                $module->execute();
@@ -875,7 +948,7 @@ class ApiMain extends ApiBase {
                        }
                }
                $s .= "\n";
-               wfDebugLog( 'api', $s, false );
+               wfDebugLog( 'api', $s, 'private' );
        }
 
        /**
@@ -1021,6 +1094,9 @@ class ApiMain extends ApiBase {
                                ApiBase::PARAM_TYPE => 'integer',
                                ApiBase::PARAM_DFLT => 0
                        ),
+                       'assert' => array(
+                               ApiBase::PARAM_TYPE => array( 'user', 'bot' )
+                       ),
                        'requestid' => null,
                        'servedby' => false,
                        'origin' => null,
@@ -1046,6 +1122,7 @@ class ApiMain extends ApiBase {
                        ),
                        'smaxage' => 'Set the s-maxage header to this many seconds. Errors are never cached',
                        'maxage' => 'Set the max-age header to this many seconds. Errors are never cached',
+                       'assert' => 'Verify the user is logged in if set to "user", or has the bot userright if "bot"',
                        'requestid' => 'Request ID to distinguish requests. This will just be output back to you',
                        'servedby' => 'Include the hostname that served the request in the ' .
                                'results. Unconditionally shown on error',
@@ -1082,14 +1159,14 @@ class ApiMain extends ApiBase {
                        '',
                        'Status:                All features shown on this page should be working, but the API',
                        '                       is still in active development, and may change at any time.',
-                       '                       Make sure to monitor our mailing list for any updates',
+                       '                       Make sure to monitor our mailing list for any updates.',
                        '',
                        'Erroneous requests:    When erroneous requests are sent to the API, a HTTP header will be sent',
                        '                       with the key "MediaWiki-API-Error" and then both the value of the',
-                       '                       header and the error code sent back will be set to the same value',
+                       '                       header and the error code sent back will be set to the same value.',
                        '',
                        '                       In the case of an invalid action being passed, these will have a value',
-                       '                       of "unknown_action"',
+                       '                       of "unknown_action".',
                        '',
                        '                       For more information see https://www.mediawiki.org' .
                                '/wiki/API:Errors_and_warnings',
@@ -1118,6 +1195,11 @@ class ApiMain extends ApiBase {
                        array( 'code' => 'unknown_action', 'info' => 'The API requires a valid action parameter' ),
                        array( 'code' => 'maxlag', 'info' => 'Waiting for host: x seconds lagged' ),
                        array( 'code' => 'maxlag', 'info' => 'Waiting for a database server: x seconds lagged' ),
+                       array( 'code' => 'assertuserfailed', 'info' => 'Assertion that the user is logged in failed' ),
+                       array(
+                               'code' => 'assertbotfailed',
+                               'info' => 'Assertion that the user has the bot right failed'
+                       ),
                ) );
        }
 
@@ -1128,12 +1210,11 @@ class ApiMain extends ApiBase {
        protected function getCredits() {
                return array(
                        'API developers:',
-                       '    Roan Kattouw - roan . kattouw @ gmail . com (lead developer Sep 2007-2009)',
-                       '    Victor Vasiliev - vasilvv @ gmail . com',
-                       '    Bryan Tong Minh - bryan . tongminh @ gmail . com',
-                       '    Sam Reed - sam @ reedyboy . net',
-                       '    Yuri Astrakhan - yuri . astrakhan @ gmail . com (creator, lead ' .
-                               'developer Sep 2006-Sep 2007, 2012-present)',
+                       '    Roan Kattouw (lead developer Sep 2007-2009)',
+                       '    Victor Vasiliev',
+                       '    Bryan Tong Minh',
+                       '    Sam Reed',
+                       '    Yuri Astrakhan (creator, lead developer Sep 2006-Sep 2007, 2012-present)',
                        '',
                        'Please send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org',
                        'or file a bug report at https://bugzilla.wikimedia.org/'