Merge "Allow API results to wrap long lines"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 19 Feb 2013 21:42:25 +0000 (21:42 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 19 Feb 2013 21:42:25 +0000 (21:42 +0000)
1  2 
includes/api/ApiFormatBase.php
includes/api/ApiMain.php

@@@ -58,7 -58,7 +58,7 @@@ abstract class ApiFormatBase extends Ap
         * This method is not called if getIsHtml() returns true.
         * @return string
         */
 -      public abstract function getMimeType();
 +      abstract public function getMimeType();
  
        /**
         * Whether this formatter needs raw data such as _element tags
  
        /**
         * Initialize the printer function and prepare the output headers, etc.
-        * This method must be the first outputing method during execution.
-        * A help screen's header is printed for the HTML-based output
-        * @param $isError bool Whether an error message is printed
+        * This method must be the first outputting method during execution.
+        * A human-targeted notice about available formats is printed for the HTML-based output,
+        * except for help screens (caused by either an error in the API parameters,
+        * the calling of action=help, or requesting the root script api.php).
+        * @param $isHelpScreen bool Whether a help screen is going to be shown
         */
-       function initPrinter( $isError ) {
+       function initPrinter( $isHelpScreen ) {
                if ( $this->mDisabled ) {
                        return;
                }
  <?php
  
  
-                       if ( !$isError ) {
+                       if ( !$isHelpScreen ) {
  ?>
  <br />
  <small>
@@@ -175,15 -177,18 +177,18 @@@ To see the non HTML representation of t
  See the <a href='https://www.mediawiki.org/wiki/API'>complete documentation</a>, or
  <a href='<?php echo( $script ); ?>'>API help</a> for more information.
  </small>
+ <pre style='white-space: pre-wrap;'>
  <?php
  
  
-                       }
+                       } else { // don't wrap the contents of the <pre> for help screens
+                                 // because these are actually formatted to rely on
+                                 // the monospaced font for layout purposes
  ?>
  <pre>
  <?php
  
+                       }
                }
        }
  
        public function getDescription() {
                return $this->getIsHtml() ? ' (pretty-print in HTML)' : '';
        }
 -
 -      public static function getBaseVersion() {
 -              return __CLASS__ . ': $Id$';
 -      }
  }
  
  /**
@@@ -377,4 -386,8 +382,4 @@@ class ApiFormatFeedWrapper extends ApiF
                        ApiBase::dieDebug( __METHOD__, 'Invalid feed class/item' );
                }
        }
 -
 -      public function getVersion() {
 -              return __CLASS__ . ': $Id$';
 -      }
  }
diff --combined includes/api/ApiMain.php
@@@ -131,9 -131,8 +131,9 @@@ class ApiMain extends ApiBase 
         */
        private $mPrinter;
  
 -      private $mModules, $mModuleNames, $mFormats, $mFormatNames;
 -      private $mResult, $mAction, $mShowVersions, $mEnableWrite;
 +      private $mModuleMgr, $mResult;
 +      private $mAction;
 +      private $mEnableWrite;
        private $mInternalMode, $mSquidMaxage, $mModule;
  
        private $mCacheMode = 'private';
                        }
                }
  
 -              global $wgAPIModules; // extension modules
 -              $this->mModules = $wgAPIModules + self::$Modules;
 -
 -              $this->mModuleNames = array_keys( $this->mModules );
 -              $this->mFormats = self::$Formats;
 -              $this->mFormatNames = array_keys( $this->mFormats );
 +              global $wgAPIModules;
 +              $this->mModuleMgr = new ApiModuleManager( $this );
 +              $this->mModuleMgr->addModules( self::$Modules, 'action' );
 +              $this->mModuleMgr->addModules( $wgAPIModules, 'action' );
 +              $this->mModuleMgr->addModules( self::$Formats, 'format' );
  
                $this->mResult = new ApiResult( $this );
 -              $this->mShowVersions = false;
                $this->mEnableWrite = $enableWrite;
  
                $this->mSquidMaxage = - 1; // flag for executeActionWithErrorHandling()
         * @return ApiFormatBase
         */
        public function createPrinterByName( $format ) {
 -              if ( !isset( $this->mFormats[$format] ) ) {
 +              $printer = $this->mModuleMgr->getModule( $format, 'format' );
 +              if ( $printer === null ) {
                        $this->dieUsage( "Unrecognized format: {$format}", 'unknown_format' );
                }
 -              return new $this->mFormats[$format] ( $this, $format );
 +              return $printer;
        }
  
        /**
                                }
                        }
  
 -                      // Handle any kind of exception by outputing properly formatted error message.
 +                      // 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.
  
                if ( !isset ( $this->mPrinter ) ) {
                        // The printer has not been created yet. Try to manually get formatter value.
                        $value = $this->getRequest()->getVal( 'format', self::API_DEFAULT_FORMAT );
 -                      if ( !in_array( $value, $this->mFormatNames ) ) {
 +                      if ( !$this->mModuleMgr->isDefined( $value, 'format' ) ) {
                                $value = self::API_DEFAULT_FORMAT;
                        }
  
                        if ( $this->mPrinter->getWantsHelp() || $this->mAction == 'help' ) {
                                ApiResult::setContent( $errMessage, $this->makeHelpMsg() );
                        }
 -
                } else {
                        global $wgShowSQLErrors, $wgShowExceptionDetails;
                        // Something is seriously wrong
                        ApiResult::setContent( $errMessage, $wgShowExceptionDetails ? "\n\n{$e->getTraceAsString()}\n\n" : '' );
                }
  
 +              // Remember all the warnings to re-add them later
 +              $oldResult = $result->getData();
 +              $warnings = isset( $oldResult['warnings'] ) ? $oldResult['warnings'] : null;
 +
                $result->reset();
                $result->disableSizeCheck();
                // Re-add the id
                if ( !is_null( $requestid ) ) {
                        $result->addValue( null, 'requestid', $requestid );
                }
 -
                if ( $wgShowHostnames ) {
                        // servedby is especially useful when debugging errors
                        $result->addValue( null, 'servedby', wfHostName() );
                }
 +              if ( $warnings !== null ) {
 +                      $result->addValue( null, 'warnings', $warnings );
 +              }
  
                $result->addValue( null, 'error', $errMessage );
  
  
                $params = $this->extractRequestParams();
  
 -              $this->mShowVersions = $params['version'];
                $this->mAction = $params['action'];
  
                if ( !is_string( $this->mAction ) ) {
         */
        protected function setupModule() {
                // Instantiate the module requested by the user
 -              $module = new $this->mModules[$this->mAction] ( $this, $this->mAction );
 -              $this->mModule = $module;
 -
 +              $module = $this->mModuleMgr->getModule( $this->mAction, 'action' );
 +              if ( $module === null ) {
 +                      $this->dieUsage( 'The API requires a valid action parameter', 'unknown_action' );
 +              }
                $moduleParams = $module->extractRequestParams();
  
                // Die if token required, but not provided (unless there is a gettoken parameter)
         * @param $params Array an array with the request parameters
         */
        protected function setupExternalResponse( $module, $params ) {
 -              // Ignore mustBePosted() for internal calls
 -              if ( $module->mustBePosted() && !$this->getRequest()->wasPosted() ) {
 -                      $this->dieUsageMsg( array( 'mustbeposted', $this->mAction ) );
 +              if ( !$this->getRequest()->wasPosted() && $module->mustBePosted() ) {
 +                      // Module requires POST. GET request might still be allowed
 +                      // if $wgDebugApi is true, otherwise fail.
 +                      $this->dieUsageMsgOrDebug( array( 'mustbeposted', $this->mAction ) );
                }
  
                // See if custom printer is used
        protected function executeAction() {
                $params = $this->setupExecuteAction();
                $module = $this->setupModule();
 +              $this->mModule = $module;
  
                $this->checkExecutePermissions( $module );
  
         * @param $isError bool
         */
        protected function printResult( $isError ) {
 +              global $wgDebugAPI;
 +              if( $wgDebugAPI !== false ) {
 +                      $this->setWarning( 'SECURITY WARNING: $wgDebugAPI is enabled' );
 +              }
 +
                $this->getResult()->cleanUpUTF8();
                $printer = $this->mPrinter;
                $printer->profileIn();
                 * tell the printer not to escape ampersands so that our links do
                 * not break.
                 */
-               $printer->setUnescapeAmps( ( $this->mAction == 'help' || $isError )
-                               && $printer->getFormat() == 'XML' && $printer->getIsHtml() );
+               $isHelp = $isError || $this->mAction == 'help';
+               $printer->setUnescapeAmps( $isHelp && $printer->getFormat() == 'XML' && $printer->getIsHtml() );
  
-               $printer->initPrinter( $isError );
+               $printer->initPrinter( $isHelp );
  
                $printer->execute();
                $printer->closePrinter();
                return array(
                        'format' => array(
                                ApiBase::PARAM_DFLT => ApiMain::API_DEFAULT_FORMAT,
 -                              ApiBase::PARAM_TYPE => $this->mFormatNames
 +                              ApiBase::PARAM_TYPE => $this->mModuleMgr->getNames( 'format' )
                        ),
                        'action' => array(
                                ApiBase::PARAM_DFLT => 'help',
 -                              ApiBase::PARAM_TYPE => $this->mModuleNames
 +                              ApiBase::PARAM_TYPE => $this->mModuleMgr->getNames( 'action' )
                        ),
 -                      'version' => false,
                        'maxlag'  => array(
                                ApiBase::PARAM_TYPE => 'integer'
                        ),
                return array(
                        'format' => 'The format of the output',
                        'action' => 'What action you would like to perform. See below for module help',
 -                      'version' => 'When showing help, include version for each module',
                        'maxlag' => array(
                                'Maximum lag can be used when MediaWiki is installed on a database replicated cluster.',
                                'To save actions causing any more site replication lag, this parameter can make the client',
                        '    Victor Vasiliev - vasilvv at gee mail dot com',
                        '    Bryan Tong Minh - bryan . tongminh @ gmail . com',
                        '    Sam Reed - sam @ reedyboy . net',
 -                      '    Yuri Astrakhan "<Firstname><Lastname>@gmail.com" (creator, lead developer Sep 2006-Sep 2007)',
 +                      '    Yuri Astrakhan "<Firstname><Lastname>@gmail.com" (creator, lead developer Sep 2006-Sep 2007, 2012)',
                        '',
                        'Please send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org',
                        'or file a bug report at https://bugzilla.wikimedia.org/'
                $this->setHelp();
                // Get help text from cache if present
                $key = wfMemcKey( 'apihelp', $this->getModuleName(),
 -                      SpecialVersion::getVersion( 'nodb' ) .
 -                      $this->getShowVersions() );
 +                      SpecialVersion::getVersion( 'nodb' ) );
                if ( $wgAPICacheHelpTimeout > 0 ) {
                        $cached = $wgMemc->get( $key );
                        if ( $cached ) {
  
                $astriks = str_repeat( '*** ', 14 );
                $msg .= "\n\n$astriks Modules  $astriks\n\n";
 -              foreach ( array_keys( $this->mModules ) as $moduleName ) {
 -                      $module = new $this->mModules[$moduleName] ( $this, $moduleName );
 +
 +              foreach ( $this->mModuleMgr->getNames( 'action' ) as $name ) {
 +                      $module = $this->mModuleMgr->getModule( $name );
                        $msg .= self::makeHelpMsgHeader( $module, 'action' );
  
                        $msg2 = $module->makeHelpMsg();
                }
  
                $msg .= "\n$astriks Formats  $astriks\n\n";
 -              foreach ( array_keys( $this->mFormats ) as $formatName ) {
 -                      $module = $this->createPrinterByName( $formatName );
 +              foreach ( $this->mModuleMgr->getNames( 'format' ) as $name ) {
 +                      $module = $this->mModuleMgr->getModule( $name );
                        $msg .= self::makeHelpMsgHeader( $module, 'format' );
                        $msg2 = $module->makeHelpMsg();
                        if ( $msg2 !== false ) {
        /**
         * Check whether the user wants us to show version information in the API help
         * @return bool
 +       * @deprecated since 1.21, always returns false
         */
        public function getShowVersions() {
 -              return $this->mShowVersions;
 +              wfDeprecated( __METHOD__, '1.21' );
 +              return false;
        }
  
        /**
 -       * Returns the version information of this file, plus it includes
 -       * the versions for all files that are not callable proper API modules
 -       *
 -       * @return array
 +       * Overrides to return this instance's module manager.
 +       * @return ApiModuleManager
         */
 -      public function getVersion() {
 -              $vers = array();
 -              $vers[] = 'MediaWiki: ' . SpecialVersion::getVersion() . "\n    https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/";
 -              $vers[] = __CLASS__ . ': $Id$';
 -              $vers[] = ApiBase::getBaseVersion();
 -              $vers[] = ApiFormatBase::getBaseVersion();
 -              $vers[] = ApiQueryBase::getBaseVersion();
 -              return $vers;
 +      public function getModuleManager() {
 +              return $this->mModuleMgr;
        }
  
        /**
         * classes who wish to add their own modules to their lexicon or override the
         * behavior of inherent ones.
         *
 -       * @param $mdlName String The identifier for this module.
 -       * @param $mdlClass String The class where this module is implemented.
 +       * @deprecated since 1.21, Use getModuleManager()->addModule() instead.
 +       * @param $name string The identifier for this module.
 +       * @param $class ApiBase The class where this module is implemented.
         */
 -      protected function addModule( $mdlName, $mdlClass ) {
 -              $this->mModules[$mdlName] = $mdlClass;
 +      protected function addModule( $name, $class ) {
 +              $this->getModuleManager()->addModule( $name, 'action', $class );
        }
  
        /**
         * Add or overwrite an output format for this ApiMain. Intended for use by extending
         * classes who wish to add to or modify current formatters.
         *
 -       * @param $fmtName string The identifier for this format.
 -       * @param $fmtClass ApiFormatBase The class implementing this format.
 +       * @deprecated since 1.21, Use getModuleManager()->addModule() instead.
 +       * @param $name string The identifier for this format.
 +       * @param $class ApiFormatBase The class implementing this format.
         */
 -      protected function addFormat( $fmtName, $fmtClass ) {
 -              $this->mFormats[$fmtName] = $fmtClass;
 +      protected function addFormat( $name, $class ) {
 +              $this->getModuleManager->addModule( $name, 'format', $class );
        }
  
        /**
         * Get the array mapping module names to class names
 +       * @deprecated since 1.21, Use getModuleManager()'s methods instead.
         * @return array
         */
        function getModules() {
 -              return $this->mModules;
 +              return $this->getModuleManager()->getNamesWithClasses( 'action' );
        }
  
        /**
         * Returns the list of supported formats in form ( 'format' => 'ClassName' )
         *
         * @since 1.18
 +       * @deprecated since 1.21, Use getModuleManager()'s methods instead.
         * @return array
         */
        public function getFormats() {
 -              return $this->mFormats;
 +              return $this->getModuleManager()->getNamesWithClasses( 'format' );
        }
  }