* API-query: normalization
authorYuri Astrakhan <yurik@users.mediawiki.org>
Sat, 23 Sep 2006 23:30:25 +0000 (23:30 +0000)
committerYuri Astrakhan <yurik@users.mediawiki.org>
Sat, 23 Sep 2006 23:30:25 +0000 (23:30 +0000)
* API: help screen improvements

includes/api/ApiBase.php
includes/api/ApiFormatBase.php
includes/api/ApiHelp.php
includes/api/ApiLogin.php
includes/api/ApiMain.php
includes/api/ApiQuery.php

index fb9395e..b374d73 100644 (file)
  */\r
 \r
 // Multi-valued enums, limit the values user can supply for the parameter\r
-define('GN_ENUM_DFLT', 0);\r
-define('GN_ENUM_ISMULTI', 1);\r
-define('GN_ENUM_CHOICES', 2);\r
+define('GN_ENUM_DFLT', 'dflt');\r
+define('GN_ENUM_ISMULTI', 'multi');\r
+define('GN_ENUM_CHOICES', 'choices');\r
+define('GN_ENUM_TYPE', 'type');\r
 \r
 abstract class ApiBase {\r
 \r
@@ -76,19 +77,23 @@ abstract class ApiBase {
         */\r
        public function MakeHelpMsg() {\r
 \r
+               static $lnPrfx = "\n  ";\r
+\r
                $msg = $this->GetDescription();\r
 \r
                if ($msg !== false) {\r
 \r
-                       if (is_array($msg))\r
-                               $msg = implode("\n", $msg);\r
-                       $msg .= "\n";\r
+                       if (!is_array($msg))\r
+                               $msg = array (\r
+                                       $msg\r
+                               );\r
+                       $msg = $lnPrfx . implode($lnPrfx, $msg) . "\n";\r
 \r
                        // Parameters\r
                        $params = $this->GetAllowedParams();\r
                        if ($params !== false) {\r
                                $paramsDescription = $this->GetParamDescription();\r
-                               $msg .= "Supported Parameters:\n";\r
+                               $msg .= "Parameters:\n";\r
                                foreach (array_keys($params) as $paramName) {\r
                                        $desc = isset ($paramsDescription[$paramName]) ? $paramsDescription[$paramName] : '';\r
                                        $msg .= sprintf("  %-14s - %s\n", $paramName, $desc);\r
@@ -98,12 +103,12 @@ abstract class ApiBase {
                        // Examples\r
                        $examples = $this->GetExamples();\r
                        if ($examples !== false) {\r
-                               if (is_array($examples)) {\r
-                                       $msg .= "Examples:\n";\r
-                                       $msg .= implode("\n  ", $examples) . "\n";\r
-                               } else {\r
-                                       $msg .= "Example:   $examples\n";\r
-                               }\r
+                               if (!is_array($examples))\r
+                                       $examples = array (\r
+                                               $examples\r
+                                       );\r
+                               $msg .= 'Example' . (count($examples) > 1 ? 's' : '') . ":\n  ";\r
+                               $msg .= implode($lnPrfx, $examples) . "\n";\r
                        }\r
                }\r
 \r
@@ -167,8 +172,24 @@ abstract class ApiBase {
                                        $dflt = isset ($enumParams[GN_ENUM_DFLT]) ? $enumParams[GN_ENUM_DFLT] : null;\r
                                        $multi = isset ($enumParams[GN_ENUM_ISMULTI]) ? $enumParams[GN_ENUM_ISMULTI] : false;\r
                                        $choices = isset ($enumParams[GN_ENUM_CHOICES]) ? $enumParams[GN_ENUM_CHOICES] : null;\r
+                                       $type = isset ($enumParams[GN_ENUM_TYPE]) ? $enumParams[GN_ENUM_TYPE] : null;\r
+\r
                                        $value = $wgRequest->getVal($param, $dflt);\r
-                                       $result = $this->ParseMultiValue($param, $value, $multi, $choices);\r
+\r
+                                       // Allow null when default is not set\r
+                                       if (isset ($dflt) || isset ($value)) {\r
+                                               $result = $this->ParseMultiValue($param, $value, $multi, $choices);\r
+\r
+                                               // When choices are not given, and the default is an integer, make sure all values are integers\r
+                                               if (!isset ($choices) && isset ($dflt) && $type === 'integer') {\r
+                                                       if (is_array($result))\r
+                                                               $result = array_map('intval', $result);\r
+                                                       else\r
+                                                               $result = intval($result);\r
+                                               }\r
+                                       } else {\r
+                                               $result = null;\r
+                                       }\r
                                        break;\r
                                default :\r
                                        $this->DieDebug("In '$param', unprocessed type " . gettype($dflt));\r
index b6195f5..a6847e3 100644 (file)
@@ -81,12 +81,12 @@ abstract class ApiFormatBase extends ApiBase {
                        <title>MediaWiki API</title>
                </head>
                <body>
-                       <br/>
 <?php
 
 
                        if (!$isError) {
 ?>
+                       <br/>
                        <small>
                        This result is being shown in <?=$this->mFormat?> format,
                        which might not be suitable for your application.<br/>
index 80c96d6..2eff7f0 100644 (file)
@@ -31,9 +31,6 @@ if (!defined('MEDIAWIKI')) {
 \r
 class ApiHelp extends ApiBase {\r
 \r
-       /**\r
-       * Constructor\r
-       */\r
        public function __construct($main, $action) {\r
                parent :: __construct($main);\r
        }\r
@@ -44,5 +41,9 @@ class ApiHelp extends ApiBase {
        public function Execute() {\r
                $this->DieUsage('', 'help');\r
        }\r
+       \r
+       protected function GetDescription() {\r
+               return array('Display this help screen.');\r
+       }\r
 }\r
 ?>
\ No newline at end of file
index 79b4b74..349751e 100644 (file)
@@ -31,9 +31,6 @@ if (!defined('MEDIAWIKI')) {
 
 class ApiLogin extends ApiBase {
 
-       /**
-       * Constructor
-       */
        public function __construct($main, $action) {
                parent :: __construct($main);
        }
@@ -86,9 +83,6 @@ class ApiLogin extends ApiBase {
                $this->GetResult()->AddMessage('login', null, $result);
        }
 
-       /**
-        * Returns an array of allowed parameters (keys) => default value for that parameter
-        */
        protected function GetAllowedParams() {
                return array (
                        'lgname' => '',
@@ -97,24 +91,16 @@ class ApiLogin extends ApiBase {
                );
        }
 
-       /**
-        * Returns the description string for the given parameter.
-        */
        protected function GetParamDescription() {
                return array (
                        'lgname' => 'User Name',
                        'lgpassword' => 'Password',
-                       'lgdomain' => 'Domain (optional)',
-                       
+                       'lgdomain' => 'Domain (optional)'                       
                );
        }
 
-       /**
-        * Returns the description string for this module
-        */
        protected function GetDescription() {
-               return array("*Login Module*",
-                       "This module is used to login and get the authentication tokens.");
+               return array('This module is used to login and get the authentication tokens.');
        }
 }
 ?>
\ No newline at end of file
index d206017..2a6da70 100644 (file)
@@ -33,11 +33,11 @@ if (!defined('MEDIAWIKI')) {
 * @desc This exception will be thrown when DieUsage is called to stop module execution.\r
 */\r
 class UsageException extends Exception {\r
-    var $codestr;\r
-    \r
+       var $codestr;\r
+\r
        public function __construct($message, $codestr) {\r
                parent :: __construct($message);\r
-        $this->codestr = $codestr;\r
+               $this->codestr = $codestr;\r
        }\r
        public function __toString() {\r
                return "{$this->codestr}: {$this->message}";\r
@@ -119,7 +119,11 @@ class ApiMain extends ApiBase {
        }\r
 \r
        protected function GetDescription() {\r
-               return "This API allows programs to access various functions of MediaWiki software.";\r
+               return array (\r
+                       '',\r
+                       'This API allows programs to access various functions of MediaWiki software.',\r
+                       ''\r
+               );\r
        }\r
 \r
        public function MainDieUsage($description, $errorCode, $httpRespCode = 0) {\r
@@ -139,26 +143,31 @@ class ApiMain extends ApiBase {
         * Override the parent to generate help messages for all available modules.\r
         */\r
        public function MakeHelpMsg() {\r
-               \r
+\r
                // Use parent to make default message for the main module\r
                $msg = parent :: MakeHelpMsg();\r
-               \r
-               $msg .= "\n\n*Modules*\n";\r
+\r
+               $astriks = str_repeat('*** ', 10);\r
+               $msg .= "\n\n$astriks  Modules  $astriks\n\n";\r
                foreach ($this->mModules as $moduleName => $moduleClass) {\r
+                       $msg .= "* action=$moduleName *";\r
                        $module = new $this->mModules[$moduleName] ($this, $moduleName);\r
                        $msg2 = $module->MakeHelpMsg();\r
                        if ($msg2 !== false)\r
-                               $msg .= $msg2 . "\n";\r
+                               $msg .= $msg2;\r
+                       $msg .= "\n";\r
                }\r
 \r
-               $msg .= "\n*Formats*\n";\r
+               $msg .= "\n$astriks  Formats  $astriks\n\n";\r
                foreach ($this->mFormats as $moduleName => $moduleClass) {\r
+                       $msg .= "* format=$moduleName *";\r
                        $module = new $this->mFormats[$moduleName] ($this, $moduleName);\r
                        $msg2 = $module->MakeHelpMsg();\r
                        if ($msg2 !== false)\r
-                               $msg .= $msg2 . "\n";\r
+                               $msg .= $msg2;\r
+                       $msg .= "\n";\r
                }\r
-               \r
+\r
                return $msg;\r
        }\r
 }\r
index b692a98..501ebb0 100644 (file)
@@ -31,22 +31,46 @@ if (!defined('MEDIAWIKI')) {
 \r
 class ApiQuery extends ApiBase {\r
 \r
+       var $mMetaModuleNames, $mPropModuleNames, $mListModuleNames;\r
+\r
+       private $mQueryMetaModules = array (\r
+//             'siteinfo' => 'ApiQuerySiteinfo',\r
+//             'userinfo' => 'ApiQueryUserinfo'\r
+       );\r
        private $mQueryPropModules = array (\r
+//             'info' => 'ApiQueryInfo',\r
+//             'categories' => 'ApiQueryCategories',\r
+//             'imageinfo' => 'ApiQueryImageinfo',\r
+//             'langlinks' => 'ApiQueryLanglinks',\r
+//             'links' => 'ApiQueryLinks',\r
+//             'templates' => 'ApiQueryTemplates',\r
+//             'revisions' => 'ApiQueryRevisions',\r
+\r
+               // Should be removed\r
                'content' => 'ApiQueryContent'\r
        );\r
        private $mQueryListModules = array (\r
-               'backlinks' => 'ApiQueryBacklinks'\r
+//             'allpages' => 'ApiQueryAllpages',\r
+//             'backlinks' => 'ApiQueryBacklinks',\r
+//             'categorymembers' => 'ApiQueryCategorymembers',\r
+//             'embeddedin' => 'ApiQueryEmbeddedin',\r
+//             'imagelinks' => 'ApiQueryImagelinks',\r
+//             'logevents' => 'ApiQueryLogevents',\r
+//             'recentchanges' => 'ApiQueryRecentchanges',\r
+//             'usercontribs' => 'ApiQueryUsercontribs',\r
+//             'users' => 'ApiQueryUsers',\r
+//             'watchlist' => 'ApiQueryWatchlist',\r
        );\r
 \r
        private $mSlaveDB = null;\r
 \r
-       /**\r
-       * Constructor\r
-       */\r
        public function __construct($main, $action) {\r
                parent :: __construct($main);\r
+               $this->mMetaModuleNames = array_keys($this->mQueryMetaModules);\r
                $this->mPropModuleNames = array_keys($this->mQueryPropModules);\r
                $this->mListModuleNames = array_keys($this->mQueryListModules);\r
+               \r
+               $this->mAllowedGenerators = array_merge( $this->mListModuleNames, $this->mPropModuleNames);\r
        }\r
 \r
        public function GetDB() {\r
@@ -56,48 +80,104 @@ class ApiQuery extends ApiBase {
        }\r
 \r
        public function Execute() {\r
+               $meta = $prop = $list = $generator = $titles = $pageids = $revids = null;\r
+               $redirects = null;\r
+               extract($this->ExtractRequestParams());\r
+\r
+               //\r
+               // Only one of the titles/pageids/revids is allowed at the same time\r
+               //\r
+               $dataSource = null;\r
+               if (isset($titles))\r
+                       $dataSource = 'titles';\r
+               if (isset($pageids)) {\r
+                       if (isset($dataSource))\r
+                               $this->DieUsage("Cannot use 'pageids' at the same time as '$dataSource'", 'multisource');\r
+                       $dataSource = 'pageids';\r
+               }\r
+               if (isset($revids)) {\r
+                       if (isset($dataSource))\r
+                               $this->DieUsage("Cannot use 'revids' at the same time as '$dataSource'", 'multisource');\r
+                       $dataSource = 'revids';\r
+               }\r
+               \r
+               //\r
+               // Normalize titles\r
+               //\r
+               if ($dataSource === 'titles') {\r
+                       $linkBatch = new LinkBatch;\r
+                       foreach ( $titles as &$titleString ) {\r
+                               $titleObj = &Title::newFromText( $titleString );\r
+\r
+                               // Validation\r
+                               if (!$titleObj)\r
+                                       $this->dieUsage( "bad title $titleString", 'pi_invalidtitle' );\r
+                               if ($titleObj->getNamespace() < 0)\r
+                                       $this->dieUsage( "No support for special page $titleString has been implemented", 'pi_unsupportednamespace' );\r
+                               if (!$titleObj->userCanRead())\r
+                                       $this->dieUsage( "No read permission for $titleString", 'pi_titleaccessdenied' );\r
+\r
+                $linkBatch->addObj( $titleObj );\r
 \r
+                               // Make sure we remember the original title that was given to us\r
+                               // This way the caller can correlate new titles with the originally requested, i.e. namespace is localized or capitalization\r
+                               if( $titleString !== $titleObj->getPrefixedText() ) {\r
+                                       $this->GetResult()->AddMessage('query', 'normalized', array($titleString => $titleObj->getPrefixedText()));\r
+                               }\r
+                       }\r
+               }\r
        }\r
 \r
-       /**\r
-        * Returns an array of allowed parameters (keys) => default value for that parameter\r
-        */\r
        protected function GetAllowedParams() {\r
                return array (\r
+                       'meta' => array (\r
+                               GN_ENUM_ISMULTI => true,\r
+                               GN_ENUM_CHOICES => $this->mMetaModuleNames\r
+                       ),\r
+                       'prop' => array (\r
+                               GN_ENUM_ISMULTI => true,\r
+                               GN_ENUM_CHOICES => $this->mPropModuleNames\r
+                       ),\r
+                       'list' => array (\r
+                               GN_ENUM_ISMULTI => true,\r
+                               GN_ENUM_CHOICES => $this->mListModuleNames\r
+                       ),\r
+                       'generator' => array (\r
+                               GN_ENUM_CHOICES => $this->mAllowedGenerators\r
+                       ),\r
                        'titles' => array (\r
-                               GN_ENUM_DFLT => null,\r
                                GN_ENUM_ISMULTI => true\r
                        ),\r
                        'pageids' => array (\r
-                               GN_ENUM_DFLT => 0,\r
+                               GN_ENUM_TYPE => 'integer',\r
                                GN_ENUM_ISMULTI => true\r
                        ),\r
                        'revids' => array (\r
-                               GN_ENUM_DFLT => 0,\r
+                               GN_ENUM_TYPE => 'integer',\r
                                GN_ENUM_ISMULTI => true\r
-                       ),\r
-                       'prop' => array (\r
-                               GN_ENUM_DFLT => null,\r
-                               GN_ENUM_ISMULTI => true,\r
-                               GN_ENUM_CHOICES => array_keys($this->mPropModuleNames\r
                        )\r
-               ), 'list' => array (\r
-                       GN_ENUM_DFLT => null,\r
-                       GN_ENUM_ISMULTI => true,\r
-                       GN_ENUM_CHOICES => array_keys($this->mListModuleNames\r
-               )));\r
+               );\r
+       }\r
+\r
+       protected function GetParamDescription() {\r
+               return array (\r
+                       'meta' => 'Which meta data to get about the site',\r
+                       'prop' => 'Which properties to get for the titles/revisions/pageids',\r
+                       'list' => 'Which lists to get',\r
+                       'generator' => 'Use the output of a list as the input for other prop/list/meta items',\r
+                       'titles' => 'A list of titles to work on',\r
+                       'pageids' => 'A list of page IDs to work on',\r
+                       'revids' => 'A list of revision IDs to work on'\r
+               );\r
        }\r
 \r
-       /**\r
-        * Returns the description string for this module\r
-        */\r
        protected function GetDescription() {\r
-               return 'Query Module';\r
+               return array(\r
+                               'Query API module allows applications to get needed pieces of data from the MediaWiki databases,',\r
+                               'and is loosely based on the Query API interface currently available on all MediaWiki servers.',\r
+                               'All data modifications will first have to use query to acquire a token to prevent abuse from malicious sites.');\r
        }\r
 \r
-       /**\r
-        * Returns usage examples for this module. Return null if no examples are available.\r
-        */\r
        protected function GetExamples() {\r
                return array (\r
                        'api.php ? action=query & what=content & titles=ArticleA|ArticleB'\r