API: Add more parameter types and improve info
authorBrad Jorsch <bjorsch@wikimedia.org>
Thu, 7 May 2015 16:39:55 +0000 (12:39 -0400)
committerUmherirrender <umherirrender_de.wp@web.de>
Fri, 29 May 2015 19:26:44 +0000 (19:26 +0000)
New types 'text' and 'password' for where a <textarea> or
<input type="password"> would be preferred over <input type="text">.

Some timestamp parameters get actually tagged as 'timestamp'.

'submodule' types change the 'submodules' output property from a boolean
to an object indicating the mapping from values to module paths. And
they get an indication of the submodule parameter prefix (e.g.
generator's "g"), if applicable. "generator" actually gets reported as a
submodule type, using this new mechanism.

action=paraminfo will now indicate ApiBase::PARAM_RANGE_ENFORCE status,
and return better-formatted defaults for timestamps and booleans.

Change-Id: Ic862d6f8fe13f7eb6b4298683514d33af5823e47

14 files changed:
includes/api/ApiBase.php
includes/api/ApiCreateAccount.php
includes/api/ApiEditPage.php
includes/api/ApiEmailUser.php
includes/api/ApiExpandTemplates.php
includes/api/ApiHelp.php
includes/api/ApiLogin.php
includes/api/ApiPageSet.php
includes/api/ApiParamInfo.php
includes/api/ApiParse.php
includes/api/ApiStashEdit.php
includes/api/ApiUpload.php
includes/api/i18n/en.json
includes/api/i18n/qqq.json

index 4870167..55f9677 100644 (file)
@@ -85,6 +85,15 @@ abstract class ApiBase extends ContextSource {
        // $msg for ApiBase::makeMessage(). Any value not having a mapping will use
        // apihelp-{$path}-paramvalue-{$param}-{$value} is used.
        const PARAM_HELP_MSG_PER_VALUE = 14;
+       /// @since 1.26
+       // When PARAM_TYPE is 'submodule', map parameter values to submodule paths.
+       // Default is to use all modules in $this->getModuleManager() in the group
+       // matching the parameter name.
+       const PARAM_SUBMODULE_MAP = 15;
+       /// @since 1.26
+       // When PARAM_TYPE is 'submodule', used to indicate the 'g' prefix added by
+       // ApiQueryGeneratorBase (and similar if anything else ever does that).
+       const PARAM_SUBMODULE_PARAM_PREFIX = 16;
 
        const LIMIT_BIG1 = 500; // Fast query, std user limit
        const LIMIT_BIG2 = 5000; // Fast query, bot/sysop limit
@@ -838,7 +847,11 @@ abstract class ApiBase extends ContextSource {
                                $type = MWNamespace::getValidNamespaces();
                        }
                        if ( isset( $value ) && $type == 'submodule' ) {
-                               $type = $this->getModuleManager()->getNames( $paramName );
+                               if ( isset( $paramSettings[self::PARAM_SUBMODULE_MAP] ) ) {
+                                       $type = array_keys( $paramSettings[self::PARAM_SUBMODULE_MAP] );
+                               } else {
+                                       $type = $this->getModuleManager()->getNames( $paramName );
+                               }
                        }
                }
 
@@ -859,6 +872,8 @@ abstract class ApiBase extends ContextSource {
                                        case 'NULL': // nothing to do
                                                break;
                                        case 'string':
+                                       case 'text':
+                                       case 'password':
                                                if ( $required && $value === '' ) {
                                                        $this->dieUsageMsg( array( 'missingparam', $paramName ) );
                                                }
@@ -1078,6 +1093,24 @@ abstract class ApiBase extends ContextSource {
         * @return string Validated and normalized parameter
         */
        protected function validateTimestamp( $value, $encParamName ) {
+               // Confusing synonyms for the current time accepted by wfTimestamp()
+               // (wfTimestamp() also accepts various non-strings and the string of 14
+               // ASCII NUL bytes, but those can't get here)
+               if ( !$value ) {
+                       $this->logFeatureUsage( 'unclear-"now"-timestamp' );
+                       $this->setWarning(
+                               "Passing '$value' for timestamp parameter $encParamName has been deprecated." .
+                                       ' If for some reason you need to explicitly specify the current time without' .
+                                       ' calculating it client-side, use "now".'
+                       );
+                       return wfTimestamp( TS_MW );
+               }
+
+               // Explicit synonym for the current time
+               if ( $value === 'now' ) {
+                       return wfTimestamp( TS_MW );
+               }
+
                $unixTimestamp = wfTimestamp( TS_UNIX, $value );
                if ( $unixTimestamp === false ) {
                        $this->dieUsage(
@@ -2672,7 +2705,11 @@ abstract class ApiBase extends ContextSource {
                                        }
 
                                        if ( $type === 'submodule' ) {
-                                               $type = $this->getModuleManager()->getNames( $paramName );
+                                               if ( isset( $paramSettings[self::PARAM_SUBMODULE_MAP] ) ) {
+                                                       $type = array_keys( $paramSettings[self::PARAM_SUBMODULE_MAP] );
+                                               } else {
+                                                       $type = $this->getModuleManager()->getNames( $paramName );
+                                               }
                                                sort( $type );
                                        }
                                        if ( is_array( $type ) ) {
index 455540b..57f96c6 100644 (file)
@@ -186,7 +186,9 @@ class ApiCreateAccount extends ApiBase {
                                ApiBase::PARAM_TYPE => 'user',
                                ApiBase::PARAM_REQUIRED => true
                        ),
-                       'password' => null,
+                       'password' => array(
+                               ApiBase::PARAM_TYPE => 'password',
+                       ),
                        'domain' => null,
                        'token' => null,
                        'email' => array(
index 6ab8483..aad71b9 100644 (file)
@@ -281,16 +281,16 @@ class ApiEditPage extends ApiBase {
                        $requestArray['wpUndidRevision'] = $params['undo'];
                }
 
-               // Watch out for basetimestamp == ''
-               // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict
-               if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) {
-                       $requestArray['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] );
+               // Watch out for basetimestamp == '' or '0'
+               // It gets treated as NOW, almost certainly causing an edit conflict
+               if ( $params['basetimestamp'] !== null && (bool)$this->getMain()->getVal( 'basetimestamp' ) ) {
+                       $requestArray['wpEdittime'] = $params['basetimestamp'];
                } else {
                        $requestArray['wpEdittime'] = $pageObj->getTimestamp();
                }
 
-               if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) {
-                       $requestArray['wpStarttime'] = wfTimestamp( TS_MW, $params['starttimestamp'] );
+               if ( $params['starttimestamp'] !== null ) {
+                       $requestArray['wpStarttime'] = $params['starttimestamp'];
                } else {
                        $requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime
                }
@@ -543,7 +543,9 @@ class ApiEditPage extends ApiBase {
                        'sectiontitle' => array(
                                ApiBase::PARAM_TYPE => 'string',
                        ),
-                       'text' => null,
+                       'text' => array(
+                               ApiBase::PARAM_TYPE => 'text',
+                       ),
                        'summary' => null,
                        'tags' => array(
                                ApiBase::PARAM_TYPE => ChangeTags::listExplicitlyDefinedTags(),
@@ -552,8 +554,12 @@ class ApiEditPage extends ApiBase {
                        'minor' => false,
                        'notminor' => false,
                        'bot' => false,
-                       'basetimestamp' => null,
-                       'starttimestamp' => null,
+                       'basetimestamp' => array(
+                               ApiBase::PARAM_TYPE => 'timestamp',
+                       ),
+                       'starttimestamp' => array(
+                               ApiBase::PARAM_TYPE => 'timestamp',
+                       ),
                        'recreate' => false,
                        'createonly' => false,
                        'nocreate' => false,
@@ -575,8 +581,12 @@ class ApiEditPage extends ApiBase {
                                ),
                        ),
                        'md5' => null,
-                       'prependtext' => null,
-                       'appendtext' => null,
+                       'prependtext' => array(
+                               ApiBase::PARAM_TYPE => 'text',
+                       ),
+                       'appendtext' => array(
+                               ApiBase::PARAM_TYPE => 'text',
+                       ),
                        'undo' => array(
                                ApiBase::PARAM_TYPE => 'integer'
                        ),
index 15eb475..efb9769 100644 (file)
@@ -95,7 +95,7 @@ class ApiEmailUser extends ApiBase {
                        ),
                        'subject' => null,
                        'text' => array(
-                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_TYPE => 'text',
                                ApiBase::PARAM_REQUIRED => true
                        ),
                        'ccme' => false,
index 6d064eb..be1a695 100644 (file)
@@ -154,7 +154,7 @@ class ApiExpandTemplates extends ApiBase {
                                ApiBase::PARAM_DFLT => 'API',
                        ),
                        'text' => array(
-                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_TYPE => 'text',
                                ApiBase::PARAM_REQUIRED => true,
                        ),
                        'revid' => array(
index 27fc378..a81ae3f 100644 (file)
@@ -490,14 +490,23 @@ class ApiHelp extends ApiBase {
                                                        switch ( $type ) {
                                                                case 'submodule':
                                                                        $groups[] = $name;
-                                                                       $submodules = $module->getModuleManager()->getNames( $name );
+                                                                       if ( isset( $settings[ApiBase::PARAM_SUBMODULE_MAP] ) ) {
+                                                                               $map = $settings[ApiBase::PARAM_SUBMODULE_MAP];
+                                                                               ksort( $map );
+                                                                               $submodules = array();
+                                                                               foreach ( $map as $v => $m ) {
+                                                                                       $submodules[] = "[[Special:ApiHelp/{$m}|{$v}]]";
+                                                                               }
+                                                                       } else {
+                                                                               $submodules = $module->getModuleManager()->getNames( $name );
+                                                                               sort( $submodules );
+                                                                               $prefix = $module->isMain()
+                                                                                       ? '' : ( $module->getModulePath() . '+' );
+                                                                               $submodules = array_map( function ( $name ) use ( $prefix ) {
+                                                                                       return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]";
+                                                                               }, $submodules );
+                                                                       }
                                                                        $count = count( $submodules );
-                                                                       sort( $submodules );
-                                                                       $prefix = $module->isMain()
-                                                                               ? '' : ( $module->getModulePath() . '+' );
-                                                                       $submodules = array_map( function ( $name ) use ( $prefix ) {
-                                                                               return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]";
-                                                                       }, $submodules );
                                                                        $info[] = $context->msg( 'api-help-param-list' )
                                                                                ->params( $multi ? 2 : 1 )
                                                                                ->params( $context->getLanguage()->commaList( $submodules ) )
@@ -564,6 +573,7 @@ class ApiHelp extends ApiBase {
                                                                        break;
 
                                                                case 'string':
+                                                               case 'text':
                                                                        // Displaying a type message here would be useless.
                                                                        $type = null;
                                                                        break;
@@ -573,6 +583,7 @@ class ApiHelp extends ApiBase {
                                                // Add type. Messages for grep: api-help-param-type-limit
                                                // api-help-param-type-integer api-help-param-type-boolean
                                                // api-help-param-type-timestamp api-help-param-type-user
+                                               // api-help-param-type-password
                                                if ( is_string( $type ) ) {
                                                        $msg = $context->msg( "api-help-param-type-$type" );
                                                        if ( !$msg->isDisabled() ) {
index 5480d94..d8b390c 100644 (file)
@@ -179,7 +179,9 @@ class ApiLogin extends ApiBase {
        public function getAllowedParams() {
                return array(
                        'name' => null,
-                       'password' => null,
+                       'password' => array(
+                               ApiBase::PARAM_TYPE => 'password',
+                       ),
                        'domain' => null,
                        'token' => null,
                );
index 5efe788..d67b184 100644 (file)
@@ -1304,8 +1304,8 @@ class ApiPageSet extends ApiBase {
                        ),
                        'generator' => array(
                                ApiBase::PARAM_TYPE => null,
-                               ApiBase::PARAM_VALUE_LINKS => array(),
                                ApiBase::PARAM_HELP_MSG => 'api-pageset-param-generator',
+                               ApiBase::PARAM_SUBMODULE_PARAM_PREFIX => 'g',
                        ),
                        'redirects' => array(
                                ApiBase::PARAM_DFLT => false,
@@ -1331,10 +1331,8 @@ class ApiPageSet extends ApiBase {
                if ( !$this->mAllowGenerator ) {
                        unset( $result['generator'] );
                } elseif ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
-                       foreach ( $this->getGenerators() as $g ) {
-                               $result['generator'][ApiBase::PARAM_TYPE][] = $g;
-                               $result['generator'][ApiBase::PARAM_VALUE_LINKS][$g] = "Special:ApiHelp/query+$g";
-                       }
+                       $result['generator'][ApiBase::PARAM_TYPE] = 'submodule';
+                       $result['generator'][ApiBase::PARAM_SUBMODULE_MAP] = $this->getGenerators();
                }
 
                return $result;
@@ -1355,13 +1353,14 @@ class ApiPageSet extends ApiBase {
                                $query = $this->getMain()->getModuleManager()->getModule( 'query' );
                        }
                        $gens = array();
+                       $prefix = $query->getModulePath() . '+';
                        $mgr = $query->getModuleManager();
                        foreach ( $mgr->getNamesWithClasses() as $name => $class ) {
                                if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
-                                       $gens[] = $name;
+                                       $gens[$name] = $prefix . $name;
                                }
                        }
-                       sort( $gens );
+                       ksort( $gens );
                        self::$generators = $gens;
                }
 
index 25069d9..8a4ef49 100644 (file)
@@ -291,14 +291,20 @@ class ApiParamInfo extends ApiBase {
                        if ( isset( $settings[ApiBase::PARAM_DFLT] ) ) {
                                switch ( $settings[ApiBase::PARAM_TYPE] ) {
                                        case 'boolean':
-                                               $item['default'] = ( $settings[ApiBase::PARAM_DFLT] ? 'true' : 'false' );
+                                               $item['default'] = (bool)$settings[ApiBase::PARAM_DFLT];
                                                break;
                                        case 'string':
+                                       case 'text':
+                                       case 'password':
                                                $item['default'] = strval( $settings[ApiBase::PARAM_DFLT] );
                                                break;
                                        case 'integer':
+                                       case 'limit':
                                                $item['default'] = intval( $settings[ApiBase::PARAM_DFLT] );
                                                break;
+                                       case 'timestamp':
+                                               $item['default'] = wfTimestamp( TS_ISO_8601, $settings[ApiBase::PARAM_DFLT] );
+                                               break;
                                        default:
                                                $item['default'] = $settings[ApiBase::PARAM_DFLT];
                                                break;
@@ -320,9 +326,23 @@ class ApiParamInfo extends ApiBase {
 
                        if ( isset( $settings[ApiBase::PARAM_TYPE] ) ) {
                                if ( $settings[ApiBase::PARAM_TYPE] === 'submodule' ) {
-                                       $item['type'] = $module->getModuleManager()->getNames( $name );
-                                       sort( $item['type'] );
-                                       $item['submodules'] = true;
+                                       if ( isset( $settings[ApiBase::PARAM_SUBMODULE_MAP] ) ) {
+                                               ksort( $settings[ApiBase::PARAM_SUBMODULE_MAP] );
+                                               $item['type'] = array_keys( $settings[ApiBase::PARAM_SUBMODULE_MAP] );
+                                               $item['submodules'] = $settings[ApiBase::PARAM_SUBMODULE_MAP];
+                                       } else {
+                                               $item['type'] = $module->getModuleManager()->getNames( $name );
+                                               sort( $item['type'] );
+                                               $prefix = $module->isMain()
+                                                       ? '' : ( $module->getModulePath() . '+' );
+                                               $item['submodules'] = array();
+                                               foreach ( $item['type'] as $v ) {
+                                                       $item['submodules'][$v] = $prefix.$v;
+                                               }
+                                       }
+                                       if ( isset( $settings[ApiBase::PARAM_SUBMODULE_PARAM_PREFIX] ) ) {
+                                               $item['submoduleparamprefix'] = $settings[ApiBase::PARAM_SUBMODULE_PARAM_PREFIX];
+                                       }
                                } else {
                                        $item['type'] = $settings[ApiBase::PARAM_TYPE];
                                }
@@ -341,6 +361,9 @@ class ApiParamInfo extends ApiBase {
                        if ( isset( $settings[ApiBase::PARAM_MIN] ) ) {
                                $item['min'] = $settings[ApiBase::PARAM_MIN];
                        }
+                       if ( !empty( $settings[ApiBase::PARAM_RANGE_ENFORCE] ) ) {
+                               $item['enforcerange'] = true;
+                       }
 
                        if ( !empty( $settings[ApiBase::PARAM_HELP_MSG_INFO] ) ) {
                                $item['info'] = array();
index cc8ca97..36be777 100644 (file)
@@ -739,7 +739,9 @@ class ApiParse extends ApiBase {
        public function getAllowedParams() {
                return array(
                        'title' => null,
-                       'text' => null,
+                       'text' => array(
+                               ApiBase::PARAM_TYPE => 'text',
+                       ),
                        'summary' => null,
                        'page' => null,
                        'pageid' => array(
index c4b717c..1b27f60 100644 (file)
@@ -380,7 +380,7 @@ class ApiStashEdit extends ApiBase {
                                ApiBase::PARAM_TYPE => 'string'
                        ),
                        'text' => array(
-                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_TYPE => 'text',
                                ApiBase::PARAM_REQUIRED => true
                        ),
                        'contentmodel' => array(
index 74ae05a..54294c9 100644 (file)
@@ -735,7 +735,9 @@ class ApiUpload extends ApiBase {
                        'comment' => array(
                                ApiBase::PARAM_DFLT => ''
                        ),
-                       'text' => null,
+                       'text' => array(
+                               ApiBase::PARAM_TYPE => 'text',
+                       ),
                        'watch' => array(
                                ApiBase::PARAM_DFLT => false,
                                ApiBase::PARAM_DEPRECATED => true,
index 9411207..d905dea 100644 (file)
        "api-help-param-deprecated": "Deprecated.",
        "api-help-param-required": "This parameter is required.",
        "api-help-datatypes-header": "Data types",
-       "api-help-datatypes": "Some parameter types in API requests need further explanation:\n;boolean\n:Boolean parameters work like HTML checkboxes: if the parameter is specified, regardless of value, it is considered true. For a false value, omit the parameter entirely.\n;timestamp\n:Timestamps may be specified in several formats. ISO 8601 date and time is recommended. All times are in UTC, any included timezone is ignored.\n:* ISO 8601 date and time, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (punctuation and <kbd>Z</kbd> are optional)\n:* ISO 8601 date and time with (ignored) fractional seconds, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (dashes, colons, and <kbd>Z</kbd> are optional)\n:* MediaWiki format, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Generic numeric format, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (optional timezone of <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, or <kbd>-<var>##</var></kbd> is ignored)\n:* EXIF format, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:*RFC 2822 format (timezone may be omitted), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 850 format (timezone may be omitted), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* C ctime format, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* Seconds since 1970-01-01T00:00:00Z as a 1 to 13 digit integer",
+       "api-help-datatypes": "Some parameter types in API requests need further explanation:\n;boolean\n:Boolean parameters work like HTML checkboxes: if the parameter is specified, regardless of value, it is considered true. For a false value, omit the parameter entirely.\n;timestamp\n:Timestamps may be specified in several formats. ISO 8601 date and time is recommended. All times are in UTC, any included timezone is ignored.\n:* ISO 8601 date and time, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (punctuation and <kbd>Z</kbd> are optional)\n:* ISO 8601 date and time with (ignored) fractional seconds, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (dashes, colons, and <kbd>Z</kbd> are optional)\n:* MediaWiki format, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Generic numeric format, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (optional timezone of <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, or <kbd>-<var>##</var></kbd> is ignored)\n:* EXIF format, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:*RFC 2822 format (timezone may be omitted), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 850 format (timezone may be omitted), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* C ctime format, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* Seconds since 1970-01-01T00:00:00Z as a 1 to 13 digit integer (excluding <kbd>0</kbd>)\n:* The string <kbd>now</kbd>",
        "api-help-param-type-limit": "Type: integer or <kbd>max</kbd>",
        "api-help-param-type-integer": "Type: {{PLURAL:$1|1=integer|2=list of integers}}",
        "api-help-param-type-boolean": "Type: boolean ([[Special:ApiHelp/main#main/datatypes|details]])",
+       "api-help-param-type-password": "",
        "api-help-param-type-timestamp": "Type: {{PLURAL:$1|1=timestamp|2=list of timestamps}} ([[Special:ApiHelp/main#main/datatypes|allowed formats]])",
        "api-help-param-type-user": "Type: {{PLURAL:$1|1=user name|2=list of user names}}",
        "api-help-param-list": "{{PLURAL:$1|1=One value|2=Values (separate with <kbd>{{!}}</kbd>)}}: $2",
index 82b169e..c6ac8fd 100644 (file)
        "api-help-param-type-limit": "{{technical}} {{doc-important|Do not translate text inside &lt;kbd%gt; tags}} Used to indicate that a parameter is a \"limit\" type. Parameters:\n* $1 - Always 1.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
        "api-help-param-type-integer": "{{technical}} Used to indicate that a parameter is an integer or list of integers. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
        "api-help-param-type-boolean": "{{technical}} {{doc-important|Do not translate <code>Special:ApiHelp</code> in this message.}} Used to indicate that a parameter is a boolean. Parameters:\n* $1 - Always 1.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
+       "api-help-param-type-password": "{{optional}}{{technical}} Used to indicate that a parameter is a password or list of passwords. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
        "api-help-param-type-timestamp": "{{technical}} {{doc-important|Do not translate <code>Special:ApiHelp</code> in this message.}} Used to indicate that a parameter is a timestamp or list of timestamps. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
        "api-help-param-type-user": "{{technical}} Used to indicate that a parameter is a username or list of usernames. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
        "api-help-param-list": "Used to display the possible values for a parameter taking a list of values\n\nParameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes any number of values\n* $2 - Comma-separated list of values, possibly formatted using {{msg-mw|api-help-param-list-can-be-empty}}\n{{Identical|Value}}",