summaryrefslogtreecommitdiff
path: root/includes/api
diff options
context:
space:
mode:
Diffstat (limited to 'includes/api')
-rw-r--r--includes/api/ApiBase.php276
-rw-r--r--includes/api/ApiBlock.php85
-rw-r--r--includes/api/ApiComparePages.php130
-rw-r--r--includes/api/ApiDelete.php42
-rw-r--r--includes/api/ApiDisabled.php6
-rw-r--r--includes/api/ApiEditPage.php105
-rw-r--r--includes/api/ApiEmailUser.php8
-rw-r--r--includes/api/ApiExpandTemplates.php21
-rw-r--r--includes/api/ApiFeedContributions.php207
-rw-r--r--includes/api/ApiFeedWatchlist.php41
-rw-r--r--includes/api/ApiFileRevert.php189
-rw-r--r--includes/api/ApiFormatBase.php22
-rw-r--r--includes/api/ApiFormatDbg.php6
-rw-r--r--includes/api/ApiFormatDump.php4
-rw-r--r--includes/api/ApiFormatJson.php4
-rw-r--r--includes/api/ApiFormatPhp.php4
-rw-r--r--includes/api/ApiFormatRaw.php8
-rw-r--r--includes/api/ApiFormatTxt.php6
-rw-r--r--includes/api/ApiFormatWddx.php4
-rw-r--r--includes/api/ApiFormatXml.php24
-rw-r--r--includes/api/ApiFormatYaml.php14
-rw-r--r--includes/api/ApiHelp.php17
-rw-r--r--includes/api/ApiImport.php38
-rw-r--r--includes/api/ApiLogin.php25
-rw-r--r--includes/api/ApiLogout.php10
-rw-r--r--includes/api/ApiMain.php256
-rw-r--r--includes/api/ApiMove.php49
-rw-r--r--includes/api/ApiOpenSearch.php12
-rw-r--r--includes/api/ApiPageSet.php127
-rw-r--r--includes/api/ApiParamInfo.php83
-rw-r--r--includes/api/ApiParse.php209
-rw-r--r--includes/api/ApiPatrol.php10
-rw-r--r--includes/api/ApiProtect.php24
-rw-r--r--includes/api/ApiPurge.php47
-rw-r--r--includes/api/ApiQuery.php74
-rw-r--r--includes/api/ApiQueryAllCategories.php28
-rw-r--r--includes/api/ApiQueryAllLinks.php31
-rw-r--r--includes/api/ApiQueryAllUsers.php189
-rw-r--r--includes/api/ApiQueryAllimages.php68
-rw-r--r--includes/api/ApiQueryAllmessages.php135
-rw-r--r--includes/api/ApiQueryAllpages.php74
-rw-r--r--includes/api/ApiQueryBacklinks.php80
-rw-r--r--includes/api/ApiQueryBase.php104
-rw-r--r--includes/api/ApiQueryBlocks.php86
-rw-r--r--includes/api/ApiQueryCategories.php14
-rw-r--r--includes/api/ApiQueryCategoryInfo.php8
-rw-r--r--includes/api/ApiQueryCategoryMembers.php88
-rw-r--r--includes/api/ApiQueryDeletedrevs.php117
-rw-r--r--includes/api/ApiQueryDisabled.php6
-rw-r--r--includes/api/ApiQueryDuplicateFiles.php14
-rw-r--r--includes/api/ApiQueryExtLinksUsage.php109
-rw-r--r--includes/api/ApiQueryExternalLinks.php52
-rw-r--r--includes/api/ApiQueryFilearchive.php113
-rw-r--r--includes/api/ApiQueryIWBacklinks.php13
-rw-r--r--includes/api/ApiQueryIWLinks.php33
-rw-r--r--includes/api/ApiQueryImageInfo.php227
-rw-r--r--includes/api/ApiQueryImages.php28
-rw-r--r--includes/api/ApiQueryInfo.php50
-rw-r--r--includes/api/ApiQueryLangBacklinks.php220
-rw-r--r--includes/api/ApiQueryLangLinks.php39
-rw-r--r--includes/api/ApiQueryLinks.php18
-rw-r--r--includes/api/ApiQueryLogEvents.php82
-rw-r--r--includes/api/ApiQueryPageProps.php62
-rw-r--r--includes/api/ApiQueryProtectedTitles.php32
-rw-r--r--includes/api/ApiQueryQueryPage.php198
-rw-r--r--includes/api/ApiQueryRandom.php22
-rw-r--r--includes/api/ApiQueryRecentChanges.php132
-rw-r--r--includes/api/ApiQueryRevisions.php57
-rw-r--r--includes/api/ApiQuerySearch.php38
-rw-r--r--includes/api/ApiQuerySiteinfo.php140
-rw-r--r--includes/api/ApiQueryStashImageInfo.php93
-rw-r--r--includes/api/ApiQueryTags.php20
-rw-r--r--includes/api/ApiQueryUserContributions.php30
-rw-r--r--includes/api/ApiQueryUserInfo.php41
-rw-r--r--includes/api/ApiQueryUsers.php97
-rw-r--r--includes/api/ApiQueryWatchlist.php94
-rw-r--r--includes/api/ApiQueryWatchlistRaw.php14
-rw-r--r--includes/api/ApiResult.php35
-rw-r--r--includes/api/ApiRollback.php24
-rw-r--r--includes/api/ApiRsd.php15
-rw-r--r--includes/api/ApiUnblock.php46
-rw-r--r--includes/api/ApiUndelete.php19
-rw-r--r--includes/api/ApiUpload.php291
-rw-r--r--includes/api/ApiUserrights.php17
-rw-r--r--includes/api/ApiWatch.php33
85 files changed, 4222 insertions, 1541 deletions
diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php
index 175fa6a1..30e42934 100644
--- a/includes/api/ApiBase.php
+++ b/includes/api/ApiBase.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 5, 2006
*
@@ -30,7 +30,7 @@
* The class functions are divided into several areas of functionality:
*
* Module parameters: Derived classes can define getAllowedParams() to specify
- * which parameters to expect,h ow to parse and validate them.
+ * which parameters to expect, how to parse and validate them.
*
* Profiling: various methods to allow keeping tabs on various tasks and their
* time costs
@@ -122,6 +122,9 @@ abstract class ApiBase {
/**
* Get the name of the module as shown in the profiler log
+ *
+ * @param $db DatabaseBase
+ *
* @return string
*/
public function getModuleProfileName( $db = false ) {
@@ -171,6 +174,24 @@ abstract class ApiBase {
}
/**
+ * Create a new RequestContext object to use e.g. for calls to other parts
+ * the software.
+ * The object will have the WebRequest and the User object set to the ones
+ * used in this instance.
+ *
+ * @return RequestContext
+ */
+ public function createContext() {
+ global $wgUser;
+
+ $context = new RequestContext;
+ $context->setRequest( $this->getMain()->getRequest() );
+ $context->setUser( $wgUser ); /// @todo FIXME: we should store the User object
+
+ return $context;
+ }
+
+ /**
* Set warning section for this module. Users should monitor this
* section to notice any changes in API. Multiple calls to this
* function will result in the warning messages being separated by
@@ -178,7 +199,8 @@ abstract class ApiBase {
* @param $warning string Warning message
*/
public function setWarning( $warning ) {
- $data = $this->getResult()->getData();
+ $result = $this->getResult();
+ $data = $result->getData();
if ( isset( $data['warnings'][$this->getModuleName()] ) ) {
// Don't add duplicate warnings
$warn_regex = preg_quote( $warning, '/' );
@@ -188,13 +210,13 @@ abstract class ApiBase {
$oldwarning = $data['warnings'][$this->getModuleName()]['*'];
// If there is a warning already, append it to the existing one
$warning = "$oldwarning\n$warning";
- $this->getResult()->unsetValue( 'warnings', $this->getModuleName() );
+ $result->unsetValue( 'warnings', $this->getModuleName() );
}
$msg = array();
ApiResult::setContent( $msg, $warning );
- $this->getResult()->disableSizeCheck();
- $this->getResult()->addValue( 'warnings', $this->getModuleName(), $msg );
- $this->getResult()->enableSizeCheck();
+ $result->disableSizeCheck();
+ $result->addValue( 'warnings', $this->getModuleName(), $msg );
+ $result->enableSizeCheck();
}
/**
@@ -235,8 +257,7 @@ abstract class ApiBase {
$msg .= "\nThis module only accepts POST requests";
}
if ( $this->isReadMode() || $this->isWriteMode() ||
- $this->mustBePosted() )
- {
+ $this->mustBePosted() ) {
$msg .= "\n";
}
@@ -246,20 +267,8 @@ abstract class ApiBase {
$msg .= "Parameters:\n$paramsMsg";
}
- // Examples
- $examples = $this->getExamples();
- if ( $examples !== false ) {
- if ( !is_array( $examples ) ) {
- $examples = array(
- $examples
- );
- }
-
- if ( count( $examples ) > 0 ) {
- $msg .= 'Example' . ( count( $examples ) > 1 ? 's' : '' ) . ":\n ";
- $msg .= implode( $lnPrfx, $examples ) . "\n";
- }
- }
+ $msg .= $this->makeHelpArrayToString( $lnPrfx, "Example", $this->getExamples() );
+ $msg .= $this->makeHelpArrayToString( $lnPrfx, "Help page", $this->getHelpUrls() );
if ( $this->getMain()->getShowVersions() ) {
$versions = $this->getVersion();
@@ -283,9 +292,33 @@ abstract class ApiBase {
}
/**
+ * @param $prefix string Text to split output items
+ * @param $title string What is being output
+ * @param $input string|array
+ * @return string
+ */
+ protected function makeHelpArrayToString( $prefix, $title, $input ) {
+ if ( $input === false ) {
+ return '';
+ }
+ if ( !is_array( $input ) ) {
+ $input = array(
+ $input
+ );
+ }
+
+ if ( count( $input ) > 0 ) {
+ $msg = $title . ( count( $input ) > 1 ? 's' : '' ) . ":\n ";
+ $msg .= implode( $prefix, $input ) . "\n";
+ return $msg;
+ }
+ return '';
+ }
+
+ /**
* Generates the parameter descriptions for this module, to be displayed in the
* module's help.
- * @return string
+ * @return string or false
*/
public function makeHelpMsgParameters() {
$params = $this->getFinalParams();
@@ -293,7 +326,8 @@ abstract class ApiBase {
$paramsDescription = $this->getFinalParamDescription();
$msg = '';
- $paramPrefix = "\n" . str_repeat( ' ', 19 );
+ $paramPrefix = "\n" . str_repeat( ' ', 24 );
+ $descWordwrap = "\n" . str_repeat( ' ', 28 );
foreach ( $params as $paramName => $paramSettings ) {
$desc = isset( $paramsDescription[$paramName] ) ? $paramsDescription[$paramName] : '';
if ( is_array( $desc ) ) {
@@ -336,12 +370,16 @@ abstract class ApiBase {
$choices[] = $t;
}
}
- $desc .= $paramPrefix . $nothingPrompt . $prompt . implode( ', ', $choices );
+ $desc .= $paramPrefix . $nothingPrompt . $prompt;
+ $choicesstring = implode( ', ', $choices );
+ $desc .= wordwrap( $choicesstring, 100, $descWordwrap );
} else {
switch ( $type ) {
case 'namespace':
// Special handling because namespaces are type-limited, yet they are not given
- $desc .= $paramPrefix . $prompt . implode( ', ', MWNamespace::getValidNamespaces() );
+ $desc .= $paramPrefix . $prompt;
+ $desc .= wordwrap( implode( ', ', MWNamespace::getValidNamespaces() ),
+ 100, $descWordwrap );
break;
case 'limit':
$desc .= $paramPrefix . "No more than {$paramSettings[self :: PARAM_MAX]}";
@@ -371,7 +409,7 @@ abstract class ApiBase {
$isArray = is_array( $paramSettings[self::PARAM_TYPE] );
if ( !$isArray
- || $isArray && count( $paramSettings[self::PARAM_TYPE] ) > self::LIMIT_SML1) {
+ || $isArray && count( $paramSettings[self::PARAM_TYPE] ) > self::LIMIT_SML1 ) {
$desc .= $paramPrefix . "Maximum number of values " .
self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)";
}
@@ -386,7 +424,7 @@ abstract class ApiBase {
$desc .= $paramPrefix . "Default: $default";
}
- $msg .= sprintf( " %-14s - %s\n", $this->encodeParamName( $paramName ), $desc );
+ $msg .= sprintf( " %-19s - %s\n", $this->encodeParamName( $paramName ), $desc );
}
return $msg;
@@ -398,9 +436,13 @@ abstract class ApiBase {
/**
* Callback for preg_replace_callback() call in makeHelpMsg().
* Replaces a source file name with a link to ViewVC
+ *
+ * @return string
*/
public function makeHelpMsg_callback( $matches ) {
global $wgAutoloadClasses, $wgAutoloadLocalClasses;
+
+ $file = '';
if ( isset( $wgAutoloadLocalClasses[get_class( $this )] ) ) {
$file = $wgAutoloadLocalClasses[get_class( $this )];
} elseif ( isset( $wgAutoloadClasses[get_class( $this )] ) ) {
@@ -421,7 +463,7 @@ abstract class ApiBase {
// This is necessary to make stuff like ApiMain::getVersion()
// returning the version string for ApiBase work
if ( $path ) {
- return "{$matches[0]}\n http://svn.wikimedia.org/" .
+ return "{$matches[0]}\n https://svn.wikimedia.org/" .
"viewvc/mediawiki/trunk/" . dirname( $path ) .
"/{$matches[2]}";
}
@@ -437,8 +479,8 @@ abstract class ApiBase {
}
/**
- * Returns usage examples for this module. Return null if no examples are available.
- * @return mixed string or array of strings
+ * Returns usage examples for this module. Return false if no examples are available.
+ * @return false|string|array
*/
protected function getExamples() {
return false;
@@ -449,7 +491,7 @@ abstract class ApiBase {
* value) or (parameter name) => (array with PARAM_* constants as keys)
* Don't call this function directly: use getFinalParams() to allow
* hooks to modify parameters as needed.
- * @return array
+ * @return array or false
*/
protected function getAllowedParams() {
return false;
@@ -459,7 +501,7 @@ abstract class ApiBase {
* Returns an array of parameter descriptions.
* Don't call this functon directly: use getFinalParamDescription() to
* allow hooks to modify descriptions as needed.
- * @return array
+ * @return array or false
*/
protected function getParamDescription() {
return false;
@@ -468,7 +510,7 @@ abstract class ApiBase {
/**
* Get final list of parameters, after hooks have had a chance to
* tweak it as needed.
- * @return array
+ * @return array or false
*/
public function getFinalParams() {
$params = $this->getAllowedParams();
@@ -554,6 +596,54 @@ abstract class ApiBase {
}
/**
+ * Generates the possible errors requireOnlyOneParameter() can die with
+ *
+ * @param $params array
+ * @return array
+ */
+ public function getRequireOnlyOneParameterErrorMessages( $params ) {
+ $p = $this->getModulePrefix();
+ $params = implode( ", {$p}", $params );
+
+ return array(
+ array( 'code' => "{$p}missingparam", 'info' => "One of the parameters {$p}{$params} is required" ),
+ array( 'code' => "{$p}invalidparammix", 'info' => "The parameters {$p}{$params} can not be used together" )
+ );
+ }
+
+ /**
+ * Die if more than one of a certain set of parameters is set and not false.
+ *
+ * @param $params array
+ */
+ public function requireMaxOneParameter( $params ) {
+ $required = func_get_args();
+ array_shift( $required );
+
+ $intersection = array_intersect( array_keys( array_filter( $params,
+ array( $this, "parameterNotEmpty" ) ) ), $required );
+
+ if ( count( $intersection ) > 1 ) {
+ $this->dieUsage( 'The parameters ' . implode( ', ', $intersection ) . ' can not be used together', 'invalidparammix' );
+ }
+ }
+
+ /**
+ * Generates the possible error requireMaxOneParameter() can die with
+ *
+ * @param $params array
+ * @return array
+ */
+ public function getRequireMaxOneParameterErrorMessages( $params ) {
+ $p = $this->getModulePrefix();
+ $params = implode( ", {$p}", $params );
+
+ return array(
+ array( 'code' => "{$p}invalidparammix", 'info' => "The parameters {$p}{$params} can not be used together" )
+ );
+ }
+
+ /**
* Callback function used in requireOnlyOneParameter to check whether reequired parameters are set
*
* @param $x object Parameter to check is not null/false
@@ -564,7 +654,7 @@ abstract class ApiBase {
}
/**
- * @deprecated use MWNamespace::getValidNamespaces()
+ * @deprecated since 1.17 use MWNamespace::getValidNamespaces()
*/
public static function getValidNamespaces() {
return MWNamespace::getValidNamespaces();
@@ -576,7 +666,7 @@ abstract class ApiBase {
* @param $titleObj Title the page under consideration
* @param $userOption String The user option to consider when $watchlist=preferences.
* If not set will magically default to either watchdefault or watchcreations
- * @returns Boolean
+ * @return bool
*/
protected function getWatchlistValue ( $watchlist, $titleObj, $userOption = null ) {
@@ -617,17 +707,17 @@ abstract class ApiBase {
* @param $titleObj Title the article's title to change
* @param $userOption String The user option to consider when $watch=preferences
*/
- protected function setWatch ( $watch, $titleObj, $userOption = null ) {
+ protected function setWatch( $watch, $titleObj, $userOption = null ) {
$value = $this->getWatchlistValue( $watch, $titleObj, $userOption );
if ( $value === null ) {
return;
}
- $articleObj = new Article( $titleObj );
+ global $wgUser;
if ( $value ) {
- $articleObj->doWatch();
+ WatchAction::doWatch( $titleObj, $wgUser );
} else {
- $articleObj->doUnwatch();
+ WatchAction::doUnwatch( $titleObj, $wgUser );
}
}
@@ -707,16 +797,18 @@ abstract class ApiBase {
$enforceLimits = isset ( $paramSettings[self::PARAM_RANGE_ENFORCE] )
? $paramSettings[self::PARAM_RANGE_ENFORCE] : false;
- if ( !is_null( $min ) || !is_null( $max ) ) {
- if ( is_array( $value ) ) {
- $value = array_map( 'intval', $value );
- foreach ( $value as &$v ) {
+ if ( is_array( $value ) ) {
+ $value = array_map( 'intval', $value );
+ if ( !is_null( $min ) || !is_null( $max ) ) {
+ foreach ( $value as &$v ) {
$this->validateLimit( $paramName, $v, $min, $max, null, $enforceLimits );
}
- } else {
- $value = intval( $value );
- $this->validateLimit( $paramName, $value, $min, $max, null, $enforceLimits );
- }
+ }
+ } else {
+ $value = intval( $value );
+ if ( !is_null( $min ) || !is_null( $max ) ) {
+ $this->validateLimit( $paramName, $value, $min, $max, null, $enforceLimits );
+ }
}
break;
case 'limit':
@@ -745,14 +837,13 @@ abstract class ApiBase {
}
break;
case 'timestamp':
- if ( $multi ) {
- ApiBase::dieDebug( __METHOD__, "Multi-values not supported for $encParamName" );
- }
- $value = wfTimestamp( TS_UNIX, $value );
- if ( $value === 0 ) {
- $this->dieUsage( "Invalid value '$value' for timestamp parameter $encParamName", "badtimestamp_{$encParamName}" );
+ if ( is_array( $value ) ) {
+ foreach ( $value as $key => $val ) {
+ $value[$key] = $this->validateTimestamp( $val, $encParamName );
+ }
+ } else {
+ $value = $this->validateTimestamp( $value, $encParamName );
}
- $value = wfTimestamp( TS_MW, $value );
break;
case 'user':
if ( !is_array( $value ) ) {
@@ -785,7 +876,7 @@ abstract class ApiBase {
if ( $deprecated && $value !== false ) {
$this->setWarning( "The $encParamName parameter has been deprecated." );
}
- } else if ( $required ) {
+ } elseif ( $required ) {
$this->dieUsageMsg( array( 'missingparam', $paramName ) );
}
@@ -848,8 +939,8 @@ abstract class ApiBase {
* Prints usage info on failure.
* @param $paramName string Parameter name
* @param $value int Parameter value
- * @param $min int Minimum value
- * @param $max int Maximum value for users
+ * @param $min int|null Minimum value
+ * @param $max int|null Maximum value for users
* @param $botMax int Maximum value for sysops/bots
* @param $enforceLimits Boolean Whether to enforce (die) if value is outside limits
*/
@@ -884,6 +975,19 @@ abstract class ApiBase {
}
/**
+ * @param $value string
+ * @param $paramName string
+ * @return string
+ */
+ function validateTimestamp( $value, $paramName ) {
+ $value = wfTimestamp( TS_UNIX, $value );
+ if ( $value === 0 ) {
+ $this->dieUsage( "Invalid value '$value' for timestamp parameter $paramName", "badtimestamp_{$paramName}" );
+ }
+ return wfTimestamp( TS_MW, $value );
+ }
+
+ /**
* Adds a warning to the output, else dies
*
* @param $msg String Message to show as a warning, or error message if dying
@@ -924,7 +1028,7 @@ abstract class ApiBase {
* @param $extradata array Data to add to the <error> element; array in ApiResult format
*/
public function dieUsage( $description, $errorCode, $httpRespCode = 0, $extradata = null ) {
- wfProfileClose();
+ Profiler::instance()->close();
throw new UsageException( $description, $this->encodeParamName( $errorCode ), $httpRespCode, $extradata );
}
@@ -940,7 +1044,8 @@ abstract class ApiBase {
'ns-specialprotected' => array( 'code' => 'unsupportednamespace', 'info' => "Pages in the Special namespace can't be edited" ),
'protectedinterface' => array( 'code' => 'protectednamespace-interface', 'info' => "You're not allowed to edit interface messages" ),
'namespaceprotected' => array( 'code' => 'protectednamespace', 'info' => "You're not allowed to edit pages in the ``\$1'' namespace" ),
- 'customcssjsprotected' => array( 'code' => 'customcssjsprotected', 'info' => "You're not allowed to edit custom CSS and JavaScript pages" ),
+ 'customcssprotected' => array( 'code' => 'customcssprotected', 'info' => "You're not allowed to edit custom CSS pages" ),
+ 'customjsprotected' => array( 'code' => 'customjsprotected', 'info' => "You're not allowed to edit custom JavaScript pages" ),
'cascadeprotected' => array( 'code' => 'cascadeprotected', 'info' => "The page you're trying to edit is protected because it's included in a cascade-protected page" ),
'protectedpagetext' => array( 'code' => 'protectedpage', 'info' => "The ``\$1'' right is required to edit this page" ),
'protect-cantedit' => array( 'code' => 'cantedit', 'info' => "You can't protect this page because you can't edit it" ),
@@ -1041,6 +1146,7 @@ abstract class ApiBase {
'sharedfile-exists' => array( 'code' => 'fileexists-sharedrepo-perm', 'info' => 'The target file exists on a shared repository. Use the ignorewarnings parameter to override it.' ),
'mustbeposted' => array( 'code' => 'mustbeposted', 'info' => "The \$1 module requires a POST request" ),
'show' => array( 'code' => 'show', 'info' => 'Incorrect parameter - mutually exclusive values may not be supplied' ),
+ 'specialpage-cantexecute' => array( 'code' => 'specialpage-cantexecute', 'info' => "You don't have permission to view the results of this special page" ),
// ApiEditPage messages
'noimageredirect-anon' => array( 'code' => 'noimageredirect-anon', 'info' => "Anonymous users can't create image redirects" ),
@@ -1058,12 +1164,22 @@ abstract class ApiBase {
'emptynewsection' => array( 'code' => 'emptynewsection', 'info' => 'Creating empty new sections is not possible.' ),
'revwrongpage' => array( 'code' => 'revwrongpage', 'info' => "r\$1 is not a revision of ``\$2''" ),
'undo-failure' => array( 'code' => 'undofailure', 'info' => 'Undo failed due to conflicting intermediate edits' ),
+
+ // Messages from WikiPage::doEit()
+ 'edit-hook-aborted' => array( 'code' => 'edit-hook-aborted', 'info' => "Your edit was aborted by an ArticleSave hook" ),
+ 'edit-gone-missing' => array( 'code' => 'edit-gone-missing', 'info' => "The page you tried to edit doesn't seem to exist anymore" ),
+ 'edit-conflict' => array( 'code' => 'editconflict', 'info' => "Edit conflict detected" ),
+ 'edit-already-exists' => array( 'code' => 'edit-already-exists', 'info' => "It seems the page you tried to create already exist" ),
// uploadMsgs
'invalid-session-key' => array( 'code' => 'invalid-session-key', 'info' => 'Not a valid session key' ),
'nouploadmodule' => array( 'code' => 'nouploadmodule', 'info' => 'No upload module set' ),
'uploaddisabled' => array( 'code' => 'uploaddisabled', 'info' => 'Uploads are not enabled. Make sure $wgEnableUploads is set to true in LocalSettings.php and the PHP ini setting file_uploads is true' ),
'copyuploaddisabled' => array( 'code' => 'copyuploaddisabled', 'info' => 'Uploads by URL is not enabled. Make sure $wgAllowCopyUploads is set to true in LocalSettings.php.' ),
+
+ 'filename-tooshort' => array( 'code' => 'filename-tooshort', 'info' => 'The filename is too short' ),
+ 'illegal-filename' => array( 'code' => 'illegal-filename', 'info' => 'The filename is not allowed' ),
+ 'filetype-missing' => array( 'code' => 'filetype-missing', 'info' => 'The file is missing an extension' ),
);
/**
@@ -1077,9 +1193,14 @@ abstract class ApiBase {
/**
* Output the error message related to a certain array
- * @param $error array Element of a getUserPermissionsErrors()-style array
+ * @param $error (array|string) Element of a getUserPermissionsErrors()-style array
*/
public function dieUsageMsg( $error ) {
+ # most of the time we send a 1 element, so we might as well send it as
+ # a string and make this an array here.
+ if( is_string( $error ) ) {
+ $error = array( $error );
+ }
$parsed = $this->parseMsg( $error );
$this->dieUsage( $parsed['info'], $parsed['code'] );
}
@@ -1091,6 +1212,14 @@ abstract class ApiBase {
*/
public function parseMsg( $error ) {
$key = array_shift( $error );
+
+ // Check whether the error array was nested
+ // array( array( <code>, <params> ), array( <another_code>, <params> ) )
+ if( is_array( $key ) ){
+ $error = $key;
+ $key = array_shift( $error );
+ }
+
if ( isset( self::$messageMap[$key] ) ) {
return array( 'code' =>
wfMsgReplaceArgs( self::$messageMap[$key]['code'], $error ),
@@ -1098,6 +1227,7 @@ abstract class ApiBase {
wfMsgReplaceArgs( self::$messageMap[$key]['info'], $error )
);
}
+
// If the key isn't present, throw an "unknown error"
return $this->parseMsg( array( 'unknownerror', $key ) );
}
@@ -1144,7 +1274,7 @@ abstract class ApiBase {
/**
* Returns whether this module requires a Token to execute
- * @returns bool
+ * @return bool
*/
public function needsToken() {
return false;
@@ -1152,17 +1282,18 @@ abstract class ApiBase {
/**
* Returns the token salt if there is one, '' if the module doesn't require a salt, else false if the module doesn't need a token
- * @returns bool
+ * @return bool
*/
public function getTokenSalt() {
return false;
}
/**
- * Gets the user for whom to get the watchlist
- *
- * @returns User
- */
+ * Gets the user for whom to get the watchlist
+ *
+ * @param $params array
+ * @return User
+ */
public function getWatchlistUser( $params ) {
global $wgUser;
if ( !is_null( $params['owner'] ) && !is_null( $params['token'] ) ) {
@@ -1184,6 +1315,13 @@ abstract class ApiBase {
}
/**
+ * @return false|string|array Returns a false if the module has no help url, else returns a (array of) string
+ */
+ public function getHelpUrls() {
+ return false;
+ }
+
+ /**
* Returns a list of all possible errors returned by the module
* @return array in the format of array( key, param1, param2, ... ) or array( 'code' => ..., 'info' => ... )
*/
@@ -1363,6 +1501,6 @@ abstract class ApiBase {
* @return string
*/
public static function getBaseVersion() {
- return __CLASS__ . ': $Id: ApiBase.php 82730 2011-02-24 16:03:05Z reedy $';
+ return __CLASS__ . ': $Id: ApiBase.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiBlock.php b/includes/api/ApiBlock.php
index 875b8aeb..8d718ab2 100644
--- a/includes/api/ApiBlock.php
+++ b/includes/api/ApiBlock.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 4, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,9 +37,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
*/
class ApiBlock extends ApiBase {
- /**
- * Std ctor.
- */
public function __construct( $main, $action ) {
parent::__construct( $main, $action );
}
@@ -51,56 +48,71 @@ class ApiBlock extends ApiBase {
* of success. If it fails, the result will specify the nature of the error.
*/
public function execute() {
- global $wgUser, $wgBlockAllowsUTEdit;
+ global $wgUser;
$params = $this->extractRequestParams();
if ( $params['gettoken'] ) {
- $res['blocktoken'] = $wgUser->editToken();
+ $res['blocktoken'] = $wgUser->editToken( '', $this->getMain()->getRequest() );
$this->getResult()->addValue( null, $this->getModuleName(), $res );
return;
}
if ( !$wgUser->isAllowed( 'block' ) ) {
- $this->dieUsageMsg( array( 'cantblock' ) );
+ $this->dieUsageMsg( 'cantblock' );
}
# bug 15810: blocked admins should have limited access here
if ( $wgUser->isBlocked() ) {
- $status = IPBlockForm::checkUnblockSelf( $params['user'] );
+ $status = SpecialBlock::checkUnblockSelf( $params['user'] );
if ( $status !== true ) {
$this->dieUsageMsg( array( $status ) );
}
}
if ( $params['hidename'] && !$wgUser->isAllowed( 'hideuser' ) ) {
- $this->dieUsageMsg( array( 'canthide' ) );
+ $this->dieUsageMsg( 'canthide' );
}
- if ( $params['noemail'] && !IPBlockForm::canBlockEmail( $wgUser ) ) {
- $this->dieUsageMsg( array( 'cantblock-email' ) );
+ if ( $params['noemail'] && !SpecialBlock::canBlockEmail( $wgUser ) ) {
+ $this->dieUsageMsg( 'cantblock-email' );
}
- $form = new IPBlockForm( '' );
- $form->BlockAddress = $params['user'];
- $form->BlockReason = ( is_null( $params['reason'] ) ? '' : $params['reason'] );
- $form->BlockReasonList = 'other';
- $form->BlockExpiry = ( $params['expiry'] == 'never' ? 'infinite' : $params['expiry'] );
- $form->BlockOther = '';
- $form->BlockAnonOnly = $params['anononly'];
- $form->BlockCreateAccount = $params['nocreate'];
- $form->BlockEnableAutoblock = $params['autoblock'];
- $form->BlockEmail = $params['noemail'];
- $form->BlockHideName = $params['hidename'];
- $form->BlockAllowUsertalk = $params['allowusertalk'] && $wgBlockAllowsUTEdit;
- $form->BlockReblock = $params['reblock'];
-
- $userID = $expiry = null;
- $retval = $form->doBlock( $userID, $expiry );
- if ( count( $retval ) ) {
+ $data = array(
+ 'Target' => $params['user'],
+ 'Reason' => array(
+ is_null( $params['reason'] ) ? '' : $params['reason'],
+ 'other',
+ is_null( $params['reason'] ) ? '' : $params['reason']
+ ),
+ 'Expiry' => $params['expiry'] == 'never' ? 'infinite' : $params['expiry'],
+ 'HardBlock' => !$params['anononly'],
+ 'CreateAccount' => $params['nocreate'],
+ 'AutoBlock' => $params['autoblock'],
+ 'DisableEmail' => $params['noemail'],
+ 'HideUser' => $params['hidename'],
+ 'DisableUTEdit' => $params['allowusertalk'],
+ 'AlreadyBlocked' => $params['reblock'],
+ 'Watch' => $params['watchuser'],
+ 'Confirm' => true,
+ );
+
+ $retval = SpecialBlock::processForm( $data );
+ if ( $retval !== true ) {
// We don't care about multiple errors, just report one of them
$this->dieUsageMsg( $retval );
}
+ list( $target, /*...*/ ) = SpecialBlock::getTargetAndType( $params['user'] );
$res['user'] = $params['user'];
- $res['userID'] = intval( $userID );
- $res['expiry'] = ( $expiry == Block::infinity() ? 'infinite' : wfTimestamp( TS_ISO_8601, $expiry ) );
+ $res['userID'] = $target instanceof User ? $target->getId() : 0;
+
+ $block = Block::newFromTarget( $target );
+ if( $block instanceof Block ){
+ $res['expiry'] = $block->mExpiry == wfGetDB( DB_SLAVE )->getInfinity()
+ ? 'infinite'
+ : wfTimestamp( TS_ISO_8601, $block->mExpiry );
+ } else {
+ # should be unreachable
+ $res['expiry'] = '';
+ }
+
$res['reason'] = $params['reason'];
if ( $params['anononly'] ) {
$res['anononly'] = '';
@@ -120,6 +132,9 @@ class ApiBlock extends ApiBase {
if ( $params['allowusertalk'] ) {
$res['allowusertalk'] = '';
}
+ if ( $params['watchuser'] ) {
+ $res['watchuser'] = '';
+ }
$this->getResult()->addValue( null, $this->getModuleName(), $res );
}
@@ -149,6 +164,7 @@ class ApiBlock extends ApiBase {
'hidename' => false,
'allowusertalk' => false,
'reblock' => false,
+ 'watchuser' => false,
);
}
@@ -166,6 +182,7 @@ class ApiBlock extends ApiBase {
'hidename' => 'Hide the username from the block log. (Requires the "hideuser" right.)',
'allowusertalk' => 'Allow the user to edit their own talk page (depends on $wgBlockAllowsUTEdit)',
'reblock' => 'If the user is already blocked, overwrite the existing block',
+ 'watchuser' => 'Watch the user/IP\'s user and talk pages',
);
}
@@ -198,7 +215,11 @@ class ApiBlock extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Block';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiBlock.php 77192 2010-11-23 22:05:27Z btongminh $';
+ return __CLASS__ . ': $Id: ApiBlock.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiComparePages.php b/includes/api/ApiComparePages.php
new file mode 100644
index 00000000..d43fa53f
--- /dev/null
+++ b/includes/api/ApiComparePages.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ *
+ * Created on May 1, 2011
+ *
+ * Copyright © 2011 Sam Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+class ApiComparePages extends ApiBase {
+
+ public function __construct( $main, $action ) {
+ parent::__construct( $main, $action );
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ $rev1 = $this->revisionOrTitle( $params['fromrev'], $params['fromtitle'] );
+ $rev2 = $this->revisionOrTitle( $params['torev'], $params['totitle'] );
+
+ $de = new DifferenceEngine( null,
+ $rev1,
+ $rev2,
+ null, // rcid
+ true,
+ false );
+
+ $vals = array();
+ if ( isset( $params['fromtitle'] ) ) {
+ $vals['fromtitle'] = $params['fromtitle'];
+ }
+ $vals['fromrevid'] = $rev1;
+ if ( isset( $params['totitle'] ) ) {
+ $vals['totitle'] = $params['totitle'];
+ }
+ $vals['torevid'] = $rev2;
+
+ $difftext = $de->getDiffBody();
+
+ if ( $difftext === false ) {
+ $this->dieUsage( 'The diff cannot be retrieved. ' .
+ 'Maybe one or both revisions do not exist or you do not have permission to view them.', 'baddiff' );
+ } else {
+ ApiResult::setContent( $vals, $difftext );
+ }
+
+ $this->getResult()->addValue( null, $this->getModuleName(), $vals );
+ }
+
+ /**
+ * @param $revision int
+ * @param $titleText string
+ * @return int
+ */
+ private function revisionOrTitle( $revision, $titleText ) {
+ if( $revision ){
+ return $revision;
+ } elseif( $titleText ) {
+ $title = Title::newFromText( $titleText );
+ if( !$title ){
+ $this->dieUsageMsg( array( 'invalidtitle', $titleText ) );
+ }
+ return $title->getLatestRevID();
+ }
+ $this->dieUsage( 'inputneeded', 'A title or a revision number is needed for both the from and the to parameters' );
+ }
+
+ public function getAllowedParams() {
+ return array(
+ 'fromtitle' => null,
+ 'fromrev' => array(
+ ApiBase::PARAM_TYPE => 'integer'
+ ),
+ 'totitle' => null,
+ 'torev' => array(
+ ApiBase::PARAM_TYPE => 'integer'
+ ),
+ );
+ }
+
+ public function getParamDescription() {
+ return array(
+ 'fromtitle' => 'First title to compare',
+ 'fromrev' => 'First revision to compare',
+ 'totitle' => 'Second title to compare',
+ 'torev' => 'Second revision to compare',
+ );
+ }
+ public function getDescription() {
+ return array(
+ 'Get the difference between 2 pages',
+ 'You must pass a revision number or a page title for each part (1 and 2)'
+ );
+ }
+
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(), array(
+ array( 'code' => 'inputneeded', 'info' => 'A title or a revision is needed' ),
+ array( 'invalidtitle', 'title' ),
+ array( 'code' => 'baddiff', 'info' => 'The diff cannot be retrieved. Maybe one or both revisions do not exist or you do not have permission to view them.' ),
+ ) );
+ }
+
+ protected function getExamples() {
+ return array(
+ 'api.php?action=compare&fromrev=1&torev=2',
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiComparePages.php 92400 2011-07-17 16:51:11Z reedy $';
+ }
+}
diff --git a/includes/api/ApiDelete.php b/includes/api/ApiDelete.php
index fbf62391..58befbfe 100644
--- a/includes/api/ApiDelete.php
+++ b/includes/api/ApiDelete.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Jun 30, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@ class ApiDelete extends ApiBase {
}
}
if ( !$titleObj->exists() ) {
- $this->dieUsageMsg( array( 'notanarticle' ) );
+ $this->dieUsageMsg( 'notanarticle' );
}
$reason = ( isset( $params['reason'] ) ? $params['reason'] : null );
@@ -146,22 +146,17 @@ class ApiDelete extends ApiBase {
}
$error = '';
- if ( !wfRunHooks( 'ArticleDelete', array( &$article, &$wgUser, &$reason, &$error ) ) ) {
- return array( array( 'hookaborted', $error ) );
- }
-
// Luckily, Article.php provides a reusable delete function that does the hard work for us
- if ( $article->doDeleteArticle( $reason ) ) {
- wfRunHooks( 'ArticleDeleteComplete', array( &$article, &$wgUser, $reason, $article->getId() ) );
+ if ( $article->doDeleteArticle( $reason, false, 0, true, $error ) ) {
return array();
+ } else {
+ return array( array( 'cannotdelete', $article->getTitle()->getPrefixedText() ) );
}
- return array( array( 'cannotdelete', $article->mTitle->getPrefixedText() ) );
}
/**
- * @static
* @param $token
- * @param $title
+ * @param $title Title
* @param $oldimage
* @param $reason
* @param $suppress bool
@@ -255,12 +250,15 @@ class ApiDelete extends ApiBase {
}
public function getPossibleErrors() {
- return array_merge( parent::getPossibleErrors(), array(
- array( 'invalidtitle', 'title' ),
- array( 'nosuchpageid', 'pageid' ),
- array( 'notanarticle' ),
- array( 'hookaborted', 'error' ),
- ) );
+ return array_merge( parent::getPossibleErrors(),
+ $this->getRequireOnlyOneParameterErrorMessages( array( 'title', 'pageid' ) ),
+ array(
+ array( 'invalidtitle', 'title' ),
+ array( 'nosuchpageid', 'pageid' ),
+ array( 'notanarticle' ),
+ array( 'hookaborted', 'error' ),
+ )
+ );
}
public function needsToken() {
@@ -278,7 +276,11 @@ class ApiDelete extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Delete';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiDelete.php 77141 2010-11-23 10:04:38Z ialex $';
+ return __CLASS__ . ': $Id: ApiDelete.php 104449 2011-11-28 15:52:04Z reedy $';
}
-} \ No newline at end of file
+}
diff --git a/includes/api/ApiDisabled.php b/includes/api/ApiDisabled.php
index f83bfdc9..947267f3 100644
--- a/includes/api/ApiDisabled.php
+++ b/includes/api/ApiDisabled.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 25, 2008
*
- * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -70,6 +70,6 @@ class ApiDisabled extends ApiBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiDisabled.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiDisabled.php 79969 2011-01-10 22:36:26Z reedy $';
}
}
diff --git a/includes/api/ApiEditPage.php b/includes/api/ApiEditPage.php
index 75cc0ba2..ffc82640 100644
--- a/includes/api/ApiEditPage.php
+++ b/includes/api/ApiEditPage.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on August 16, 2007
*
@@ -50,38 +50,40 @@ class ApiEditPage extends ApiBase {
is_null( $params['prependtext'] ) &&
$params['undo'] == 0 )
{
- $this->dieUsageMsg( array( 'missingtext' ) );
+ $this->dieUsageMsg( 'missingtext' );
}
$titleObj = Title::newFromText( $params['title'] );
if ( !$titleObj || $titleObj->isExternal() ) {
$this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
}
-
- if( $params['redirect'] ) {
- if( $titleObj->isRedirect() ) {
+
+ $apiResult = $this->getResult();
+
+ if ( $params['redirect'] ) {
+ if ( $titleObj->isRedirect() ) {
$oldTitle = $titleObj;
-
+
$titles = Title::newFromRedirectArray( Revision::newFromTitle( $oldTitle )->getText( Revision::FOR_THIS_USER ) );
+ // array_shift( $titles );
$redirValues = array();
foreach ( $titles as $id => $newTitle ) {
-
- if( !isset( $titles[ $id - 1 ] ) ) {
+
+ if ( !isset( $titles[ $id - 1 ] ) ) {
$titles[ $id - 1 ] = $oldTitle;
}
-
+
$redirValues[] = array(
'from' => $titles[ $id - 1 ]->getPrefixedText(),
'to' => $newTitle->getPrefixedText()
);
-
+
$titleObj = $newTitle;
}
-
- $this->getResult()->setIndexedTagName( $redirValues, 'r' );
- $this->getResult()->addValue( null, 'redirects', $redirValues );
+ $apiResult->setIndexedTagName( $redirValues, 'r' );
+ $apiResult->addValue( null, 'redirects', $redirValues );
}
}
@@ -90,10 +92,10 @@ class ApiEditPage extends ApiBase {
$wgTitle = $titleObj;
if ( $params['createonly'] && $titleObj->exists() ) {
- $this->dieUsageMsg( array( 'createonly-exists' ) );
+ $this->dieUsageMsg( 'createonly-exists' );
}
if ( $params['nocreate'] && !$titleObj->exists() ) {
- $this->dieUsageMsg( array( 'nocreate-missing' ) );
+ $this->dieUsageMsg( 'nocreate-missing' );
}
// Now let's check whether we're even allowed to do this
@@ -161,7 +163,7 @@ class ApiEditPage extends ApiBase {
$newtext = $articleObj->getUndoText( $undoRev, $undoafterRev );
if ( $newtext === false ) {
- $this->dieUsageMsg( array( 'undo-failure' ) );
+ $this->dieUsageMsg( 'undo-failure' );
}
$params['text'] = $newtext;
// If no summary was given and we only undid one rev,
@@ -173,10 +175,12 @@ class ApiEditPage extends ApiBase {
// See if the MD5 hash checks out
if ( !is_null( $params['md5'] ) && md5( $toMD5 ) !== $params['md5'] ) {
- $this->dieUsageMsg( array( 'hashcheckfailed' ) );
+ $this->dieUsageMsg( 'hashcheckfailed' );
}
$ep = new EditPage( $articleObj );
+ $ep->setContextTitle( $titleObj );
+
// EditPage wants to parse its stuff from a WebRequest
// That interface kind of sucks, but it's workable
$reqArr = array(
@@ -251,10 +255,10 @@ class ApiEditPage extends ApiBase {
if ( !wfRunHooks( 'APIEditBeforeSave', array( $ep, $ep->textbox1, &$r ) ) ) {
if ( count( $r ) ) {
$r['result'] = 'Failure';
- $this->getResult()->addValue( null, $this->getModuleName(), $r );
+ $apiResult->addValue( null, $this->getModuleName(), $r );
return;
} else {
- $this->dieUsageMsg( array( 'hookaborted' ) );
+ $this->dieUsageMsg( 'hookaborted' );
}
}
@@ -262,65 +266,65 @@ class ApiEditPage extends ApiBase {
$oldRevId = $articleObj->getRevIdFetched();
$result = null;
// Fake $wgRequest for some hooks inside EditPage
- // FIXME: This interface SUCKS
+ // @todo FIXME: This interface SUCKS
$oldRequest = $wgRequest;
$wgRequest = $req;
- $retval = $ep->internalAttemptSave( $result, $wgUser->isAllowed( 'bot' ) && $params['bot'] );
+ $status = $ep->internalAttemptSave( $result, $wgUser->isAllowed( 'bot' ) && $params['bot'] );
$wgRequest = $oldRequest;
global $wgMaxArticleSize;
- switch( $retval ) {
+ switch( $status->value ) {
case EditPage::AS_HOOK_ERROR:
case EditPage::AS_HOOK_ERROR_EXPECTED:
- $this->dieUsageMsg( array( 'hookaborted' ) );
+ $this->dieUsageMsg( 'hookaborted' );
case EditPage::AS_IMAGE_REDIRECT_ANON:
- $this->dieUsageMsg( array( 'noimageredirect-anon' ) );
+ $this->dieUsageMsg( 'noimageredirect-anon' );
case EditPage::AS_IMAGE_REDIRECT_LOGGED:
- $this->dieUsageMsg( array( 'noimageredirect-logged' ) );
+ $this->dieUsageMsg( 'noimageredirect-logged' );
case EditPage::AS_SPAM_ERROR:
$this->dieUsageMsg( array( 'spamdetected', $result['spam'] ) );
case EditPage::AS_FILTERING:
- $this->dieUsageMsg( array( 'filtered' ) );
+ $this->dieUsageMsg( 'filtered' );
case EditPage::AS_BLOCKED_PAGE_FOR_USER:
- $this->dieUsageMsg( array( 'blockedtext' ) );
+ $this->dieUsageMsg( 'blockedtext' );
case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
case EditPage::AS_CONTENT_TOO_BIG:
$this->dieUsageMsg( array( 'contenttoobig', $wgMaxArticleSize ) );
case EditPage::AS_READ_ONLY_PAGE_ANON:
- $this->dieUsageMsg( array( 'noedit-anon' ) );
+ $this->dieUsageMsg( 'noedit-anon' );
case EditPage::AS_READ_ONLY_PAGE_LOGGED:
- $this->dieUsageMsg( array( 'noedit' ) );
+ $this->dieUsageMsg( 'noedit' );
case EditPage::AS_READ_ONLY_PAGE:
$this->dieReadOnly();
case EditPage::AS_RATE_LIMITED:
- $this->dieUsageMsg( array( 'actionthrottledtext' ) );
+ $this->dieUsageMsg( 'actionthrottledtext' );
case EditPage::AS_ARTICLE_WAS_DELETED:
- $this->dieUsageMsg( array( 'wasdeleted' ) );
+ $this->dieUsageMsg( 'wasdeleted' );
case EditPage::AS_NO_CREATE_PERMISSION:
- $this->dieUsageMsg( array( 'nocreate-loggedin' ) );
+ $this->dieUsageMsg( 'nocreate-loggedin' );
case EditPage::AS_BLANK_ARTICLE:
- $this->dieUsageMsg( array( 'blankpage' ) );
+ $this->dieUsageMsg( 'blankpage' );
case EditPage::AS_CONFLICT_DETECTED:
- $this->dieUsageMsg( array( 'editconflict' ) );
+ $this->dieUsageMsg( 'editconflict' );
// case EditPage::AS_SUMMARY_NEEDED: Can't happen since we set wpIgnoreBlankSummary
case EditPage::AS_TEXTBOX_EMPTY:
- $this->dieUsageMsg( array( 'emptynewsection' ) );
+ $this->dieUsageMsg( 'emptynewsection' );
case EditPage::AS_SUCCESS_NEW_ARTICLE:
$r['new'] = '';
@@ -346,20 +350,17 @@ class ApiEditPage extends ApiBase {
break;
case EditPage::AS_SUMMARY_NEEDED:
- $this->dieUsageMsg( array( 'summaryrequired' ) );
+ $this->dieUsageMsg( 'summaryrequired' );
case EditPage::AS_END:
- // This usually means some kind of race condition
- // or DB weirdness occurred. Fall through to throw an unknown
- // error.
-
- // This needs fixing higher up, as Article::doEdit should be
- // used rather than Article::updateArticle, so that specific
- // error conditions can be returned
+ // $status came from WikiPage::doEdit()
+ $errors = $status->getErrorsArray();
+ $this->dieUsageMsg( $errors[0] ); // TODO: Add new errors to message map
+ break;
default:
- $this->dieUsageMsg( array( 'unknownerror', $retval ) );
+ $this->dieUsageMsg( array( 'unknownerror', $status->value ) );
}
- $this->getResult()->addValue( null, $this->getModuleName(), $r );
+ $apiResult->addValue( null, $this->getModuleName(), $r );
}
public function mustBePosted() {
@@ -406,6 +407,8 @@ class ApiEditPage extends ApiBase {
array( 'unknownerror', 'retval' ),
array( 'code' => 'nosuchsection', 'info' => 'There is no section section.' ),
array( 'code' => 'invalidsection', 'info' => 'The section parameter must be set to an integer or \'new\'' ),
+ array( 'customcssprotected' ),
+ array( 'customjsprotected' ),
) );
}
@@ -468,12 +471,14 @@ class ApiEditPage extends ApiBase {
'title' => 'Page title',
'section' => 'Section number. 0 for the top section, \'new\' for a new section',
'text' => 'Page content',
- 'token' => 'Edit token. You can get one of these through prop=info',
+ 'token' => array( 'Edit token. You can get one of these through prop=info.',
+ 'The token should always be sent as the last parameter, or at least, after the text parameter'
+ ),
'summary' => 'Edit summary. Also section title when section=new',
'minor' => 'Minor edit',
'notminor' => 'Non-minor edit',
'bot' => 'Mark this edit as bot',
- 'basetimestamp' => array( 'Timestamp of the base revision (gotten through prop=revisions&rvprop=timestamp).',
+ 'basetimestamp' => array( 'Timestamp of the base revision (obtained through prop=revisions&rvprop=timestamp).',
'Used to detect edit conflicts; leave unset to ignore conflicts.'
),
'starttimestamp' => array( 'Timestamp when you obtained the edit token.',
@@ -516,7 +521,11 @@ class ApiEditPage extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Edit';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiEditPage.php 90492 2011-06-20 22:39:10Z reedy $';
+ return __CLASS__ . ': $Id: ApiEditPage.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiEmailUser.php b/includes/api/ApiEmailUser.php
index ab58eb18..9ce43183 100644
--- a/includes/api/ApiEmailUser.php
+++ b/includes/api/ApiEmailUser.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on June 1, 2008
*
@@ -144,7 +144,11 @@ class ApiEmailUser extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:E-mail';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiEmailUser.php 85354 2011-04-04 18:25:31Z demon $';
+ return __CLASS__ . ': $Id: ApiEmailUser.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiExpandTemplates.php b/includes/api/ApiExpandTemplates.php
index 6f2df1b8..6ec18463 100644
--- a/includes/api/ApiExpandTemplates.php
+++ b/includes/api/ApiExpandTemplates.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 05, 2007
*
@@ -61,6 +61,10 @@ class ApiExpandTemplates extends ApiBase {
global $wgParser;
$options = new ParserOptions();
+ if ( $params['includecomments'] ) {
+ $options->setRemoveComments( false );
+ }
+
if ( $params['generatexml'] ) {
$wgParser->startExternalParse( $title_obj, $options, OT_PREPROCESS );
$dom = $wgParser->preprocessToDom( $params['text'] );
@@ -86,8 +90,12 @@ class ApiExpandTemplates extends ApiBase {
'title' => array(
ApiBase::PARAM_DFLT => 'API',
),
- 'text' => null,
+ 'text' => array(
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_REQUIRED => true,
+ ),
'generatexml' => false,
+ 'includecomments' => false,
);
}
@@ -96,11 +104,12 @@ class ApiExpandTemplates extends ApiBase {
'text' => 'Wikitext to convert',
'title' => 'Title of page',
'generatexml' => 'Generate XML parse tree',
+ 'includecomments' => 'Whether to include HTML comments in the output',
);
}
public function getDescription() {
- return 'This module expand all templates in wikitext';
+ return 'Expands all templates in wikitext';
}
protected function getExamples() {
@@ -109,7 +118,11 @@ class ApiExpandTemplates extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#expandtemplates';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiExpandTemplates.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiExpandTemplates.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiFeedContributions.php b/includes/api/ApiFeedContributions.php
new file mode 100644
index 00000000..c06b71af
--- /dev/null
+++ b/includes/api/ApiFeedContributions.php
@@ -0,0 +1,207 @@
+<?php
+
+/**
+ *
+ *
+ * Created on June 06, 2011
+ *
+ * Copyright © 2011 Sam Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @ingroup API
+ */
+class ApiFeedContributions extends ApiBase {
+
+ public function __construct( $main, $action ) {
+ parent::__construct( $main, $action );
+ }
+
+ /**
+ * This module uses a custom feed wrapper printer.
+ */
+ public function getCustomPrinter() {
+ return new ApiFormatFeedWrapper( $this->getMain() );
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ global $wgFeed, $wgFeedClasses, $wgSitename, $wgLanguageCode;
+
+ if( !$wgFeed ) {
+ $this->dieUsage( 'Syndication feeds are not available', 'feed-unavailable' );
+ }
+
+ if( !isset( $wgFeedClasses[ $params['feedformat'] ] ) ) {
+ $this->dieUsage( 'Invalid subscription feed type', 'feed-invalid' );
+ }
+
+ global $wgMiserMode;
+ if ( $params['showsizediff'] && $wgMiserMode ) {
+ $this->dieUsage( 'Size difference is disabled in Miser Mode', 'sizediffdisabled' );
+ }
+
+ $msg = wfMsgForContent( 'Contributions' );
+ $feedTitle = $wgSitename . ' - ' . $msg . ' [' . $wgLanguageCode . ']';
+ $feedUrl = SpecialPage::getTitleFor( 'Contributions', $params['user'] )->getFullURL();
+
+ $target = $params['user'] == 'newbies'
+ ? 'newbies'
+ : Title::makeTitleSafe( NS_USER, $params['user'] )->getText();
+
+ $feed = new $wgFeedClasses[$params['feedformat']] (
+ $feedTitle,
+ htmlspecialchars( $msg ),
+ $feedUrl
+ );
+
+ $pager = new ContribsPager( array(
+ 'target' => $target,
+ 'namespace' => $params['namespace'],
+ 'year' => $params['year'],
+ 'month' => $params['month'],
+ 'tagFilter' => $params['tagfilter'],
+ 'deletedOnly' => $params['deletedonly'],
+ 'topOnly' => $params['toponly'],
+ 'showSizeDiff' => $params['showsizediff'],
+ ) );
+
+ $feedItems = array();
+ if( $pager->getNumRows() > 0 ) {
+ foreach ( $pager->mResult as $row ) {
+ $feedItems[] = $this->feedItem( $row );
+ }
+ }
+
+ ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems );
+ }
+
+ protected function feedItem( $row ) {
+ $title = Title::MakeTitle( intval( $row->page_namespace ), $row->page_title );
+ if( $title ) {
+ $date = $row->rev_timestamp;
+ $comments = $title->getTalkPage()->getFullURL();
+ $revision = Revision::newFromRow( $row);
+
+ return new FeedItem(
+ $title->getPrefixedText(),
+ $this->feedItemDesc( $revision ),
+ $title->getFullURL(),
+ $date,
+ $this->feedItemAuthor( $revision ),
+ $comments
+ );
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @param $revision Revision
+ * @return string
+ */
+ protected function feedItemAuthor( $revision ) {
+ return $revision->getUserText();
+ }
+
+ /**
+ * @param $revision Revision
+ * @return string
+ */
+ protected function feedItemDesc( $revision ) {
+ if( $revision ) {
+ return '<p>' . htmlspecialchars( $revision->getUserText() ) . wfMsgForContent( 'colon-separator' ) .
+ htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) .
+ "</p>\n<hr />\n<div>" .
+ nl2br( htmlspecialchars( $revision->getText() ) ) . "</div>";
+ }
+ return '';
+ }
+
+ public function getAllowedParams() {
+ global $wgFeedClasses;
+ $feedFormatNames = array_keys( $wgFeedClasses );
+ return array (
+ 'feedformat' => array(
+ ApiBase::PARAM_DFLT => 'rss',
+ ApiBase::PARAM_TYPE => $feedFormatNames
+ ),
+ 'user' => array(
+ ApiBase::PARAM_TYPE => 'user',
+ ApiBase::PARAM_REQUIRED => true,
+ ),
+ 'namespace' => array(
+ ApiBase::PARAM_TYPE => 'namespace',
+ ApiBase::PARAM_ISMULTI => true
+ ),
+ 'year' => array(
+ ApiBase::PARAM_TYPE => 'integer'
+ ),
+ 'month' => array(
+ ApiBase::PARAM_TYPE => 'integer'
+ ),
+ 'tagfilter' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => array_values( ChangeTags::listDefinedTags() ),
+ ApiBase::PARAM_DFLT => '',
+ ),
+ 'deletedonly' => false,
+ 'toponly' => false,
+ 'showsizediff' => false,
+ );
+ }
+
+ public function getParamDescription() {
+ return array(
+ 'feedformat' => 'The format of the feed',
+ 'user' => 'What users to get the contributions for',
+ 'namespace' => 'What namespace to filter the contributions by',
+ 'year' => 'From year (and earlier)',
+ 'month' => 'From month (and earlier)',
+ 'tagfilter' => 'Filter contributions that have these tags',
+ 'deletedonly' => 'Show only deleted contributions',
+ 'toponly' => 'Only show edits that are latest revisions',
+ 'showsizediff' => 'Show the size difference between revisions. Disabled in Miser Mode',
+ );
+ }
+
+ public function getDescription() {
+ return 'Returns a user contributions feed';
+ }
+
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(), array(
+ array( 'code' => 'feed-unavailable', 'info' => 'Syndication feeds are not available' ),
+ array( 'code' => 'feed-invalid', 'info' => 'Invalid subscription feed type' ),
+ array( 'code' => 'sizediffdisabled', 'info' => 'Size difference is disabled in Miser Mode' ),
+ ) );
+ }
+
+ protected function getExamples() {
+ return array(
+ 'api.php?action=feedcontributions&user=Reedy',
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiFeedContributions.php 95607 2011-08-27 19:28:13Z hashar $';
+ }
+} \ No newline at end of file
diff --git a/includes/api/ApiFeedWatchlist.php b/includes/api/ApiFeedWatchlist.php
index e1ba61f6..75ce7ca0 100644
--- a/includes/api/ApiFeedWatchlist.php
+++ b/includes/api/ApiFeedWatchlist.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 13, 2006
*
@@ -56,11 +56,19 @@ class ApiFeedWatchlist extends ApiBase {
* Wrap the result as an RSS/Atom feed.
*/
public function execute() {
- global $wgFeedClasses, $wgFeedLimit, $wgSitename, $wgLanguageCode;
+ global $wgFeed, $wgFeedClasses, $wgFeedLimit, $wgSitename, $wgLanguageCode;
try {
$params = $this->extractRequestParams();
+ if( !$wgFeed ) {
+ $this->dieUsage( 'Syndication feeds are not available', 'feed-unavailable' );
+ }
+
+ if( !isset( $wgFeedClasses[ $params['feedformat'] ] ) ) {
+ $this->dieUsage( 'Invalid subscription feed type', 'feed-invalid' );
+ }
+
// limit to the number of hours going from now back
$endTime = wfTimestamp( TS_MW, time() - intval( $params['hours'] * 60 * 60 ) );
@@ -90,7 +98,7 @@ class ApiFeedWatchlist extends ApiBase {
}
// Check for 'allrev' parameter, and if found, show all revisions to each page on wl.
- if ( !is_null( $params['allrev'] ) ) {
+ if ( $params['allrev'] ) {
$fauxReqArr['wlallrev'] = '';
}
@@ -109,10 +117,12 @@ class ApiFeedWatchlist extends ApiBase {
$feedItems[] = $this->createFeedItem( $info );
}
- $feedTitle = $wgSitename . ' - ' . wfMsgForContent( 'watchlist' ) . ' [' . $wgLanguageCode . ']';
+ $msg = wfMsgForContent( 'watchlist' );
+
+ $feedTitle = $wgSitename . ' - ' . $msg . ' [' . $wgLanguageCode . ']';
$feedUrl = SpecialPage::getTitleFor( 'Watchlist' )->getFullURL();
- $feed = new $wgFeedClasses[$params['feedformat']] ( $feedTitle, htmlspecialchars( wfMsgForContent( 'watchlist' ) ), $feedUrl );
+ $feed = new $wgFeedClasses[$params['feedformat']] ( $feedTitle, htmlspecialchars( $msg ), $feedUrl );
ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems );
@@ -171,7 +181,7 @@ class ApiFeedWatchlist extends ApiBase {
ApiBase::PARAM_MIN => 1,
ApiBase::PARAM_MAX => 72,
),
- 'allrev' => null,
+ 'allrev' => false,
'wlowner' => array(
ApiBase::PARAM_TYPE => 'user'
),
@@ -189,22 +199,33 @@ class ApiFeedWatchlist extends ApiBase {
'allrev' => 'Include multiple revisions of the same page within given timeframe',
'wlowner' => "The user whose watchlist you want (must be accompanied by {$this->getModulePrefix()}token if it's not you)",
'wltoken' => 'Security token that requested user set in their preferences',
- 'linktodiffs'=> 'Link to change differences instead of article pages'
+ 'linktodiffs' => 'Link to change differences instead of article pages'
);
}
public function getDescription() {
- return 'This module returns a watchlist feed';
+ return 'Returns a watchlist feed';
+ }
+
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(), array(
+ array( 'code' => 'feed-unavailable', 'info' => 'Syndication feeds are not available' ),
+ array( 'code' => 'feed-invalid', 'info' => 'Invalid subscription feed type' ),
+ ) );
}
protected function getExamples() {
return array(
'api.php?action=feedwatchlist',
- 'api.php?action=feedwatchlist&allrev=allrev&linktodiffs=&hours=6'
+ 'api.php?action=feedwatchlist&allrev=&linktodiffs=&hours=6'
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Watchlist_feed';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFeedWatchlist.php 77674 2010-12-03 19:47:22Z catrope $';
+ return __CLASS__ . ': $Id: ApiFeedWatchlist.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiFileRevert.php b/includes/api/ApiFileRevert.php
new file mode 100644
index 00000000..1540fe6c
--- /dev/null
+++ b/includes/api/ApiFileRevert.php
@@ -0,0 +1,189 @@
+<?php
+/**
+ *
+ *
+ * Created on March 5, 2011
+ *
+ * Copyright © 2011 Bryan Tong Minh <Bryan.TongMinh@Gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ // Eclipse helper - will be ignored in production
+ require_once( "ApiBase.php" );
+}
+
+/**
+ * @ingroup API
+ */
+class ApiFileRevert extends ApiBase {
+
+ /**
+ * @var File
+ */
+ protected $file;
+ protected $archiveName;
+
+ protected $params;
+
+ public function __construct( $main, $action ) {
+ parent::__construct( $main, $action );
+ }
+
+ public function execute() {
+ global $wgUser;
+
+ $this->params = $this->extractRequestParams();
+ // Extract the file and archiveName from the request parameters
+ $this->validateParameters();
+
+ // Check whether we're allowed to revert this file
+ $this->checkPermissions( $wgUser );
+
+ $sourceUrl = $this->file->getArchiveVirtualUrl( $this->archiveName );
+ $status = $this->file->upload( $sourceUrl, $this->params['comment'], $this->params['comment'] );
+
+ if ( $status->isGood() ) {
+ $result = array( 'result' => 'Success' );
+ } else {
+ $result = array(
+ 'result' => 'Failure',
+ 'errors' => $this->getResult()->convertStatusToArray( $status ),
+ );
+ }
+
+ $this->getResult()->addValue( null, $this->getModuleName(), $result );
+
+ }
+
+ /**
+ * Checks that the user has permissions to perform this revert.
+ * Dies with usage message on inadequate permissions.
+ * @param $user User The user to check.
+ */
+ protected function checkPermissions( $user ) {
+ $permissionErrors = array_merge(
+ $this->file->getTitle()->getUserPermissionsErrors( 'edit' , $user ),
+ $this->file->getTitle()->getUserPermissionsErrors( 'upload' , $user )
+ );
+
+ if ( $permissionErrors ) {
+ $this->dieUsageMsg( $permissionErrors[0] );
+ }
+ }
+
+ /**
+ * Validate the user parameters and set $this->archiveName and $this->file.
+ * Throws an error if validation fails
+ */
+ protected function validateParameters() {
+ // Validate the input title
+ $title = Title::makeTitleSafe( NS_FILE, $this->params['filename'] );
+ if ( is_null( $title ) ) {
+ $this->dieUsageMsg( array( 'invalidtitle', $this->params['filename'] ) );
+ }
+ // Check if the file really exists
+ $this->file = wfLocalFile( $title );
+ if ( !$this->file->exists() ) {
+ $this->dieUsageMsg( 'notanarticle' );
+ }
+
+ // Check if the archivename is valid for this file
+ $this->archiveName = $this->params['archivename'];
+ $oldFile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $title, $this->archiveName );
+ if ( !$oldFile->exists() ) {
+ $this->dieUsageMsg( 'filerevert-badversion' );
+ }
+ }
+
+ public function mustBePosted() {
+ return true;
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ public function getAllowedParams() {
+ return array(
+ 'filename' => array(
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_REQUIRED => true,
+ ),
+ 'comment' => array(
+ ApiBase::PARAM_DFLT => '',
+ ),
+ 'archivename' => array(
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_REQUIRED => true,
+ ),
+ 'token' => null,
+ );
+
+ }
+
+ public function getParamDescription() {
+ $params = array(
+ 'filename' => 'Target filename',
+ 'token' => 'Edit token. You can get one of these through prop=info',
+ 'comment' => 'Upload comment',
+ 'archivename' => 'Archive name of the revision to revert to',
+ );
+
+ return $params;
+
+ }
+
+ public function getDescription() {
+ return array(
+ 'Revert a file to an old version'
+ );
+ }
+
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(),
+ array(
+ array( 'mustbeloggedin', 'upload' ),
+ array( 'badaccess-groups' ),
+ array( 'invalidtitle', 'title' ),
+ array( 'notanarticle' ),
+ array( 'filerevert-badversion' ),
+ )
+ );
+ }
+
+ public function needsToken() {
+ return true;
+ }
+
+ public function getTokenSalt() {
+ return '';
+ }
+
+ protected function getExamples() {
+ return array(
+ 'Revert Wiki.png to the version of 20110305152740:',
+ ' api.php?action=filerevert&filename=Wiki.png&comment=Revert&archivename=20110305152740!Wiki.png&token=+\\',
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiFileRevert.php 92400 2011-07-17 16:51:11Z reedy $';
+ }
+}
diff --git a/includes/api/ApiFormatBase.php b/includes/api/ApiFormatBase.php
index 9d1dfbc1..ce881599 100644
--- a/includes/api/ApiFormatBase.php
+++ b/includes/api/ApiFormatBase.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 19, 2006
*
@@ -146,11 +146,11 @@ abstract class ApiFormatBase extends ApiBase {
return; // skip any initialization
}
- header( "Content-Type: $mime; charset=utf-8" );
+ $this->getMain()->getRequest()->response()->header( "Content-Type: $mime; charset=utf-8" );
if ( $isHtml ) {
?>
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!DOCTYPE HTML>
<html>
<head>
<?php if ( $this->mUnescapeAmps ) {
@@ -169,7 +169,7 @@ abstract class ApiFormatBase extends ApiBase {
<small>
You are looking at the HTML representation of the <?php echo( $this->mFormat ); ?> format.<br />
HTML is good for debugging, but probably is not suitable for your application.<br />
-See <a href='http://www.mediawiki.org/wiki/API'>complete documentation</a>, or
+See <a href='https://www.mediawiki.org/wiki/API'>complete documentation</a>, or
<a href='<?php echo( $script ); ?>'>API help</a> for more information.
</small>
<?php
@@ -257,15 +257,13 @@ See <a href='http://www.mediawiki.org/wiki/API'>complete documentation</a>, or
* @return string
*/
protected function formatHTML( $text ) {
- global $wgUrlProtocols;
-
// Escape everything first for full coverage
$text = htmlspecialchars( $text );
// encode all comments or tags as safe blue strings
$text = preg_replace( '/\&lt;(!--.*?--|.*?)\&gt;/', '<span style="color:blue;">&lt;\1&gt;</span>', $text );
// identify URLs
- $protos = implode( "|", $wgUrlProtocols );
+ $protos = wfUrlProtocolsWithoutProtRel();
// This regex hacks around bug 13218 (&quot; included in the URL)
$text = preg_replace( "#(($protos).*?)(&quot;)?([ \\'\"<>\n]|&lt;|&gt;|&quot;)#", '<a href="\\1">\\1</a>\\3\\4', $text );
// identify requests to api.php
@@ -294,12 +292,16 @@ See <a href='http://www.mediawiki.org/wiki/API'>complete documentation</a>, or
return 'api.php?action=query&meta=siteinfo&siprop=namespaces&format=' . $this->getModuleName();
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Data_formats';
+ }
+
public function getDescription() {
return $this->getIsHtml() ? ' (pretty-print in HTML)' : '';
}
public static function getBaseVersion() {
- return __CLASS__ . ': $Id: ApiFormatBase.php 75970 2010-11-04 00:55:30Z reedy $';
+ return __CLASS__ . ': $Id: ApiFormatBase.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
@@ -368,6 +370,6 @@ class ApiFormatFeedWrapper extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatBase.php 75970 2010-11-04 00:55:30Z reedy $';
+ return __CLASS__ . ': $Id: ApiFormatBase.php 104449 2011-11-28 15:52:04Z reedy $';
}
-} \ No newline at end of file
+}
diff --git a/includes/api/ApiFormatDbg.php b/includes/api/ApiFormatDbg.php
index d4aeb0b8..00b03494 100644
--- a/includes/api/ApiFormatDbg.php
+++ b/includes/api/ApiFormatDbg.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 22, 2006
*
- * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,6 +55,6 @@ class ApiFormatDbg extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatDbg.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiFormatDbg.php 78829 2010-12-22 20:52:06Z reedy $';
}
}
diff --git a/includes/api/ApiFormatDump.php b/includes/api/ApiFormatDump.php
index 6197563d..b88572e9 100644
--- a/includes/api/ApiFormatDump.php
+++ b/includes/api/ApiFormatDump.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on August 8, 2010
*
@@ -59,6 +59,6 @@ class ApiFormatDump extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id$';
+ return __CLASS__ . ': $Id: ApiFormatDump.php 79969 2011-01-10 22:36:26Z reedy $';
}
}
diff --git a/includes/api/ApiFormatJson.php b/includes/api/ApiFormatJson.php
index 7c02baa0..92689084 100644
--- a/includes/api/ApiFormatJson.php
+++ b/includes/api/ApiFormatJson.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 19, 2006
*
@@ -97,6 +97,6 @@ class ApiFormatJson extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatJson.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiFormatJson.php 78829 2010-12-22 20:52:06Z reedy $';
}
}
diff --git a/includes/api/ApiFormatPhp.php b/includes/api/ApiFormatPhp.php
index e83941d4..010966d6 100644
--- a/includes/api/ApiFormatPhp.php
+++ b/includes/api/ApiFormatPhp.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 22, 2006
*
@@ -52,6 +52,6 @@ class ApiFormatPhp extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatPhp.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiFormatPhp.php 78829 2010-12-22 20:52:06Z reedy $';
}
}
diff --git a/includes/api/ApiFormatRaw.php b/includes/api/ApiFormatRaw.php
index 98a50652..3b0c10ea 100644
--- a/includes/api/ApiFormatRaw.php
+++ b/includes/api/ApiFormatRaw.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Feb 2, 2009
*
- * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,7 +38,7 @@ class ApiFormatRaw extends ApiFormatBase {
/**
* Constructor
* @param $main ApiMain object
- * @param $errorFallback Formatter object to fall back on for errors
+ * @param $errorFallback ApiFormatBase object to fall back on for errors
*/
public function __construct( $main, $errorFallback ) {
parent::__construct( $main, 'raw' );
@@ -73,6 +73,6 @@ class ApiFormatRaw extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatRaw.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiFormatRaw.php 82429 2011-02-19 00:30:18Z reedy $';
}
}
diff --git a/includes/api/ApiFormatTxt.php b/includes/api/ApiFormatTxt.php
index bbb268f1..bb5a3ba1 100644
--- a/includes/api/ApiFormatTxt.php
+++ b/includes/api/ApiFormatTxt.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 22, 2006
*
- * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,6 +55,6 @@ class ApiFormatTxt extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatTxt.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiFormatTxt.php 78829 2010-12-22 20:52:06Z reedy $';
}
}
diff --git a/includes/api/ApiFormatWddx.php b/includes/api/ApiFormatWddx.php
index 6c1e3066..2598cc55 100644
--- a/includes/api/ApiFormatWddx.php
+++ b/includes/api/ApiFormatWddx.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 22, 2006
*
@@ -117,6 +117,6 @@ class ApiFormatWddx extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatWddx.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiFormatWddx.php 78829 2010-12-22 20:52:06Z reedy $';
}
}
diff --git a/includes/api/ApiFormatXml.php b/includes/api/ApiFormatXml.php
index 45ab73ef..3bdfdfa3 100644
--- a/includes/api/ApiFormatXml.php
+++ b/includes/api/ApiFormatXml.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 19, 2006
*
@@ -36,7 +36,9 @@ if ( !defined( 'MEDIAWIKI' ) ) {
class ApiFormatXml extends ApiFormatBase {
private $mRootElemName = 'api';
+ public static $namespace = 'http://www.mediawiki.org/xml/api/';
private $mDoubleQuote = false;
+ private $mIncludeNamespace = false;
private $mXslt = null;
public function __construct( $main, $format ) {
@@ -58,15 +60,22 @@ class ApiFormatXml extends ApiFormatBase {
public function execute() {
$params = $this->extractRequestParams();
$this->mDoubleQuote = $params['xmldoublequote'];
+ $this->mIncludeNamespace = $params['includexmlnamespace'];
$this->mXslt = $params['xslt'];
$this->printText( '<?xml version="1.0"?>' );
if ( !is_null( $this->mXslt ) ) {
$this->addXslt();
}
+ if ( $this->mIncludeNamespace ) {
+ $data = array( 'xmlns' => self::$namespace ) + $this->getResultData();
+ } else {
+ $data = $this->getResultData();
+ }
+
$this->printText(
self::recXmlPrint( $this->mRootElemName,
- $this->getResultData(),
+ $data,
$this->getIsHtml() ? - 2 : null,
$this->mDoubleQuote
)
@@ -85,6 +94,13 @@ class ApiFormatXml extends ApiFormatBase {
*
* If neither key is found, all keys become element names, and values become element content.
* The method is recursive, so the same rules apply to any sub-arrays.
+ *
+ * @param $elemName
+ * @param $elemValue
+ * @param $indent
+ * @param $doublequote bool
+ *
+ * @return string
*/
public static function recXmlPrint( $elemName, $elemValue, $indent, $doublequote = false ) {
$retval = '';
@@ -193,6 +209,7 @@ class ApiFormatXml extends ApiFormatBase {
return array(
'xmldoublequote' => false,
'xslt' => null,
+ 'includexmlnamespace' => false,
);
}
@@ -200,6 +217,7 @@ class ApiFormatXml extends ApiFormatBase {
return array(
'xmldoublequote' => 'If specified, double quotes all attributes and content',
'xslt' => 'If specified, adds <xslt> as stylesheet',
+ 'includexmlnamespace' => 'If specified, adds an XML namespace'
);
}
@@ -208,6 +226,6 @@ class ApiFormatXml extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatXml.php 73753 2010-09-25 16:56:03Z reedy $';
+ return __CLASS__ . ': $Id: ApiFormatXml.php 104476 2011-11-28 20:08:17Z reedy $';
}
}
diff --git a/includes/api/ApiFormatYaml.php b/includes/api/ApiFormatYaml.php
index ccf52746..d62bbbba 100644
--- a/includes/api/ApiFormatYaml.php
+++ b/includes/api/ApiFormatYaml.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 19, 2006
*
@@ -33,25 +33,17 @@ if ( !defined( 'MEDIAWIKI' ) ) {
* API YAML output formatter
* @ingroup API
*/
-class ApiFormatYaml extends ApiFormatBase {
-
- public function __construct( $main, $format ) {
- parent::__construct( $main, $format );
- }
+class ApiFormatYaml extends ApiFormatJson {
public function getMimeType() {
return 'application/yaml';
}
- public function execute() {
- $this->printText( Spyc::YAMLDump( $this->getResultData() ) );
- }
-
public function getDescription() {
return 'Output data in YAML format' . parent::getDescription();
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatYaml.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiFormatYaml.php 86302 2011-04-18 11:42:44Z reedy $';
}
}
diff --git a/includes/api/ApiHelp.php b/includes/api/ApiHelp.php
index eedbde13..4b2ced7e 100644
--- a/includes/api/ApiHelp.php
+++ b/includes/api/ApiHelp.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 6, 2006
*
@@ -93,6 +93,11 @@ class ApiHelp extends ApiBase {
$result->addValue( null, $this->getModuleName(), $r );
}
+ /**
+ * @param $module ApiBase
+ * @param $type String What type of request is this? e.g. action, query, list, prop, meta, format
+ * @return string
+ */
private function buildModuleHelp( $module, $type ) {
$msg = ApiMain::makeHelpMsgHeader( $module, $type );
@@ -149,7 +154,15 @@ class ApiHelp extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return array(
+ 'https://www.mediawiki.org/wiki/API:Main_page',
+ 'https://www.mediawiki.org/wiki/API:FAQ',
+ 'https://www.mediawiki.org/wiki/API:Quick_start_guide',
+ );
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiHelp.php 73863 2010-09-28 02:33:43Z brion $';
+ return __CLASS__ . ': $Id: ApiHelp.php 104439 2011-11-28 15:22:23Z reedy $';
}
}
diff --git a/includes/api/ApiImport.php b/includes/api/ApiImport.php
index 1b5153f9..a1e5709a 100644
--- a/includes/api/ApiImport.php
+++ b/includes/api/ApiImport.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Feb 4, 2009
*
- * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -42,13 +42,14 @@ class ApiImport extends ApiBase {
public function execute() {
global $wgUser;
- if ( !$wgUser->isAllowed( 'import' ) ) {
- $this->dieUsageMsg( array( 'cantimport' ) );
- }
+
$params = $this->extractRequestParams();
$isUpload = false;
if ( isset( $params['interwikisource'] ) ) {
+ if ( !$wgUser->isAllowed( 'import' ) ) {
+ $this->dieUsageMsg( 'cantimport' );
+ }
if ( !isset( $params['interwikipage'] ) ) {
$this->dieUsageMsg( array( 'missingparam', 'interwikipage' ) );
}
@@ -61,7 +62,7 @@ class ApiImport extends ApiBase {
} else {
$isUpload = true;
if ( !$wgUser->isAllowed( 'importupload' ) ) {
- $this->dieUsageMsg( array( 'cantimport-upload' ) );
+ $this->dieUsageMsg( 'cantimport-upload' );
}
$source = ImportStreamSource::newFromUpload( 'xml' );
}
@@ -87,8 +88,9 @@ class ApiImport extends ApiBase {
}
$resultData = $reporter->getData();
- $this->getResult()->setIndexedTagName( $resultData, 'page' );
- $this->getResult()->addValue( null, $this->getModuleName(), $resultData );
+ $result = $this->getResult();
+ $result->setIndexedTagName( $resultData, 'page' );
+ $result->addValue( null, $this->getModuleName(), $resultData );
}
public function mustBePosted() {
@@ -131,7 +133,11 @@ class ApiImport extends ApiBase {
}
public function getDescription() {
- return 'Import a page from another wiki, or an XML file';
+ return array(
+ 'Import a page from another wiki, or an XML file.' ,
+ 'Note that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when',
+ 'sending a file for the "xml" parameter.'
+ );
}
public function getPossibleErrors() {
@@ -159,8 +165,12 @@ class ApiImport extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Import';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiImport.php 77800 2010-12-05 14:22:49Z ialex $';
+ return __CLASS__ . ': $Id: ApiImport.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
@@ -171,6 +181,14 @@ class ApiImport extends ApiBase {
class ApiImportReporter extends ImportReporter {
private $mResultArr = array();
+ /**
+ * @param $title Title
+ * @param $origTitle Title
+ * @param $revisionCount int
+ * @param $successCount int
+ * @param $pageInfo
+ * @return void
+ */
function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
// Add a result entry
$r = array();
diff --git a/includes/api/ApiLogin.php b/includes/api/ApiLogin.php
index 0675de7b..a09f0335 100644
--- a/includes/api/ApiLogin.php
+++ b/includes/api/ApiLogin.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 19, 2006
*
@@ -72,13 +72,15 @@ class ApiLogin extends ApiBase {
global $wgCookiePrefix, $wgUser, $wgPasswordAttemptThrottle;
- switch ( $authRes = $loginForm->authenticateUserData() ) {
+ $authRes = $loginForm->authenticateUserData();
+ switch ( $authRes ) {
case LoginForm::SUCCESS:
$wgUser->setOption( 'rememberpassword', 1 );
- $wgUser->setCookies();
+ $wgUser->setCookies( $this->getMain()->getRequest() );
- // Run hooks. FIXME: split back and frontend from this hook.
- // FIXME: This hook should be placed in the backend
+ // Run hooks.
+ // @todo FIXME: Split back and frontend from this hook.
+ // @todo FIXME: This hook should be placed in the backend
$injected_html = '';
wfRunHooks( 'UserLoginComplete', array( &$wgUser, &$injected_html ) );
@@ -140,6 +142,11 @@ class ApiLogin extends ApiBase {
$result['result'] = 'Blocked';
break;
+ case LoginForm::ABORTED:
+ $result['result'] = 'Aborted';
+ $result['reason'] = $loginForm->mAbortLoginErrorMsg;
+ break;
+
default:
ApiBase::dieDebug( __METHOD__, "Unhandled case value: {$authRes}" );
}
@@ -175,7 +182,7 @@ class ApiLogin extends ApiBase {
public function getDescription() {
return array(
- 'This module is used to login and get the authentication tokens. ',
+ 'Log in and get the authentication tokens. ',
'In the event of a successful log-in, a cookie will be attached',
'to your session. In the event of a failed log-in, you will not ',
'be able to attempt another log-in through this method for 5 seconds.',
@@ -205,7 +212,11 @@ class ApiLogin extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Login';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiLogin.php 76080 2010-11-05 11:54:35Z catrope $';
+ return __CLASS__ . ': $Id: ApiLogin.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiLogout.php b/includes/api/ApiLogout.php
index 89326915..3639df3b 100644
--- a/includes/api/ApiLogout.php
+++ b/includes/api/ApiLogout.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Jan 4, 2008
*
@@ -64,7 +64,7 @@ class ApiLogout extends ApiBase {
}
public function getDescription() {
- return 'This module is used to logout and clear session data';
+ return 'Log out and clear session data';
}
protected function getExamples() {
@@ -73,7 +73,11 @@ class ApiLogout extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Logout';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiLogout.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiLogout.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php
index d5238a51..d24e1df2 100644
--- a/includes/api/ApiMain.php
+++ b/includes/api/ApiMain.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 4, 2006
*
@@ -60,10 +60,12 @@ class ApiMain extends ApiBase {
'expandtemplates' => 'ApiExpandTemplates',
'parse' => 'ApiParse',
'opensearch' => 'ApiOpenSearch',
+ 'feedcontributions' => 'ApiFeedContributions',
'feedwatchlist' => 'ApiFeedWatchlist',
'help' => 'ApiHelp',
'paraminfo' => 'ApiParamInfo',
'rsd' => 'ApiRsd',
+ 'compare' => 'ApiComparePages',
// Write modules
'purge' => 'ApiPurge',
@@ -76,6 +78,7 @@ class ApiMain extends ApiBase {
'move' => 'ApiMove',
'edit' => 'ApiEditPage',
'upload' => 'ApiUpload',
+ 'filerevert' => 'ApiFileRevert',
'emailuser' => 'ApiEmailUser',
'watch' => 'ApiWatch',
'patrol' => 'ApiPatrol',
@@ -123,7 +126,12 @@ class ApiMain extends ApiBase {
)
);
- private $mPrinter, $mModules, $mModuleNames, $mFormats, $mFormatNames;
+ /**
+ * @var ApiFormatBase
+ */
+ private $mPrinter;
+
+ private $mModules, $mModuleNames, $mFormats, $mFormatNames;
private $mResult, $mAction, $mShowVersions, $mEnableWrite, $mRequest;
private $mInternalMode, $mSquidMaxage, $mModule;
@@ -175,6 +183,7 @@ class ApiMain extends ApiBase {
/**
* Return true if the API was started by other PHP code using FauxRequest
+ * @return bool
*/
public function isInternalMode() {
return $this->mInternalMode;
@@ -199,6 +208,8 @@ class ApiMain extends ApiBase {
/**
* Get the API module object. Only works after executeAction()
+ *
+ * @return ApiBase
*/
public function getModule() {
return $this->mModule;
@@ -215,6 +226,8 @@ class ApiMain extends ApiBase {
/**
* Set how long the response should be cached.
+ *
+ * @param $maxage
*/
public function setCacheMaxAge( $maxage ) {
$this->setCacheControl( array(
@@ -268,7 +281,7 @@ class ApiMain extends ApiBase {
}
/**
- * @deprecated Private caching is now the default, so there is usually no
+ * @deprecated since 1.17 Private caching is now the default, so there is usually no
* need to call this function. If there is a need, you can use
* $this->setCacheMode('private')
*/
@@ -283,6 +296,8 @@ class ApiMain extends ApiBase {
*
* Cache control values set here will only be used if the cache mode is not
* private, see setCacheMode().
+ *
+ * @param $directives array
*/
public function setCacheControl( $directives ) {
$this->mCacheControl = $directives + $this->mCacheControl;
@@ -296,7 +311,7 @@ class ApiMain extends ApiBase {
* given URL must either always or never call this function; if it sometimes does and
* sometimes doesn't, stuff will break.
*
- * @deprecated Use setCacheMode( 'anon-public-user-private' )
+ * @deprecated since 1.17 Use setCacheMode( 'anon-public-user-private' )
*/
public function setVaryCookie() {
$this->setCacheMode( 'anon-public-user-private' );
@@ -304,6 +319,10 @@ class ApiMain extends ApiBase {
/**
* Create an instance of an output formatter by its name
+ *
+ * @param $format string
+ *
+ * @return ApiFormatBase
*/
public function createPrinterByName( $format ) {
if ( !isset( $this->mFormats[$format] ) ) {
@@ -343,22 +362,21 @@ class ApiMain extends ApiBase {
wfDebugLog( 'exception', $e->getLogMessage() );
}
- //
// Handle any kind of exception by outputing 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 ) {
- header( $headerStr );
+ $response->header( $headerStr );
} else {
- header( $headerStr, true, $e->getCode() );
+ $response->header( $headerStr, true, $e->getCode() );
}
// Reset and print just the error message
@@ -381,29 +399,44 @@ class ApiMain extends ApiBase {
}
protected function sendCacheHeaders() {
+ global $wgUseXVO, $wgOut, $wgVaryOnXFP;
+ $response = $this->getRequest()->response();
+
if ( $this->mCacheMode == 'private' ) {
- header( 'Cache-Control: private' );
+ $response->header( 'Cache-Control: private' );
return;
}
if ( $this->mCacheMode == 'anon-public-user-private' ) {
- global $wgUseXVO, $wgOut;
- header( 'Vary: Accept-Encoding, Cookie' );
+ $xfp = $wgVaryOnXFP ? ', X-Forwarded-Proto' : '';
+ $response->header( 'Vary: Accept-Encoding, Cookie' . $xfp );
if ( $wgUseXVO ) {
- header( $wgOut->getXVO() );
+ if ( $wgVaryOnXFP ) {
+ $wgOut->addVaryHeader( 'X-Forwarded-Proto' );
+ }
+ $response->header( $wgOut->getXVO() );
if ( $wgOut->haveCacheVaryCookies() ) {
// Logged in, mark this request private
- header( 'Cache-Control: private' );
+ $response->header( 'Cache-Control: private' );
return;
}
// Logged out, send normal public headers below
} elseif ( session_id() != '' ) {
// Logged in or otherwise has session (e.g. anonymous users who have edited)
// Mark request private
- header( 'Cache-Control: private' );
+ $response->header( 'Cache-Control: private' );
return;
} // else no XVO and anonymous, send public headers below
}
+
+ // Send public headers
+ if ( $wgVaryOnXFP ) {
+ $response->header( 'Vary: Accept-Encoding, X-Forwarded-Proto' );
+ if ( $wgUseXVO ) {
+ // Bleeeeegh. Our header setting system sucks
+ $response->header( 'X-Vary-Options: Accept-Encoding;list-contains=gzip, X-Forwarded-Proto' );
+ }
+ }
// If nobody called setCacheMaxAge(), use the (s)maxage parameters
if ( !isset( $this->mCacheControl['s-maxage'] ) ) {
@@ -417,7 +450,7 @@ class ApiMain extends ApiBase {
// Public cache not requested
// Sending a Vary header in this case is harmless, and protects us
// against conditional calls of setCacheMaxAge().
- header( 'Cache-Control: private' );
+ $response->header( 'Cache-Control: private' );
return;
}
@@ -426,7 +459,7 @@ class ApiMain extends ApiBase {
// Send an Expires header
$maxAge = min( $this->mCacheControl['s-maxage'], $this->mCacheControl['max-age'] );
$expiryUnixTime = ( $maxAge == 0 ? 1 : time() + $maxAge );
- header( 'Expires: ' . wfTimestamp( TS_RFC2822, $expiryUnixTime ) );
+ $response->header( 'Expires: ' . wfTimestamp( TS_RFC2822, $expiryUnixTime ) );
// Construct the Cache-Control header
$ccHeader = '';
@@ -443,15 +476,17 @@ class ApiMain extends ApiBase {
}
}
- header( "Cache-Control: $ccHeader" );
+ $response->header( "Cache-Control: $ccHeader" );
}
/**
* Replace the result data with the information about an exception.
* Returns the error code
* @param $e Exception
+ * @return string
*/
protected function substituteResultWithError( $e ) {
+ $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.
@@ -462,14 +497,12 @@ class ApiMain extends ApiBase {
$this->mPrinter = $this->createPrinterByName( $value );
if ( $this->mPrinter->getNeedsRawData() ) {
- $this->getResult()->setRawMode();
+ $result->setRawMode();
}
}
if ( $e instanceof UsageException ) {
- //
// User entered incorrect parameters - print usage screen
- //
$errMessage = $e->getMessageArray();
// Only print the help message when this is for the developer, not runtime
@@ -479,9 +512,7 @@ class ApiMain extends ApiBase {
} else {
global $wgShowSQLErrors, $wgShowExceptionDetails;
- //
// Something is seriously wrong
- //
if ( ( $e instanceof DBQueryError ) && !$wgShowSQLErrors ) {
$info = 'Database query error';
} else {
@@ -495,32 +526,34 @@ class ApiMain extends ApiBase {
ApiResult::setContent( $errMessage, $wgShowExceptionDetails ? "\n\n{$e->getTraceAsString()}\n\n" : '' );
}
- $this->getResult()->reset();
- $this->getResult()->disableSizeCheck();
+ $result->reset();
+ $result->disableSizeCheck();
// Re-add the id
$requestid = $this->getParameter( 'requestid' );
if ( !is_null( $requestid ) ) {
- $this->getResult()->addValue( null, 'requestid', $requestid );
+ $result->addValue( null, 'requestid', $requestid );
}
// servedby is especially useful when debugging errors
- $this->getResult()->addValue( null, 'servedby', wfHostName() );
- $this->getResult()->addValue( null, 'error', $errMessage );
+ $result->addValue( null, 'servedby', wfHostName() );
+ $result->addValue( null, 'error', $errMessage );
return $errMessage['code'];
}
/**
* Set up for the execution.
+ * @return array
*/
protected function setupExecuteAction() {
// First add the id to the top element
+ $result = $this->getResult();
$requestid = $this->getParameter( 'requestid' );
if ( !is_null( $requestid ) ) {
- $this->getResult()->addValue( null, 'requestid', $requestid );
+ $result->addValue( null, 'requestid', $requestid );
}
$servedby = $this->getParameter( 'servedby' );
if ( $servedby ) {
- $this->getResult()->addValue( null, 'servedby', wfHostName() );
+ $result->addValue( null, 'servedby', wfHostName() );
}
$params = $this->extractRequestParams();
@@ -553,8 +586,8 @@ class ApiMain extends ApiBase {
$this->dieUsageMsg( array( 'missingparam', 'token' ) );
} else {
global $wgUser;
- if ( !$wgUser->matchEditToken( $moduleParams['token'], $salt ) ) {
- $this->dieUsageMsg( array( 'sessionfailure' ) );
+ if ( !$wgUser->matchEditToken( $moduleParams['token'], $salt, $this->getRequest() ) ) {
+ $this->dieUsageMsg( 'sessionfailure' );
}
}
}
@@ -574,8 +607,11 @@ class ApiMain extends ApiBase {
$maxLag = $params['maxlag'];
list( $host, $lag ) = wfGetLB()->getMaxLag();
if ( $lag > $maxLag ) {
- header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
- header( 'X-Database-Lag: ' . intval( $lag ) );
+ $response = $this->getRequest()->response();
+
+ $response->header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
+ $response->header( 'X-Database-Lag: ' . intval( $lag ) );
+
if ( $wgShowHostnames ) {
$this->dieUsage( "Waiting for $host: $lag seconds lagged", 'maxlag' );
} else {
@@ -587,7 +623,6 @@ class ApiMain extends ApiBase {
return true;
}
-
/**
* Check for sufficient permissions to execute
* @param $module ApiBase An Api module
@@ -597,14 +632,14 @@ class ApiMain extends ApiBase {
if ( $module->isReadMode() && !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) &&
!$wgUser->isAllowed( 'read' ) )
{
- $this->dieUsageMsg( array( 'readrequired' ) );
+ $this->dieUsageMsg( 'readrequired' );
}
if ( $module->isWriteMode() ) {
if ( !$this->mEnableWrite ) {
- $this->dieUsageMsg( array( 'writedisabled' ) );
+ $this->dieUsageMsg( 'writedisabled' );
}
if ( !$wgUser->isAllowed( 'writeapi' ) ) {
- $this->dieUsageMsg( array( 'writerequired' ) );
+ $this->dieUsageMsg( 'writerequired' );
}
if ( wfReadOnly() ) {
$this->dieReadOnly();
@@ -666,6 +701,8 @@ class ApiMain extends ApiBase {
/**
* Print results using the current printer
+ *
+ * @param $isError bool
*/
protected function printResult( $isError ) {
$this->getResult()->cleanUpUTF8();
@@ -687,12 +724,17 @@ class ApiMain extends ApiBase {
$printer->profileOut();
}
+ /**
+ * @return bool
+ */
public function isReadMode() {
return false;
}
/**
* See ApiBase for description.
+ *
+ * @return array
*/
public function getAllowedParams() {
return array(
@@ -723,13 +765,22 @@ class ApiMain extends ApiBase {
/**
* See ApiBase for description.
+ *
+ * @return array
*/
public function getParamDescription() {
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' => 'Maximum lag',
+ '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',
+ 'wait until the replication lag is less than the specified value.',
+ 'In case of a replag error, a HTTP 503 error is returned, with the message like',
+ '"Waiting for $host: $lag seconds lagged\n".',
+ 'See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter for more information',
+ ),
'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',
'requestid' => 'Request ID to distinguish requests. This will just be output back to you',
@@ -739,28 +790,40 @@ class ApiMain extends ApiBase {
/**
* See ApiBase for description.
+ *
+ * @return array
*/
public function getDescription() {
return array(
'',
'',
- '******************************************************************************************',
- '** **',
- '** This is an auto-generated MediaWiki API documentation page **',
- '** **',
- '** Documentation and Examples: **',
- '** http://www.mediawiki.org/wiki/API **',
- '** **',
- '******************************************************************************************',
+ '**********************************************************************************************************',
+ '** **',
+ '** This is an auto-generated MediaWiki API documentation page **',
+ '** **',
+ '** Documentation and Examples: **',
+ '** https://www.mediawiki.org/wiki/API **',
+ '** **',
+ '**********************************************************************************************************',
'',
'Status: All features shown on this page should be working, but the API',
- ' is still in active development, and may change at any time.',
+ ' is still in active development, and may change at any time.',
' Make sure to monitor our mailing list for any updates',
'',
- 'Documentation: http://www.mediawiki.org/wiki/API',
- 'Mailing list: http://lists.wikimedia.org/mailman/listinfo/mediawiki-api',
- 'Api Announcements: http://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce',
- 'Bugs & Requests: http://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts',
+ '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',
+ '',
+ ' In the case of an invalid action being passed, these will have a value',
+ ' of "unknown_action"',
+ '',
+ ' For more information see https://www.mediawiki.org/wiki/API:Errors_and_warnings',
+ '',
+ 'Documentation: https://www.mediawiki.org/wiki/API:Main_page',
+ 'FAQ https://www.mediawiki.org/wiki/API:FAQ',
+ 'Mailing list: https://lists.wikimedia.org/mailman/listinfo/mediawiki-api',
+ 'Api Announcements: https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce',
+ 'Bugs & Requests: https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts',
'',
'',
'',
@@ -769,6 +832,9 @@ class ApiMain extends ApiBase {
);
}
+ /**
+ * @return array
+ */
public function getPossibleErrors() {
return array_merge( parent::getPossibleErrors(), array(
array( 'readonlytext' ),
@@ -781,22 +847,26 @@ class ApiMain extends ApiBase {
/**
* Returns an array of strings with credits for the API
+ * @return array
*/
protected function getCredits() {
return array(
'API developers:',
- ' Roan Kattouw <Firstname>.<Lastname>@home.nl (lead developer Sep 2007-present)',
+ ' Roan Kattouw <Firstname>.<Lastname>@gmail.com (lead developer Sep 2007-present)',
' 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)',
'',
'Please send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org',
- 'or file a bug report at http://bugzilla.wikimedia.org/'
+ 'or file a bug report at https://bugzilla.wikimedia.org/'
);
}
+
/**
* Sets whether the pretty-printer should format *bold* and $italics$
+ *
+ * @param $help bool
*/
public function setHelp( $help = true ) {
$this->mPrinter->setHelp( $help );
@@ -804,34 +874,39 @@ class ApiMain extends ApiBase {
/**
* Override the parent to generate help messages for all available modules.
+ *
+ * @return string
*/
public function makeHelpMsg() {
- global $wgMemc, $wgAPICacheHelp, $wgAPICacheHelpTimeout;
+ global $wgMemc, $wgAPICacheHelpTimeout;
$this->setHelp();
// Get help text from cache if present
$key = wfMemcKey( 'apihelp', $this->getModuleName(),
SpecialVersion::getVersion( 'nodb' ) .
- $this->getMain()->getShowVersions() );
- if ( $wgAPICacheHelp ) {
+ $this->getShowVersions() );
+ if ( $wgAPICacheHelpTimeout > 0 ) {
$cached = $wgMemc->get( $key );
if ( $cached ) {
return $cached;
}
}
$retval = $this->reallyMakeHelpMsg();
- if ( $wgAPICacheHelp ) {
+ if ( $wgAPICacheHelpTimeout > 0 ) {
$wgMemc->set( $key, $retval, $wgAPICacheHelpTimeout );
}
return $retval;
}
+ /**
+ * @return mixed|string
+ */
public function reallyMakeHelpMsg() {
$this->setHelp();
// Use parent to make default message for the main module
$msg = parent::makeHelpMsg();
- $astriks = str_repeat( '*** ', 10 );
+ $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 );
@@ -867,6 +942,11 @@ class ApiMain extends ApiBase {
return $msg;
}
+ /**
+ * @param $module ApiBase
+ * @param $paramName String What type of request is this? e.g. action, query, list, prop, meta, format
+ * @return string
+ */
public static function makeHelpMsgHeader( $module, $paramName ) {
$modulePrefix = $module->getModulePrefix();
if ( strval( $modulePrefix ) !== '' ) {
@@ -876,37 +956,9 @@ class ApiMain extends ApiBase {
return "* $paramName={$module->getModuleName()} $modulePrefix*";
}
- private $mIsBot = null;
- private $mIsSysop = null;
private $mCanApiHighLimits = null;
/**
- * Returns true if the currently logged in user is a bot, false otherwise
- * OBSOLETE, use canApiHighLimits() instead
- */
- public function isBot() {
- if ( !isset( $this->mIsBot ) ) {
- global $wgUser;
- $this->mIsBot = $wgUser->isAllowed( 'bot' );
- }
- return $this->mIsBot;
- }
-
- /**
- * Similar to isBot(), this method returns true if the logged in user is
- * a sysop, and false if not.
- * OBSOLETE, use canApiHighLimits() instead
- */
- public function isSysop() {
- if ( !isset( $this->mIsSysop ) ) {
- global $wgUser;
- $this->mIsSysop = in_array( 'sysop', $wgUser->getGroups() );
- }
-
- return $this->mIsSysop;
- }
-
- /**
* Check whether the current user is allowed to use high limits
* @return bool
*/
@@ -930,11 +982,13 @@ class ApiMain extends ApiBase {
/**
* Returns the version information of this file, plus it includes
* the versions for all files that are not callable proper API modules
+ *
+ * @return array
*/
public function getVersion() {
- $vers = array ();
- $vers[] = 'MediaWiki: ' . SpecialVersion::getVersion() . "\n http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/";
- $vers[] = __CLASS__ . ': $Id: ApiMain.php 76196 2010-11-06 16:11:19Z reedy $';
+ $vers = array();
+ $vers[] = 'MediaWiki: ' . SpecialVersion::getVersion() . "\n https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/";
+ $vers[] = __CLASS__ . ': $Id: ApiMain.php 104449 2011-11-28 15:52:04Z reedy $';
$vers[] = ApiBase::getBaseVersion();
$vers[] = ApiFormatBase::getBaseVersion();
$vers[] = ApiQueryBase::getBaseVersion();
@@ -957,8 +1011,8 @@ class ApiMain extends ApiBase {
* 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 The identifier for this format.
- * @param $fmtClass The class implementing this format.
+ * @param $fmtName string The identifier for this format.
+ * @param $fmtClass ApiFormatBase The class implementing this format.
*/
protected function addFormat( $fmtName, $fmtClass ) {
$this->mFormats[$fmtName] = $fmtClass;
@@ -966,10 +1020,21 @@ class ApiMain extends ApiBase {
/**
* Get the array mapping module names to class names
+ * @return array
*/
function getModules() {
return $this->mModules;
}
+
+ /**
+ * Returns the list of supported formats in form ( 'format' => 'ClassName' )
+ *
+ * @since 1.18
+ * @return array
+ */
+ public function getFormats() {
+ return $this->mFormats;
+ }
}
/**
@@ -989,10 +1054,16 @@ class UsageException extends Exception {
$this->mExtraData = $extradata;
}
+ /**
+ * @return string
+ */
public function getCodeString() {
return $this->mCodestr;
}
+ /**
+ * @return array
+ */
public function getMessageArray() {
$result = array(
'code' => $this->mCodestr,
@@ -1004,6 +1075,9 @@ class UsageException extends Exception {
return $result;
}
+ /**
+ * @return string
+ */
public function __toString() {
return "{$this->getCodeString()}: {$this->getMessage()}";
}
diff --git a/includes/api/ApiMove.php b/includes/api/ApiMove.php
index a93188bf..f15a086c 100644
--- a/includes/api/ApiMove.php
+++ b/includes/api/ApiMove.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 31, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -61,7 +61,7 @@ class ApiMove extends ApiBase {
}
if ( !$fromTitle->exists() ) {
- $this->dieUsageMsg( array( 'notanarticle' ) );
+ $this->dieUsageMsg( 'notanarticle' );
}
$fromTalk = $fromTitle->getTalkPage();
@@ -76,9 +76,9 @@ class ApiMove extends ApiBase {
&& wfFindFile( $toTitle ) )
{
if ( !$params['ignorewarnings'] && $wgUser->isAllowed( 'reupload-shared' ) ) {
- $this->dieUsageMsg( array( 'sharedfile-exists' ) );
+ $this->dieUsageMsg( 'sharedfile-exists' );
} elseif ( !$wgUser->isAllowed( 'reupload-shared' ) ) {
- $this->dieUsageMsg( array( 'cantoverwrite-sharedfile' ) );
+ $this->dieUsageMsg( 'cantoverwrite-sharedfile' );
}
}
@@ -107,15 +107,18 @@ class ApiMove extends ApiBase {
}
}
+ $result = $this->getResult();
+
// Move subpages
if ( $params['movesubpages'] ) {
$r['subpages'] = $this->moveSubpages( $fromTitle, $toTitle,
$params['reason'], $params['noredirect'] );
- $this->getResult()->setIndexedTagName( $r['subpages'], 'subpage' );
+ $result->setIndexedTagName( $r['subpages'], 'subpage' );
+
if ( $params['movetalk'] ) {
$r['subpages-talk'] = $this->moveSubpages( $fromTalk, $toTalk,
$params['reason'], $params['noredirect'] );
- $this->getResult()->setIndexedTagName( $r['subpages-talk'], 'subpage' );
+ $result->setIndexedTagName( $r['subpages-talk'], 'subpage' );
}
}
@@ -132,9 +135,16 @@ class ApiMove extends ApiBase {
$this->setWatch( $watch, $fromTitle, 'watchmoves' );
$this->setWatch( $watch, $toTitle, 'watchmoves' );
- $this->getResult()->addValue( null, $this->getModuleName(), $r );
+ $result->addValue( null, $this->getModuleName(), $r );
}
+ /**
+ * @param Title $fromTitle
+ * @param Title $toTitle
+ * @param $reason
+ * @param $noredirect
+ * @return array
+ */
public function moveSubpages( $fromTitle, $toTitle, $reason, $noredirect ) {
$retval = array();
$success = $fromTitle->moveSubpages( $toTitle, true, $reason, !$noredirect );
@@ -224,13 +234,16 @@ class ApiMove extends ApiBase {
}
public function getPossibleErrors() {
- return array_merge( parent::getPossibleErrors(), array(
- array( 'invalidtitle', 'from' ),
- array( 'nosuchpageid', 'fromid' ),
- array( 'notanarticle' ),
- array( 'invalidtitle', 'to' ),
- array( 'sharedfile-exists' ),
- ) );
+ return array_merge( parent::getPossibleErrors(),
+ $this->getRequireOnlyOneParameterErrorMessages( array( 'from', 'fromid' ) ),
+ array(
+ array( 'invalidtitle', 'from' ),
+ array( 'nosuchpageid', 'fromid' ),
+ array( 'notanarticle' ),
+ array( 'invalidtitle', 'to' ),
+ array( 'sharedfile-exists' ),
+ )
+ );
}
public function needsToken() {
@@ -247,7 +260,11 @@ class ApiMove extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Move';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiMove.php 77192 2010-11-23 22:05:27Z btongminh $';
+ return __CLASS__ . ': $Id: ApiMove.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiOpenSearch.php b/includes/api/ApiOpenSearch.php
index 885766d2..084c9860 100644
--- a/includes/api/ApiOpenSearch.php
+++ b/includes/api/ApiOpenSearch.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 13, 2006
*
@@ -60,7 +60,7 @@ class ApiOpenSearch extends ApiBase {
$searches = PrefixSearch::titleSearch( $search, $limit,
$namespaces );
-
+
// if the content language has variants, try to retrieve fallback results
$fallbackLimit = $limit - count( $searches );
if ( $fallbackLimit > 0 ) {
@@ -116,7 +116,7 @@ class ApiOpenSearch extends ApiBase {
}
public function getDescription() {
- return 'This module implements OpenSearch protocol';
+ return 'Searches the wiki using the OpenSearch protocol';
}
protected function getExamples() {
@@ -125,7 +125,11 @@ class ApiOpenSearch extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Opensearch';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiOpenSearch.php 79720 2011-01-06 14:48:34Z catrope $';
+ return __CLASS__ . ': $Id: ApiOpenSearch.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiPageSet.php b/includes/api/ApiPageSet.php
index 1cb12c07..cf10a9ac 100644
--- a/includes/api/ApiPageSet.php
+++ b/includes/api/ApiPageSet.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 24, 2006
*
@@ -59,6 +59,7 @@ class ApiPageSet extends ApiQueryBase {
* Constructor
* @param $query ApiQuery
* @param $resolveRedirects bool Whether redirects should be resolved
+ * @param $convertTitles bool
*/
public function __construct( $query, $resolveRedirects = false, $convertTitles = false ) {
parent::__construct( $query, 'query' );
@@ -212,7 +213,7 @@ class ApiPageSet extends ApiQueryBase {
/**
* Get a list of redirect resolutions - maps a title to its redirect
* target.
- * @return array prefixed_title (string) => prefixed_title (string)
+ * @return array prefixed_title (string) => Title object
*/
public function getRedirectTitles() {
return $this->mRedirectTitles;
@@ -351,7 +352,7 @@ class ApiPageSet extends ApiQueryBase {
*/
public function populateFromQueryResult( $db, $queryResult ) {
$this->profileIn();
- $this->initFromQueryResult( $db, $queryResult );
+ $this->initFromQueryResult( $queryResult );
$this->profileOut();
}
@@ -430,7 +431,7 @@ class ApiPageSet extends ApiQueryBase {
$this->profileDBOut();
// Hack: get the ns:titles stored in array(ns => array(titles)) format
- $this->initFromQueryResult( $db, $res, $linkBatch->data, true ); // process Titles
+ $this->initFromQueryResult( $res, $linkBatch->data, true ); // process Titles
// Resolve any found redirects
$this->resolvePendingRedirects();
@@ -446,19 +447,25 @@ class ApiPageSet extends ApiQueryBase {
}
$pageids = array_map( 'intval', $pageids ); // paranoia
- $set = array(
- 'page_id' => $pageids
- );
- $db = $this->getDB();
+ $remaining = array_flip( $pageids );
- // Get pageIDs data from the `page` table
- $this->profileDBIn();
- $res = $db->select( 'page', $this->getPageTableFields(), $set,
- __METHOD__ );
- $this->profileDBOut();
+ $pageids = self::getPositiveIntegers( $pageids );
- $remaining = array_flip( $pageids );
- $this->initFromQueryResult( $db, $res, $remaining, false ); // process PageIDs
+ $res = null;
+ if ( count( $pageids ) ) {
+ $set = array(
+ 'page_id' => $pageids
+ );
+ $db = $this->getDB();
+
+ // Get pageIDs data from the `page` table
+ $this->profileDBIn();
+ $res = $db->select( 'page', $this->getPageTableFields(), $set,
+ __METHOD__ );
+ $this->profileDBOut();
+ }
+
+ $this->initFromQueryResult( $res, $remaining, false ); // process PageIDs
// Resolve any found redirects
$this->resolvePendingRedirects();
@@ -467,7 +474,6 @@ class ApiPageSet extends ApiQueryBase {
/**
* Iterate through the result of the query on 'page' table,
* and for each row create and store title object and save any extra fields requested.
- * @param $db Database
* @param $res ResultWrapper DB Query result
* @param $remaining array of either pageID or ns/title elements (optional).
* If given, any missing items will go to $mMissingPageIDs and $mMissingTitles
@@ -475,25 +481,27 @@ class ApiPageSet extends ApiQueryBase {
* If true, treat $remaining as an array of [ns][title]
* If false, treat it as an array of [pageIDs]
*/
- private function initFromQueryResult( $db, $res, &$remaining = null, $processTitles = null ) {
+ private function initFromQueryResult( $res, &$remaining = null, $processTitles = null ) {
if ( !is_null( $remaining ) && is_null( $processTitles ) ) {
ApiBase::dieDebug( __METHOD__, 'Missing $processTitles parameter when $remaining is provided' );
}
- foreach ( $res as $row ) {
- $pageId = intval( $row->page_id );
+ if ( $res ) {
+ foreach ( $res as $row ) {
+ $pageId = intval( $row->page_id );
- // Remove found page from the list of remaining items
- if ( isset( $remaining ) ) {
- if ( $processTitles ) {
- unset( $remaining[$row->page_namespace][$row->page_title] );
- } else {
- unset( $remaining[$pageId] );
+ // Remove found page from the list of remaining items
+ if ( isset( $remaining ) ) {
+ if ( $processTitles ) {
+ unset( $remaining[$row->page_namespace][$row->page_title] );
+ } else {
+ unset( $remaining[$pageId] );
+ }
}
- }
- // Store any extra fields requested by modules
- $this->processDbRow( $row );
+ // Store any extra fields requested by modules
+ $this->processDbRow( $row );
+ }
}
if ( isset( $remaining ) ) {
@@ -535,21 +543,25 @@ class ApiPageSet extends ApiQueryBase {
$pageids = array();
$remaining = array_flip( $revids );
- $tables = array( 'revision', 'page' );
- $fields = array( 'rev_id', 'rev_page' );
- $where = array( 'rev_id' => $revids, 'rev_page = page_id' );
-
- // Get pageIDs data from the `page` table
- $this->profileDBIn();
- $res = $db->select( $tables, $fields, $where, __METHOD__ );
- foreach ( $res as $row ) {
- $revid = intval( $row->rev_id );
- $pageid = intval( $row->rev_page );
- $this->mGoodRevIDs[$revid] = $pageid;
- $pageids[$pageid] = '';
- unset( $remaining[$revid] );
+ $revids = self::getPositiveIntegers( $revids );
+
+ if ( count( $revids ) ) {
+ $tables = array( 'revision', 'page' );
+ $fields = array( 'rev_id', 'rev_page' );
+ $where = array( 'rev_id' => $revids, 'rev_page = page_id' );
+
+ // Get pageIDs data from the `page` table
+ $this->profileDBIn();
+ $res = $db->select( $tables, $fields, $where, __METHOD__ );
+ foreach ( $res as $row ) {
+ $revid = intval( $row->rev_id );
+ $pageid = intval( $row->rev_page );
+ $this->mGoodRevIDs[$revid] = $pageid;
+ $pageids[$pageid] = '';
+ unset( $remaining[$revid] );
+ }
+ $this->profileDBOut();
}
- $this->profileDBOut();
$this->mMissingRevIDs = array_keys( $remaining );
@@ -589,7 +601,7 @@ class ApiPageSet extends ApiQueryBase {
$this->profileDBOut();
// Hack: get the ns:titles stored in array(ns => array(titles)) format
- $this->initFromQueryResult( $db, $res, $linkBatch->data, true );
+ $this->initFromQueryResult( $res, $linkBatch->data, true );
}
}
}
@@ -611,16 +623,17 @@ class ApiPageSet extends ApiQueryBase {
array(
'rd_from',
'rd_namespace',
+ 'rd_fragment',
+ 'rd_interwiki',
'rd_title'
), array( 'rd_from' => array_keys( $this->mPendingRedirectIDs ) ),
__METHOD__
);
$this->profileDBOut();
-
foreach ( $res as $row ) {
$rdfrom = intval( $row->rd_from );
$from = $this->mPendingRedirectIDs[$rdfrom]->getPrefixedText();
- $to = Title::makeTitle( $row->rd_namespace, $row->rd_title )->getPrefixedText();
+ $to = Title::makeTitle( $row->rd_namespace, $row->rd_title, $row->rd_fragment, $row->rd_interwiki );
unset( $this->mPendingRedirectIDs[$rdfrom] );
if ( !isset( $this->mAllPages[$row->rd_namespace][$row->rd_title] ) ) {
$lb->add( $row->rd_namespace, $row->rd_title );
@@ -639,7 +652,7 @@ class ApiPageSet extends ApiQueryBase {
continue;
}
$lb->addObj( $rt );
- $this->mRedirectTitles[$title->getPrefixedText()] = $rt->getPrefixedText();
+ $this->mRedirectTitles[$title->getPrefixedText()] = $rt;
unset( $this->mPendingRedirectIDs[$id] );
}
}
@@ -685,7 +698,6 @@ class ApiPageSet extends ApiQueryBase {
$titleWasConverted = $unconvertedTitle !== $titleObj->getPrefixedText();
}
-
if ( $titleObj->getNamespace() < 0 ) {
// Handle Special and Media pages
$titleObj = $titleObj->fixSpecialName();
@@ -712,6 +724,25 @@ class ApiPageSet extends ApiQueryBase {
return $linkBatch;
}
+ /**
+ * Returns the input array of integers with all values < 0 removed
+ *
+ * @param $array array
+ * @return array
+ */
+ private static function getPositiveIntegers( $array ) {
+ // bug 25734 API: possible issue with revids validation
+ // It seems with a load of revision rows, MySQL gets upset
+ // Remove any < 0 integers, as they can't be valid
+ foreach( $array as $i => $int ) {
+ if ( $int < 0 ) {
+ unset( $array[$i] );
+ }
+ }
+
+ return $array;
+ }
+
protected function getAllowedParams() {
return array(
'titles' => array(
@@ -744,6 +775,6 @@ class ApiPageSet extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiPageSet.php 76196 2010-11-06 16:11:19Z reedy $';
+ return __CLASS__ . ': $Id: ApiPageSet.php 89574 2011-06-06 15:58:55Z reedy $';
}
}
diff --git a/includes/api/ApiParamInfo.php b/includes/api/ApiParamInfo.php
index a2c0bd11..5670b041 100644
--- a/includes/api/ApiParamInfo.php
+++ b/includes/api/ApiParamInfo.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Dec 01, 2007
*
- * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -70,6 +70,7 @@ class ApiParamInfo extends ApiBase {
$obj = new $qmodArr[$qm]( $this, $qm );
$a = $this->getClassInfo( $obj );
$a['name'] = $qm;
+ $a['querytype'] = $queryObj->getModuleType( $qm );
$r['querymodules'][] = $a;
}
$result->setIndexedTagName( $r['querymodules'], 'module' );
@@ -84,11 +85,16 @@ class ApiParamInfo extends ApiBase {
$result->addValue( null, $this->getModuleName(), $r );
}
+ /**
+ * @param $obj ApiBase
+ * @return ApiResult
+ */
function getClassInfo( $obj ) {
$result = $this->getResult();
$retval['classname'] = get_class( $obj );
$retval['description'] = implode( "\n", (array)$obj->getDescription() );
- $retval['examples'] = implode( "\n", (array)$obj->getExamples() );
+ $examples = (array)$obj->getExamples();
+ $retval['examples'] = implode( "\n", $examples );
$retval['version'] = implode( "\n", (array)$obj->getVersion() );
$retval['prefix'] = $obj->getModulePrefix();
@@ -110,6 +116,18 @@ class ApiParamInfo extends ApiBase {
return $retval;
}
+ $retval['helpurls'] = (array)$obj->getHelpUrls();
+ if ( isset( $retval['helpurls'][0] ) && $retval['helpurls'][0] === false ) {
+ $retval['helpurls'] = array();
+ }
+ $result->setIndexedTagName( $retval['helpurls'], 'helpurl' );
+
+ $retval['allexamples'] = $examples;
+ if ( isset( $retval['allexamples'][0] ) && $retval['allexamples'][0] === false ) {
+ $retval['allexamples'] = array();
+ }
+ $result->setIndexedTagName( $retval['allexamples'], 'example' );
+
$retval['parameters'] = array();
$paramDesc = $obj->getFinalParamDescription();
foreach ( $allowedParams as $n => $p ) {
@@ -117,6 +135,26 @@ class ApiParamInfo extends ApiBase {
if ( isset( $paramDesc[$n] ) ) {
$a['description'] = implode( "\n", (array)$paramDesc[$n] );
}
+
+ //handle shorthand
+ if( !is_array( $p ) ) {
+ $p = array(
+ ApiBase::PARAM_DFLT => $p,
+ );
+ }
+
+ //handle missing type
+ if ( !isset( $p[ApiBase::PARAM_TYPE] ) ) {
+ $dflt = isset( $p[ApiBase::PARAM_DFLT] ) ? $p[ApiBase::PARAM_DFLT] : null;
+ if ( is_bool( $dflt ) ) {
+ $p[ApiBase::PARAM_TYPE] = 'boolean';
+ } elseif ( is_string( $dflt ) || is_null( $dflt ) ) {
+ $p[ApiBase::PARAM_TYPE] = 'string';
+ } elseif ( is_int( $dflt ) ) {
+ $p[ApiBase::PARAM_TYPE] = 'integer';
+ }
+ }
+
if ( isset( $p[ApiBase::PARAM_DEPRECATED] ) && $p[ApiBase::PARAM_DEPRECATED] ) {
$a['deprecated'] = '';
}
@@ -124,29 +162,25 @@ class ApiParamInfo extends ApiBase {
$a['required'] = '';
}
- if ( !is_array( $p ) ) {
- if ( is_bool( $p ) ) {
- $a['type'] = 'bool';
- $a['default'] = ( $p ? 'true' : 'false' );
- } elseif ( is_string( $p ) || is_null( $p ) ) {
- $a['type'] = 'string';
- $a['default'] = strval( $p );
- } elseif ( is_int( $p ) ) {
- $a['type'] = 'integer';
- $a['default'] = intval( $p );
- }
- $retval['parameters'][] = $a;
- continue;
- }
-
if ( isset( $p[ApiBase::PARAM_DFLT] ) ) {
- $a['default'] = $p[ApiBase::PARAM_DFLT];
+ $type = $p[ApiBase::PARAM_TYPE];
+ if( $type === 'boolean' ) {
+ $a['default'] = ( $p[ApiBase::PARAM_DFLT] ? 'true' : 'false' );
+ } elseif( $type === 'string' ) {
+ $a['default'] = strval( $p[ApiBase::PARAM_DFLT] );
+ } elseif( $type === 'integer' ) {
+ $a['default'] = intval( $p[ApiBase::PARAM_DFLT] );
+ } else {
+ $a['default'] = $p[ApiBase::PARAM_DFLT];
+ }
}
if ( isset( $p[ApiBase::PARAM_ISMULTI] ) && $p[ApiBase::PARAM_ISMULTI] ) {
$a['multi'] = '';
$a['limit'] = $this->getMain()->canApiHighLimits() ?
- ApiBase::LIMIT_SML2 :
- ApiBase::LIMIT_SML1;
+ ApiBase::LIMIT_SML2 :
+ ApiBase::LIMIT_SML1;
+ $a['lowlimit'] = ApiBase::LIMIT_SML1;
+ $a['highlimit'] = ApiBase::LIMIT_SML2;
}
if ( isset( $p[ApiBase::PARAM_ALLOW_DUPLICATES] ) && $p[ApiBase::PARAM_ALLOW_DUPLICATES] ) {
@@ -175,7 +209,6 @@ class ApiParamInfo extends ApiBase {
// Errors
$retval['errors'] = $this->parseErrors( $obj->getPossibleErrors() );
-
$result->setIndexedTagName( $retval['errors'], 'error' );
return $retval;
@@ -217,7 +250,11 @@ class ApiParamInfo extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Parameter_information';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiParamInfo.php 87170 2011-04-30 16:57:22Z catrope $';
+ return __CLASS__ . ': $Id: ApiParamInfo.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiParse.php b/includes/api/ApiParse.php
index 2d12c233..6212b4ad 100644
--- a/includes/api/ApiParse.php
+++ b/includes/api/ApiParse.php
@@ -1,7 +1,5 @@
<?php
/**
- * API for MediaWiki 1.8+
- *
* Created on Dec 01, 2007
*
* Copyright © 2007 Yuri Astrakhan <Firstname><Lastname>@gmail.com
@@ -33,7 +31,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
* @ingroup API
*/
class ApiParse extends ApiBase {
-
private $section, $text, $pstText = null;
public function __construct( $main, $action ) {
@@ -80,8 +77,10 @@ class ApiParse extends ApiBase {
$redirValues = null;
- if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) {
+ // Return result
+ $result = $this->getResult();
+ if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) {
if ( !is_null( $oldid ) ) {
// Don't use the parser cache
$rev = Revision::newFromID( $oldid );
@@ -96,13 +95,12 @@ class ApiParse extends ApiBase {
$wgTitle = $titleObj;
- //If for some reason the "oldid" is actually the current revision, it may be cached
- if ( $titleObj->getLatestRevID() === $oldid ) {
+ // If for some reason the "oldid" is actually the current revision, it may be cached
+ if ( $titleObj->getLatestRevID() === intval( $oldid ) ) {
$articleObj = new Article( $titleObj, 0 );
$p_result = $this->getParsedSectionOrText( $articleObj, $titleObj, $popts, $pageid,
isset( $prop['wikitext'] ) ) ;
-
} else { // This is an old revision, so get the text differently
$this->text = $rev->getText( Revision::FOR_THIS_USER );
@@ -114,38 +112,45 @@ class ApiParse extends ApiBase {
$p_result = $wgParser->parse( $this->text, $titleObj, $popts );
}
-
} else { // Not $oldid
-
- if ( !is_null ( $pageid ) ) {
- $titleObj = Title::newFromID( $pageid );
-
- if ( !$titleObj ) {
- $this->dieUsageMsg( array( 'nosuchpageid', $pageid ) );
+ if ( $params['redirects'] ) {
+ $reqParams = array(
+ 'action' => 'query',
+ 'redirects' => '',
+ );
+ if ( !is_null ( $pageid ) ) {
+ $reqParams['pageids'] = $pageid;
+ } else { // $page
+ $reqParams['titles'] = $page;
}
- } else { // $page
-
- if ( $params['redirects'] ) {
- $req = new FauxRequest( array(
- 'action' => 'query',
- 'redirects' => '',
- 'titles' => $page
- ) );
- $main = new ApiMain( $req );
- $main->execute();
- $data = $main->getResultData();
- $redirValues = @$data['query']['redirects'];
- $to = $page;
- foreach ( (array)$redirValues as $r ) {
- $to = $r['to'];
- }
- } else {
- $to = $page;
+ $req = new FauxRequest( $reqParams );
+ $main = new ApiMain( $req );
+ $main->execute();
+ $data = $main->getResultData();
+ $redirValues = isset( $data['query']['redirects'] )
+ ? $data['query']['redirects']
+ : array();
+ $to = $page;
+ foreach ( (array)$redirValues as $r ) {
+ $to = $r['to'];
}
$titleObj = Title::newFromText( $to );
- if ( !$titleObj || !$titleObj->exists() ) {
- $this->dieUsage( "The page you specified doesn't exist", 'missingtitle' );
+ } else {
+ if ( !is_null ( $pageid ) ) {
+ $reqParams['pageids'] = $pageid;
+ $titleObj = Title::newFromID( $pageid );
+ } else { // $page
+ $to = $page;
+ $titleObj = Title::newFromText( $to );
+ }
+ }
+ if ( !is_null ( $pageid ) ) {
+ if ( !$titleObj ) {
+ // Still throw nosuchpageid error if pageid was provided
+ $this->dieUsageMsg( array( 'nosuchpageid', $pageid ) );
}
+ } elseif ( !$titleObj || !$titleObj->exists() ) {
+ $this->dieUsage( "The page you specified doesn't exist", 'missingtitle' );
}
$wgTitle = $titleObj;
@@ -157,13 +162,12 @@ class ApiParse extends ApiBase {
$p_result = $this->getParsedSectionOrText( $articleObj, $titleObj, $popts, $pageid,
isset( $prop['wikitext'] ) ) ;
}
-
} else { // Not $oldid, $pageid, $page. Hence based on $text
$this->text = $text;
$titleObj = Title::newFromText( $title );
if ( !$titleObj ) {
- $titleObj = Title::newFromText( 'API' );
+ $this->dieUsageMsg( array( 'invalidtitle', $title ) );
}
$wgTitle = $titleObj;
@@ -177,20 +181,25 @@ class ApiParse extends ApiBase {
if ( $params['onlypst'] ) {
// Build a result and bail out
$result_array['text'] = array();
- $this->getResult()->setContent( $result_array['text'], $this->pstText );
+ $result->setContent( $result_array['text'], $this->pstText );
if ( isset( $prop['wikitext'] ) ) {
$result_array['wikitext'] = array();
- $this->getResult()->setContent( $result_array['wikitext'], $this->text );
+ $result->setContent( $result_array['wikitext'], $this->text );
}
- $this->getResult()->addValue( null, $this->getModuleName(), $result_array );
+ $result->addValue( null, $this->getModuleName(), $result_array );
return;
}
$p_result = $wgParser->parse( $params['pst'] ? $this->pstText : $this->text, $titleObj, $popts );
}
- // Return result
- $result = $this->getResult();
$result_array = array();
+
+ $result_array['title'] = $titleObj->getPrefixedText();
+
+ if ( !is_null( $oldid ) ) {
+ $result_array['revid'] = intval( $oldid );
+ }
+
if ( $params['redirects'] && !is_null( $redirValues ) ) {
$result_array['redirects'] = $redirValues;
}
@@ -244,31 +253,30 @@ class ApiParse extends ApiBase {
}
if ( isset( $prop['headitems'] ) || isset( $prop['headhtml'] ) ) {
- $out = new OutputPage;
- $out->addParserOutputNoText( $p_result );
- $userSkin = $wgUser->getSkin();
- }
+ $context = new RequestContext;
+ $context->getOutput()->addParserOutputNoText( $p_result );
- if ( isset( $prop['headitems'] ) ) {
- $headItems = $this->formatHeadItems( $p_result->getHeadItems() );
+ if ( isset( $prop['headitems'] ) ) {
+ $headItems = $this->formatHeadItems( $p_result->getHeadItems() );
- $userSkin->setupUserCss( $out );
- $css = $this->formatCss( $out->buildCssLinksArray() );
+ $context->getSkin()->setupUserCss( $context->getOutput() );
+ $css = $this->formatCss( $context->getOutput()->buildCssLinksArray() );
- $scripts = array( $out->getHeadScripts( $userSkin ) );
+ $scripts = array( $context->getOutput()->getHeadScripts( $context->getSkin() ) );
- $result_array['headitems'] = array_merge( $headItems, $css, $scripts );
- }
+ $result_array['headitems'] = array_merge( $headItems, $css, $scripts );
+ }
- if ( isset( $prop['headhtml'] ) ) {
- $result_array['headhtml'] = array();
- $result->setContent( $result_array['headhtml'], $out->headElement( $userSkin ) );
+ if ( isset( $prop['headhtml'] ) ) {
+ $result_array['headhtml'] = array();
+ $result->setContent( $result_array['headhtml'], $context->getOutput()->headElement( $context->getSkin() ) );
+ }
}
if ( isset( $prop['iwlinks'] ) ) {
$result_array['iwlinks'] = $this->formatIWLinks( $p_result->getInterwikiLinks() );
}
-
+
if ( isset( $prop['wikitext'] ) ) {
$result_array['wikitext'] = array();
$result->setContent( $result_array['wikitext'], $this->text );
@@ -278,10 +286,6 @@ class ApiParse extends ApiBase {
}
}
- if ( !is_null( $oldid ) ) {
- $result_array['revid'] = intval( $oldid );
- }
-
$result_mapping = array(
'redirects' => 'r',
'langlinks' => 'll',
@@ -303,11 +307,11 @@ class ApiParse extends ApiBase {
}
/**
- * @param $articleObj Article
- * @param $titleObj Title
- * @param $popts ParserOptions
- * @param $pageId Int
- * @param $getWikitext Bool
+ * @param $articleObj Article
+ * @param $titleObj Title
+ * @param $popts ParserOptions
+ * @param $pageId Int
+ * @param $getWikitext Bool
* @return ParserOutput
*/
private function getParsedSectionOrText( $articleObj, $titleObj, $popts, $pageId = null, $getWikitext = false ) {
@@ -346,10 +350,10 @@ class ApiParse extends ApiBase {
$entry = array();
$bits = explode( ':', $link, 2 );
$title = Title::newFromText( $link );
-
+
$entry['lang'] = $bits[0];
if ( $title ) {
- $entry['url'] = $title->getFullURL();
+ $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
}
$this->getResult()->setContent( $entry, $bits[1] );
$result[] = $entry;
@@ -369,17 +373,41 @@ class ApiParse extends ApiBase {
}
private function categoriesHtml( $categories ) {
- global $wgOut, $wgUser;
- $wgOut->addCategoryLinks( $categories );
- $sk = $wgUser->getSkin();
- return $sk->getCategories();
+ $context = $this->createContext();
+ $context->getOutput()->addCategoryLinks( $categories );
+ return $context->getSkin()->getCategories();
}
+ /**
+ * @deprecated since 1.18 No modern skin generates language links this way, please use language links
+ * data to generate your own HTML.
+ */
private function languagesHtml( $languages ) {
- global $wgOut, $wgUser;
- $wgOut->setLanguageLinks( $languages );
- $sk = $wgUser->getSkin();
- return $sk->otherLanguages();
+ global $wgContLang, $wgHideInterlanguageLinks;
+
+ if ( $wgHideInterlanguageLinks || count( $languages ) == 0 ) {
+ return '';
+ }
+
+ $s = htmlspecialchars( wfMsg( 'otherlanguages' ) . wfMsg( 'colon-separator' ) );
+
+ $langs = array();
+ foreach ( $languages as $l ) {
+ $nt = Title::newFromText( $l );
+ $text = $wgContLang->getLanguageName( $nt->getInterwiki() );
+
+ $langs[] = Html::element( 'a',
+ array( 'href' => $nt->getFullURL(), 'title' => $nt->getText(), 'class' => "external" ),
+ $text == '' ? $l : $text );
+ }
+
+ $s .= implode( htmlspecialchars( wfMsgExt( 'pipe-separator', 'escapenoentities' ) ), $langs );
+
+ if ( $wgContLang->isRTL() ) {
+ $s = Html::rawElement( 'span', array( 'dir' => "LTR" ), $s );
+ }
+
+ return $s;
}
private function formatLinks( $links ) {
@@ -407,7 +435,7 @@ class ApiParse extends ApiBase {
$title = Title::newFromText( "{$prefix}:{$title}" );
if ( $title ) {
- $entry['url'] = $title->getFullURL();
+ $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
}
$this->getResult()->setContent( $entry, $title->getFullText() );
@@ -455,9 +483,13 @@ class ApiParse extends ApiBase {
'text' => null,
'summary' => null,
'page' => null,
- 'pageid' => null,
+ 'pageid' => array(
+ ApiBase::PARAM_TYPE => 'integer',
+ ),
'redirects' => false,
- 'oldid' => null,
+ 'oldid' => array(
+ ApiBase::PARAM_TYPE => 'integer',
+ ),
'prop' => array(
ApiBase::PARAM_DFLT => 'text|langlinks|categories|links|templates|images|externallinks|sections|revid|displaytitle',
ApiBase::PARAM_ISMULTI => true,
@@ -493,7 +525,7 @@ class ApiParse extends ApiBase {
return array(
'text' => 'Wikitext to parse',
'summary' => 'Summary to parse',
- 'redirects' => "If the {$p}page parameter is set to a redirect, resolve it",
+ 'redirects' => "If the {$p}page or the {$p}pageid parameter is set to a redirect, resolve it",
'title' => 'Title of page the text belongs to',
'page' => "Parse the content of this page. Cannot be used together with {$p}text and {$p}title",
'pageid' => "Parse the content of this page. Overrides {$p}page",
@@ -501,16 +533,16 @@ class ApiParse extends ApiBase {
'prop' => array(
'Which pieces of information to get',
' text - Gives the parsed text of the wikitext',
- ' langlinks - Gives the langlinks the parsed wikitext',
- ' categories - Gives the categories of the parsed wikitext',
- ' categorieshtml - Gives the html version of the categories',
- ' languageshtml - Gives the html version of the languagelinks',
+ ' langlinks - Gives the language links in the parsed wikitext',
+ ' categories - Gives the categories in the parsed wikitext',
+ ' categorieshtml - Gives the HTML version of the categories',
+ ' languageshtml - Gives the HTML version of the language links',
' links - Gives the internal links in the parsed wikitext',
' templates - Gives the templates in the parsed wikitext',
' images - Gives the images in the parsed wikitext',
' externallinks - Gives the external links in the parsed wikitext',
' sections - Gives the sections in the parsed wikitext',
- ' revid - Adds the revision id of the parsed page',
+ ' revid - Adds the revision ID of the parsed page',
' displaytitle - Adds the title of the parsed wikitext',
' headitems - Gives items to put in the <head> of the page',
' headhtml - Gives parsed <head> of the page',
@@ -532,7 +564,7 @@ class ApiParse extends ApiBase {
}
public function getDescription() {
- return 'This module parses wikitext and returns parser output';
+ return 'Parses wikitext and returns parser output';
}
public function getPossibleErrors() {
@@ -543,6 +575,7 @@ class ApiParse extends ApiBase {
array( 'code' => 'missingtitle', 'info' => 'The page you specified doesn\'t exist' ),
array( 'code' => 'nosuchsection', 'info' => 'There is no section sectionnumber in page' ),
array( 'nosuchpageid' ),
+ array( 'invalidtitle', 'title' ),
) );
}
@@ -552,7 +585,11 @@ class ApiParse extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Parsing_wikitext#parse';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiParse.php 89672 2011-06-07 18:45:20Z catrope $';
+ return __CLASS__ . ': $Id: ApiParse.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiPatrol.php b/includes/api/ApiPatrol.php
index 08835743..8066e655 100644
--- a/includes/api/ApiPatrol.php
+++ b/includes/api/ApiPatrol.php
@@ -42,13 +42,15 @@ class ApiPatrol extends ApiBase {
* Patrols the article or provides the reason the patrol failed.
*/
public function execute() {
+ global $wgUser;
+
$params = $this->extractRequestParams();
$rc = RecentChange::newFromID( $params['rcid'] );
if ( !$rc instanceof RecentChange ) {
$this->dieUsageMsg( array( 'nosuchrcid', $params['rcid'] ) );
}
- $retval = RecentChange::markPatrolled( $params['rcid'] );
+ $retval = $rc->doMarkPatrolled( $wgUser );
if ( $retval ) {
$this->dieUsageMsg( reset( $retval ) );
@@ -108,7 +110,11 @@ class ApiPatrol extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Patrol';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiPatrol.php 78437 2010-12-15 14:14:16Z catrope $';
+ return __CLASS__ . ': $Id: ApiPatrol.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiProtect.php b/includes/api/ApiProtect.php
index 3a1d18e0..5556262e 100644
--- a/includes/api/ApiProtect.php
+++ b/includes/api/ApiProtect.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 1, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -63,6 +63,7 @@ class ApiProtect extends ApiBase {
}
$restrictionTypes = $titleObj->getRestrictionTypes();
+ $dbr = wfGetDB( DB_SLAVE );
$protections = array();
$expiryarray = array();
@@ -72,10 +73,10 @@ class ApiProtect extends ApiBase {
$protections[$p[0]] = ( $p[1] == 'all' ? '' : $p[1] );
if ( $titleObj->exists() && $p[0] == 'create' ) {
- $this->dieUsageMsg( array( 'create-titleexists' ) );
+ $this->dieUsageMsg( 'create-titleexists' );
}
if ( !$titleObj->exists() && $p[0] != 'create' ) {
- $this->dieUsageMsg( array( 'missingtitle-createonly' ) );
+ $this->dieUsageMsg( 'missingtitle-createonly' );
}
if ( !in_array( $p[0], $restrictionTypes ) && $p[0] != 'create' ) {
@@ -86,7 +87,7 @@ class ApiProtect extends ApiBase {
}
if ( in_array( $expiry[$i], array( 'infinite', 'indefinite', 'never' ) ) ) {
- $expiryarray[$p[0]] = Block::infinity();
+ $expiryarray[$p[0]] = $dbr->getInfinity();
} else {
$exp = strtotime( $expiry[$i] );
if ( $exp < 0 || !$exp ) {
@@ -100,7 +101,7 @@ class ApiProtect extends ApiBase {
$expiryarray[$p[0]] = $exp;
}
$resultProtections[] = array( $p[0] => $protections[$p[0]],
- 'expiry' => ( $expiryarray[$p[0]] == Block::infinity() ?
+ 'expiry' => ( $expiryarray[$p[0]] == $dbr->getInfinity() ?
'infinite' :
wfTimestamp( TS_ISO_8601, $expiryarray[$p[0]] ) ) );
}
@@ -129,8 +130,9 @@ class ApiProtect extends ApiBase {
$res['cascade'] = '';
}
$res['protections'] = $resultProtections;
- $this->getResult()->setIndexedTagName( $res['protections'], 'protection' );
- $this->getResult()->addValue( null, $this->getModuleName(), $res );
+ $result = $this->getResult();
+ $result->setIndexedTagName( $res['protections'], 'protection' );
+ $result->addValue( null, $this->getModuleName(), $res );
}
public function mustBePosted() {
@@ -222,7 +224,11 @@ class ApiProtect extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Protect';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiProtect.php 77192 2010-11-23 22:05:27Z btongminh $';
+ return __CLASS__ . ': $Id: ApiProtect.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiPurge.php b/includes/api/ApiPurge.php
index a17abf16..bdf911cb 100644
--- a/includes/api/ApiPurge.php
+++ b/includes/api/ApiPurge.php
@@ -49,6 +49,9 @@ class ApiPurge extends ApiBase {
!$this->getMain()->getRequest()->wasPosted() ) {
$this->dieUsageMsg( array( 'mustbeposted', $this->getModuleName() ) );
}
+
+ $forceLinkUpdate = $params['forcelinkupdate'];
+
$result = array();
foreach ( $params['titles'] as $t ) {
$r = array();
@@ -65,13 +68,39 @@ class ApiPurge extends ApiBase {
$result[] = $r;
continue;
}
- $article = MediaWiki::articleFromTitle( $title );
+ $context = $this->createContext();
+ $context->setTitle( $title );
+ $article = Article::newFromTitle( $title, $context );
$article->doPurge(); // Directly purge and skip the UI part of purge().
$r['purged'] = '';
+
+ if( $forceLinkUpdate ) {
+ if ( !$wgUser->pingLimiter() ) {
+ global $wgParser, $wgEnableParserCache;
+ $popts = new ParserOptions();
+ $p_result = $wgParser->parse( $article->getContent(), $title, $popts );
+
+ # Update the links tables
+ $u = new LinksUpdate( $title, $p_result );
+ $u->doUpdate();
+
+ $r['linkupdate'] = '';
+
+ if ( $wgEnableParserCache ) {
+ $pcache = ParserCache::singleton();
+ $pcache->save( $p_result, $article, $popts );
+ }
+ } else {
+ $this->setWarning( $this->parseMsg( array( 'actionthrottledtext' ) ) );
+ $forceLinkUpdate = false;
+ }
+ }
+
$result[] = $r;
}
- $this->getResult()->setIndexedTagName( $result, 'page' );
- $this->getResult()->addValue( null, $this->getModuleName(), $result );
+ $apiResult = $this->getResult();
+ $apiResult->setIndexedTagName( $result, 'page' );
+ $apiResult->addValue( null, $this->getModuleName(), $result );
}
public function isWriteMode() {
@@ -83,19 +112,21 @@ class ApiPurge extends ApiBase {
'titles' => array(
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_REQUIRED => true
- )
+ ),
+ 'forcelinkupdate' => false,
);
}
public function getParamDescription() {
return array(
'titles' => 'A list of titles',
+ 'forcelinkupdate' => 'Update the links tables',
);
}
public function getDescription() {
return array( 'Purge the cache for the given titles.',
- 'This module requires a POST request if the user is not logged in.'
+ 'Requires a POST request if the user is not logged in.'
);
}
@@ -111,7 +142,11 @@ class ApiPurge extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Purge';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiPurge.php 74944 2010-10-18 09:19:20Z catrope $';
+ return __CLASS__ . ': $Id: ApiPurge.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php
index f88aa850..49fd8569 100644
--- a/includes/api/ApiQuery.php
+++ b/includes/api/ApiQuery.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 7, 2006
*
@@ -43,8 +43,13 @@ if ( !defined( 'MEDIAWIKI' ) ) {
class ApiQuery extends ApiBase {
private $mPropModuleNames, $mListModuleNames, $mMetaModuleNames;
+
+ /**
+ * @var ApiPageSet
+ */
private $mPageSet;
- private $params, $redirects, $convertTitles;
+
+ private $params, $redirects, $convertTitles, $iwUrl;
private $mQueryPropModules = array(
'info' => 'ApiQueryInfo',
@@ -77,6 +82,7 @@ class ApiQuery extends ApiBase {
'filearchive' => 'ApiQueryFilearchive',
'imageusage' => 'ApiQueryBacklinks',
'iwbacklinks' => 'ApiQueryIWBacklinks',
+ 'langbacklinks' => 'ApiQueryLangBacklinks',
'logevents' => 'ApiQueryLogEvents',
'recentchanges' => 'ApiQueryRecentChanges',
'search' => 'ApiQuerySearch',
@@ -88,6 +94,7 @@ class ApiQuery extends ApiBase {
'users' => 'ApiQueryUsers',
'random' => 'ApiQueryRandom',
'protectedtitles' => 'ApiQueryProtectedTitles',
+ 'querypage' => 'ApiQueryQueryPage',
);
private $mQueryMetaModules = array(
@@ -184,15 +191,15 @@ class ApiQuery extends ApiBase {
* @return mixed string or null
*/
function getModuleType( $moduleName ) {
- if ( array_key_exists ( $moduleName, $this->mQueryPropModules ) ) {
+ if ( isset( $this->mQueryPropModules[$moduleName] ) ) {
return 'prop';
}
- if ( array_key_exists ( $moduleName, $this->mQueryListModules ) ) {
+ if ( isset( $this->mQueryListModules[$moduleName] ) ) {
return 'list';
}
- if ( array_key_exists ( $moduleName, $this->mQueryMetaModules ) ) {
+ if ( isset( $this->mQueryMetaModules[$moduleName] ) ) {
return 'meta';
}
@@ -225,6 +232,7 @@ class ApiQuery extends ApiBase {
$this->params = $this->extractRequestParams();
$this->redirects = $this->params['redirects'];
$this->convertTitles = $this->params['converttitles'];
+ $this->iwUrl = $this->params['iwurl'];
// Create PageSet
$this->mPageSet = new ApiPageSet( $this, $this->redirects, $this->convertTitles );
@@ -272,6 +280,8 @@ class ApiQuery extends ApiBase {
* Update a cache mode string, applying the cache mode of a new module to it.
* The cache mode may increase in the level of privacy, but public modules
* added to private data do not decrease the level of privacy.
+ *
+ * @return string
*/
protected function mergeCacheMode( $cacheMode, $modCacheMode ) {
if ( $modCacheMode === 'anon-public-user-private' ) {
@@ -307,9 +317,8 @@ class ApiQuery extends ApiBase {
* @param $moduleList Array array(modulename => classname)
*/
private function instantiateModules( &$modules, $param, $moduleList ) {
- $list = @$this->params[$param];
- if ( !is_null ( $list ) ) {
- foreach ( $list as $moduleName ) {
+ if ( isset( $this->params[$param] ) ) {
+ foreach ( $this->params[$param] as $moduleName ) {
$modules[] = new $moduleList[$moduleName] ( $this, $moduleName );
}
}
@@ -359,10 +368,15 @@ class ApiQuery extends ApiBase {
// Interwiki titles
$intrwValues = array();
foreach ( $pageSet->getInterwikiTitles() as $rawTitleStr => $interwikiStr ) {
- $intrwValues[] = array(
+ $item = array(
'title' => $rawTitleStr,
- 'iw' => $interwikiStr
+ 'iw' => $interwikiStr,
);
+ if ( $this->iwUrl ) {
+ $title = Title::newFromText( $rawTitleStr );
+ $item['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
+ }
+ $intrwValues[] = $item;
}
if ( count( $intrwValues ) ) {
@@ -372,11 +386,15 @@ class ApiQuery extends ApiBase {
// Show redirect information
$redirValues = array();
- foreach ( $pageSet->getRedirectTitles() as $titleStrFrom => $titleStrTo ) {
- $redirValues[] = array(
+ foreach ( $pageSet->getRedirectTitles() as $titleStrFrom => $titleTo ) {
+ $r = array(
'from' => strval( $titleStrFrom ),
- 'to' => $titleStrTo
+ 'to' => $titleTo->getPrefixedText(),
);
+ if ( $titleTo->getFragment() !== '' ) {
+ $r['tofragment'] = $titleTo->getFragment();
+ }
+ $redirValues[] = $r;
}
if ( count( $redirValues ) ) {
@@ -424,7 +442,7 @@ class ApiQuery extends ApiBase {
ApiQueryBase::addTitleInfo( $vals, $title );
$vals['special'] = '';
if ( $title->getNamespace() == NS_SPECIAL &&
- !SpecialPage::exists( $title->getDbKey() ) ) {
+ !SpecialPageFactory::exists( $title->getDbKey() ) ) {
$vals['missing'] = '';
} elseif ( $title->getNamespace() == NS_MEDIA &&
!wfFindFile( $title ) ) {
@@ -465,17 +483,13 @@ class ApiQuery extends ApiBase {
private function doExport( $pageSet, $result ) {
$exportTitles = array();
$titles = $pageSet->getGoodTitles();
- if( count( $titles ) ) {
+ if ( count( $titles ) ) {
foreach ( $titles as $title ) {
if ( $title->userCanRead() ) {
$exportTitles[] = $title;
}
}
}
- // only export when there are titles
- if ( !count( $exportTitles ) ) {
- return;
- }
$exporter = new WikiExporter( $this->getDB() );
// WikiExporter writes to stdout, so catch its
@@ -578,6 +592,7 @@ class ApiQuery extends ApiBase {
'indexpageids' => false,
'export' => false,
'exportnowrap' => false,
+ 'iwurl' => false,
);
}
@@ -586,16 +601,14 @@ class ApiQuery extends ApiBase {
* @return string
*/
public function makeHelpMsg() {
- $msg = '';
-
// Make sure the internal object is empty
// (just in case a sub-module decides to optimize during instantiation)
$this->mPageSet = null;
$this->mAllowedGenerators = array(); // Will be repopulated
- $querySeparator = str_repeat( '--- ', 8 );
- $moduleSeparator = str_repeat( '*** ', 10 );
- $msg .= "\n$querySeparator Query: Prop $querySeparator\n\n";
+ $querySeparator = str_repeat( '--- ', 12 );
+ $moduleSeparator = str_repeat( '*** ', 14 );
+ $msg = "\n$querySeparator Query: Prop $querySeparator\n\n";
$msg .= $this->makeHelpMsgHelper( $this->mQueryPropModules, 'prop' );
$msg .= "\n$querySeparator Query: List $querySeparator\n\n";
$msg .= $this->makeHelpMsgHelper( $this->mQueryListModules, 'list' );
@@ -621,7 +634,7 @@ class ApiQuery extends ApiBase {
$moduleDescriptions = array();
foreach ( $moduleList as $moduleName => $moduleClass ) {
- $module = new $moduleClass ( $this, $moduleName, null );
+ $module = new $moduleClass( $this, $moduleName, null );
$msg = ApiMain::makeHelpMsgHeader( $module, $paramName );
$msg2 = $module->makeHelpMsg();
@@ -664,6 +677,7 @@ class ApiQuery extends ApiBase {
'indexpageids' => 'Include an additional pageids section listing all returned page IDs',
'export' => 'Export the current revisions of all given or generated pages',
'exportnowrap' => 'Return the export XML without wrapping it in an XML result (same format as Special:Export). Can only be used with export',
+ 'iwurl' => 'Whether to get the full URL if the title is an interwiki link',
);
}
@@ -688,10 +702,18 @@ class ApiQuery extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return array(
+ 'https://www.mediawiki.org/wiki/API:Meta',
+ 'https://www.mediawiki.org/wiki/API:Properties',
+ 'https://www.mediawiki.org/wiki/API:Lists',
+ );
+ }
+
public function getVersion() {
$psModule = new ApiPageSet( $this );
$vers = array();
- $vers[] = __CLASS__ . ': $Id: ApiQuery.php 80897 2011-01-24 18:57:42Z catrope $';
+ $vers[] = __CLASS__ . ': $Id: ApiQuery.php 104449 2011-11-28 15:52:04Z reedy $';
$vers[] = $psModule->getVersion();
return $vers;
}
diff --git a/includes/api/ApiQueryAllCategories.php b/includes/api/ApiQueryAllCategories.php
index c1473252..c7f4b0aa 100644
--- a/includes/api/ApiQueryAllCategories.php
+++ b/includes/api/ApiQueryAllCategories.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on December 12, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,6 +53,10 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$db = $this->getDB();
$params = $this->extractRequestParams();
@@ -65,6 +69,10 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase {
$to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
$this->addWhereRange( 'cat_title', $dir, $from, $to );
+ $min = $params['min'];
+ $max = $params['max'];
+ $this->addWhereRange( 'cat_pages', $dir, $min, $max );
+
if ( isset( $params['prefix'] ) ) {
$this->addWhere( 'cat_title' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
}
@@ -144,6 +152,14 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase {
'descending'
),
),
+ 'min' => array(
+ ApiBase::PARAM_DFLT => null,
+ ApiBase::PARAM_TYPE => 'integer'
+ ),
+ 'max' => array(
+ ApiBase::PARAM_DFLT => null,
+ ApiBase::PARAM_TYPE => 'integer'
+ ),
'limit' => array(
ApiBase::PARAM_DFLT => 10,
ApiBase::PARAM_TYPE => 'limit',
@@ -165,6 +181,8 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase {
'to' => 'The category to stop enumerating at',
'prefix' => 'Search for all category titles that begin with this value',
'dir' => 'Direction to sort in',
+ 'min' => 'Minimum number of category members',
+ 'max' => 'Maximum number of category members',
'limit' => 'How many categories to return',
'prop' => array(
'Which properties to get',
@@ -185,7 +203,11 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Allcategories';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllCategories.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryAllCategories.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryAllLinks.php b/includes/api/ApiQueryAllLinks.php
index 78784845..90620e91 100644
--- a/includes/api/ApiQueryAllLinks.php
+++ b/includes/api/ApiQueryAllLinks.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on July 7, 2007
*
@@ -52,6 +52,10 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$db = $this->getDB();
$params = $this->extractRequestParams();
@@ -90,27 +94,22 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
);
}
- if ( !is_null( $params['from'] ) ) {
- $this->addWhere( 'pl_title>=' . $db->addQuotes( $this->titlePartToKey( $params['from'] ) ) );
- }
- if ( !is_null( $params['to'] ) ) {
- $this->addWhere( 'pl_title<=' . $db->addQuotes( $this->titlePartToKey( $params['to'] ) ) );
- }
+ $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) );
+ $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
+ $this->addWhereRange( 'pl_title', 'newer', $from, $to );
+
if ( isset( $params['prefix'] ) ) {
$this->addWhere( 'pl_title' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
}
- $this->addFields( array(
- 'pl_title',
- ) );
+ $this->addFields( 'pl_title' );
$this->addFieldsIf( 'pl_from', !$params['unique'] );
$this->addOption( 'USE INDEX', 'pl_namespace' );
$limit = $params['limit'];
$this->addOption( 'LIMIT', $limit + 1 );
- if ( $params['unique'] ) {
- $this->addOption( 'ORDER BY', 'pl_title' );
- } else {
+
+ if ( !$params['unique'] ) {
$this->addOption( 'ORDER BY', 'pl_title, pl_from' );
}
@@ -228,7 +227,11 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Alllinks';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllLinks.php 77192 2010-11-23 22:05:27Z btongminh $';
+ return __CLASS__ . ': $Id: ApiQueryAllLinks.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php
index 77f507fc..c0984d95 100644
--- a/includes/api/ApiQueryAllUsers.php
+++ b/includes/api/ApiQueryAllUsers.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on July 7, 2007
*
@@ -49,67 +49,119 @@ class ApiQueryAllUsers extends ApiQueryBase {
$fld_blockinfo = isset( $prop['blockinfo'] );
$fld_editcount = isset( $prop['editcount'] );
$fld_groups = isset( $prop['groups'] );
+ $fld_rights = isset( $prop['rights'] );
$fld_registration = isset( $prop['registration'] );
+ $fld_implicitgroups = isset( $prop['implicitgroups'] );
} else {
- $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = $fld_rights = false;
+ $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration = $fld_rights = $fld_implicitgroups = false;
}
$limit = $params['limit'];
- $this->addTables( 'user', 'u1' );
+
+ $this->addTables( 'user' );
$useIndex = true;
- if ( !is_null( $params['from'] ) ) {
- $this->addWhere( 'u1.user_name >= ' . $db->addQuotes( $this->keyToTitle( $params['from'] ) ) );
+ $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
+ $from = is_null( $params['from'] ) ? null : $this->keyToTitle( $params['from'] );
+ $to = is_null( $params['to'] ) ? null : $this->keyToTitle( $params['to'] );
+
+ $this->addWhereRange( 'user_name', $dir, $from, $to );
+
+ if ( !is_null( $params['prefix'] ) ) {
+ $this->addWhere( 'user_name' . $db->buildLike( $this->keyToTitle( $params['prefix'] ), $db->anyString() ) );
}
- if ( !is_null( $params['to'] ) ) {
- $this->addWhere( 'u1.user_name <= ' . $db->addQuotes( $this->keyToTitle( $params['to'] ) ) );
+
+ if ( !is_null( $params['rights'] ) ) {
+ $groups = array();
+ foreach( $params['rights'] as $r ) {
+ $groups = array_merge( $groups, User::getGroupsWithPermission( $r ) );
+ }
+
+ $groups = array_unique( $groups );
+
+ if ( is_null( $params['group'] ) ) {
+ $params['group'] = $groups;
+ } else {
+ $params['group'] = array_unique( array_merge( $params['group'], $groups ) );
+ }
}
- if ( !is_null( $params['prefix'] ) ) {
- $this->addWhere( 'u1.user_name' . $db->buildLike( $this->keyToTitle( $params['prefix'] ), $db->anyString() ) );
+ if ( !is_null( $params['group'] ) && !is_null( $params['excludegroup'] ) ) {
+ $this->dieUsage( 'group and excludegroup cannot be used together', 'group-excludegroup' );
}
- if ( !is_null( $params['group'] ) ) {
+ if ( !is_null( $params['group'] ) && count( $params['group'] ) ) {
$useIndex = false;
// Filter only users that belong to a given group
$this->addTables( 'user_groups', 'ug1' );
- $ug1 = $this->getAliasedName( 'user_groups', 'ug1' );
- $this->addJoinConds( array( $ug1 => array( 'INNER JOIN', array( 'ug1.ug_user=u1.user_id',
+ $this->addJoinConds( array( 'ug1' => array( 'INNER JOIN', array( 'ug1.ug_user=user_id',
'ug1.ug_group' => $params['group'] ) ) ) );
}
+ if ( !is_null( $params['excludegroup'] ) && count( $params['excludegroup'] ) ) {
+ $useIndex = false;
+ // Filter only users don't belong to a given group
+ $this->addTables( 'user_groups', 'ug1' );
+
+ if ( count( $params['excludegroup'] ) == 1 ) {
+ $exclude = array( 'ug1.ug_group' => $params['excludegroup'][0] );
+ } else {
+ $exclude = array( $db->makeList( array( 'ug1.ug_group' => $params['excludegroup'] ), LIST_OR ) );
+ }
+ $this->addJoinConds( array( 'ug1' => array( 'LEFT OUTER JOIN',
+ array_merge( array( 'ug1.ug_user=user_id' ), $exclude )
+ )
+ ) );
+ $this->addWhere( 'ug1.ug_user IS NULL' );
+ }
+
if ( $params['witheditsonly'] ) {
- $this->addWhere( 'u1.user_editcount > 0' );
+ $this->addWhere( 'user_editcount > 0' );
}
- if ( $fld_groups ) {
+ $this->showHiddenUsersAddBlockInfo( $fld_blockinfo );
+
+ if ( $fld_groups || $fld_rights ) {
// Show the groups the given users belong to
// request more than needed to avoid not getting all rows that belong to one user
$groupCount = count( User::getAllGroups() );
$sqlLimit = $limit + $groupCount + 1;
$this->addTables( 'user_groups', 'ug2' );
- $tname = $this->getAliasedName( 'user_groups', 'ug2' );
- $this->addJoinConds( array( $tname => array( 'LEFT JOIN', 'ug2.ug_user=u1.user_id' ) ) );
+ $this->addJoinConds( array( 'ug2' => array( 'LEFT JOIN', 'ug2.ug_user=user_id' ) ) );
$this->addFields( 'ug2.ug_group ug_group2' );
} else {
$sqlLimit = $limit + 1;
}
- $this->showHiddenUsersAddBlockInfo( $fld_blockinfo );
+
+ if ( $params['activeusers'] ) {
+ global $wgActiveUserDays;
+ $this->addTables( 'recentchanges' );
+
+ $this->addJoinConds( array( 'recentchanges' => array(
+ 'INNER JOIN', 'rc_user_text=user_name'
+ ) ) );
+
+ $this->addFields( 'COUNT(*) AS recentedits' );
+
+ $this->addWhere( "rc_log_type IS NULL OR rc_log_type != 'newusers'" );
+ $timestamp = $db->timestamp( wfTimestamp( TS_UNIX ) - $wgActiveUserDays*24*3600 );
+ $this->addWhere( "rc_timestamp >= {$db->addQuotes( $timestamp )}" );
+
+ $this->addOption( 'GROUP BY', 'user_name' );
+ }
$this->addOption( 'LIMIT', $sqlLimit );
$this->addFields( array(
- 'u1.user_name',
- 'u1.user_id'
+ 'user_name',
+ 'user_id'
) );
- $this->addFieldsIf( 'u1.user_editcount', $fld_editcount );
- $this->addFieldsIf( 'u1.user_registration', $fld_registration );
+ $this->addFieldsIf( 'user_editcount', $fld_editcount );
+ $this->addFieldsIf( 'user_registration', $fld_registration );
- $this->addOption( 'ORDER BY', 'u1.user_name' );
if ( $useIndex ) {
- $u1 = $this->getAliasedName( 'user', 'u1' );
- $this->addOption( 'USE INDEX', array( $u1 => 'user_name' ) );
+ $this->addOption( 'USE INDEX', array( 'user' => 'user_name' ) );
}
$res = $this->select( __METHOD__ );
@@ -153,12 +205,13 @@ class ApiQueryAllUsers extends ApiQueryBase {
// Record new user's data
$lastUser = $row->user_name;
$lastUserData = array(
- 'name' => $lastUser,
'userid' => $row->user_id,
+ 'name' => $lastUser,
);
- if ( $fld_blockinfo && !is_null( $row->blocker_name ) ) {
- $lastUserData['blockedby'] = $row->blocker_name;
+ if ( $fld_blockinfo && !is_null( $row->ipb_by_text ) ) {
+ $lastUserData['blockedby'] = $row->ipb_by_text;
$lastUserData['blockreason'] = $row->ipb_reason;
+ $lastUserData['blockexpiry'] = $row->ipb_expiry;
}
if ( $row->ipb_deleted ) {
$lastUserData['hidden'] = '';
@@ -166,11 +219,13 @@ class ApiQueryAllUsers extends ApiQueryBase {
if ( $fld_editcount ) {
$lastUserData['editcount'] = intval( $row->user_editcount );
}
+ if ( $params['activeusers'] ) {
+ $lastUserData['recenteditcount'] = intval( $row->recentedits );
+ }
if ( $fld_registration ) {
$lastUserData['registration'] = $row->user_registration ?
wfTimestamp( TS_ISO_8601, $row->user_registration ) : '';
}
-
}
if ( $sqlLimit == $count ) {
@@ -181,10 +236,31 @@ class ApiQueryAllUsers extends ApiQueryBase {
}
// Add user's group info
- if ( $fld_groups && !is_null( $row->ug_group2 ) ) {
- $lastUserData['groups'][] = $row->ug_group2;
+ if ( $fld_groups ) {
+ if ( !isset( $lastUserData['groups'] ) ) {
+ $lastUserData['groups'] = ApiQueryUsers::getAutoGroups( User::newFromName( $lastUser ) );
+ }
+
+ if ( !is_null( $row->ug_group2 ) ) {
+ $lastUserData['groups'][] = $row->ug_group2;
+ }
$result->setIndexedTagName( $lastUserData['groups'], 'g' );
}
+
+ if ( $fld_implicitgroups && !isset( $lastUserData['implicitgroups'] ) ) {
+ $lastUserData['implicitgroups'] = ApiQueryUsers::getAutoGroups( User::newFromName( $lastUser ) );
+ $result->setIndexedTagName( $lastUserData['implicitgroups'], 'g' );
+ }
+ if ( $fld_rights ) {
+ if ( !isset( $lastUserData['rights'] ) ) {
+ $lastUserData['rights'] = User::getGroupPermissions( User::newFromName( $lastUser )->getAutomaticGroups() );
+ }
+ if ( !is_null( $row->ug_group2 ) ) {
+ $lastUserData['rights'] = array_unique( array_merge( $lastUserData['rights'],
+ User::getGroupPermissions( array( $row->ug_group2 ) ) ) );
+ }
+ $result->setIndexedTagName( $lastUserData['rights'], 'r' );
+ }
}
if ( is_array( $lastUserData ) ) {
@@ -204,18 +280,37 @@ class ApiQueryAllUsers extends ApiQueryBase {
}
public function getAllowedParams() {
+ $userGroups = User::getAllGroups();
return array(
'from' => null,
'to' => null,
'prefix' => null,
+ 'dir' => array(
+ ApiBase::PARAM_DFLT => 'ascending',
+ ApiBase::PARAM_TYPE => array(
+ 'ascending',
+ 'descending'
+ ),
+ ),
'group' => array(
- ApiBase::PARAM_TYPE => User::getAllGroups()
+ ApiBase::PARAM_TYPE => $userGroups,
+ ApiBase::PARAM_ISMULTI => true,
+ ),
+ 'excludegroup' => array(
+ ApiBase::PARAM_TYPE => $userGroups,
+ ApiBase::PARAM_ISMULTI => true,
+ ),
+ 'rights' => array(
+ ApiBase::PARAM_TYPE => User::getAllRights(),
+ ApiBase::PARAM_ISMULTI => true,
),
'prop' => array(
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => array(
'blockinfo',
'groups',
+ 'implicitgroups',
+ 'rights',
'editcount',
'registration'
)
@@ -228,24 +323,32 @@ class ApiQueryAllUsers extends ApiQueryBase {
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
),
'witheditsonly' => false,
+ 'activeusers' => false,
);
}
public function getParamDescription() {
+ global $wgActiveUserDays;
return array(
'from' => 'The user name to start enumerating from',
'to' => 'The user name to stop enumerating at',
'prefix' => 'Search for all users that begin with this value',
- 'group' => 'Limit users to a given group name',
+ 'dir' => 'Direction to sort in',
+ 'group' => 'Limit users to given group name(s)',
+ 'excludegroup' => 'Exclude users in given group name(s)',
+ 'rights' => 'Limit users to given right(s)',
'prop' => array(
'What pieces of information to include.',
- ' blockinfo - Adds the information about a current block on the user',
- ' groups - Lists groups that the user is in',
- ' editcount - Adds the edit count of the user',
- ' registration - Adds the timestamp of when the user registered',
- '`groups` property uses more server resources and may return fewer results than the limit' ),
+ ' blockinfo - Adds the information about a current block on the user',
+ ' groups - Lists groups that the user is in. This uses more server resources and may return fewer results than the limit',
+ ' implicitgroups - Lists all the groups the user is automatically in',
+ ' rights - Lists rights that the user has',
+ ' editcount - Adds the edit count of the user',
+ ' registration - Adds the timestamp of when the user registered if available (may be blank)',
+ ),
'limit' => 'How many total user names to return',
'witheditsonly' => 'Only list users who have made edits',
+ 'activeusers' => "Only list users active in the last {$wgActiveUserDays} days(s)"
);
}
@@ -253,13 +356,23 @@ class ApiQueryAllUsers extends ApiQueryBase {
return 'Enumerate all registered users';
}
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(), array(
+ array( 'code' => 'group-excludegroup', 'info' => 'group and excludegroup cannot be used together' ),
+ ) );
+ }
+
protected function getExamples() {
return array(
'api.php?action=query&list=allusers&aufrom=Y',
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Allusers';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllUsers.php 85354 2011-04-04 18:25:31Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryAllUsers.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryAllimages.php b/includes/api/ApiQueryAllimages.php
index a7825519..cafff871 100644
--- a/includes/api/ApiQueryAllimages.php
+++ b/includes/api/ApiQueryAllimages.php
@@ -38,16 +38,19 @@ if ( !defined( 'MEDIAWIKI' ) ) {
*/
class ApiQueryAllimages extends ApiQueryGeneratorBase {
+ protected $mRepo;
+
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'ai' );
$this->mRepo = RepoGroup::singleton()->getLocalRepo();
}
/**
- * Overide parent method to make sure to make sure the repo's DB is used
+ * Override parent method to make sure to make sure the repo's DB is used
* which may not necesarilly be the same as the local DB.
*
* TODO: allow querying non-local repos.
+ * @return DatabaseBase
*/
protected function getDB() {
return $this->mRepo->getSlaveDB();
@@ -61,6 +64,10 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
return 'public';
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
public function executeGenerator( $resultPageSet ) {
if ( $resultPageSet->isResolvingRedirects() ) {
$this->dieUsage( 'Use "gaifilterredir=nonredirects" option instead of "redirects" when using allimages as a generator', 'params' );
@@ -69,6 +76,10 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$repo = $this->mRepo;
if ( !$repo instanceof LocalRepo ) {
@@ -98,12 +109,30 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
$sha1 = false;
if ( isset( $params['sha1'] ) ) {
+ if ( !$this->validateSha1Hash( $params['sha1'] ) ) {
+ $this->dieUsage( 'The SHA1 hash provided is not valid', 'invalidsha1hash' );
+ }
$sha1 = wfBaseConvert( $params['sha1'], 16, 36, 31 );
} elseif ( isset( $params['sha1base36'] ) ) {
$sha1 = $params['sha1base36'];
+ if ( !$this->validateSha1Base36Hash( $sha1 ) ) {
+ $this->dieUsage( 'The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash' );
+ }
}
if ( $sha1 ) {
- $this->addWhere( 'img_sha1=' . $db->addQuotes( $sha1 ) );
+ $this->addWhereFld( 'img_sha1', $sha1 );
+ }
+
+ if ( !is_null( $params['mime'] ) ) {
+ global $wgMiserMode;
+ if ( $wgMiserMode ) {
+ $this->dieUsage( 'MIME search disabled in Miser Mode', 'mimesearchdisabled' );
+ }
+
+ list( $major, $minor ) = File::splitMime( $params['mime'] );
+
+ $this->addWhereFld( 'img_major_mime', $major );
+ $this->addWhereFld( 'img_minor_mime', $minor );
}
$this->addTables( 'image' );
@@ -133,6 +162,8 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
$file = $repo->newFileFromRow( $row );
$info = array_merge( array( 'name' => $row->img_name ),
ApiQueryImageInfo::getInfo( $file, $prop, $result ) );
+ self::addTitleInfo( $info, $file->getTitle() );
+
$fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $info );
if ( !$fit ) {
$this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->img_name ) );
@@ -178,10 +209,11 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
'sha1' => null,
'sha1base36' => null,
'prop' => array(
- ApiBase::PARAM_TYPE => ApiQueryImageInfo::getPropertyNames(),
+ ApiBase::PARAM_TYPE => ApiQueryImageInfo::getPropertyNames( $this->propertyFilter ),
ApiBase::PARAM_DFLT => 'timestamp|url',
ApiBase::PARAM_ISMULTI => true
- )
+ ),
+ 'mime' => null,
);
}
@@ -196,24 +228,13 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
'limit' => 'How many images in total to return',
'sha1' => "SHA1 hash of image. Overrides {$this->getModulePrefix()}sha1base36",
'sha1base36' => 'SHA1 hash of image in base 36 (used in MediaWiki)',
- 'prop' => array(
- 'Which properties to get',
- ' timestamp - Adds the timestamp when the image was upload',
- ' user - Adds the username of the last uploader',
- ' userid - Adds the user id of the last uploader',
- ' comment - Adds the comment of the last upload',
- ' url - Adds the URL of the image and its description page',
- ' size - Adds the size of the image in bytes and its height and width',
- ' dimensions - Alias of size',
- ' sha1 - Adds the sha1 of the image',
- ' mime - Adds the MIME of the image',
- ' thumbmime - Adds the MIME of the tumbnail for the image',
- ' archivename - Adds the file name of the archive version for non-latest versions',
- ' bitdepth - Adds the bit depth of the version',
- ),
+ 'prop' => ApiQueryImageInfo::getPropertyDescriptions( $this->propertyFilter ),
+ 'mime' => 'What MIME type to search for. e.g. image/jpeg. Disabled in Miser Mode',
);
}
+ private $propertyFilter = array( 'archivename' );
+
public function getDescription() {
return 'Enumerate all images sequentially';
}
@@ -222,6 +243,9 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
return array_merge( parent::getPossibleErrors(), array(
array( 'code' => 'params', 'info' => 'Use "gaifilterredir=nonredirects" option instead of "redirects" when using allimages as a generator' ),
array( 'code' => 'unsupportedrepo', 'info' => 'Local file repository does not support querying all images' ),
+ array( 'code' => 'mimesearchdisabled', 'info' => 'MIME search disabled in Miser Mode' ),
+ array( 'code' => 'invalidsha1hash', 'info' => 'The SHA1 hash provided is not valid' ),
+ array( 'code' => 'invalidsha1base36hash', 'info' => 'The SHA1Base36 hash provided is not valid' ),
) );
}
@@ -236,7 +260,11 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Allimages';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllimages.php 71838 2010-08-28 01:18:18Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryAllimages.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryAllmessages.php b/includes/api/ApiQueryAllmessages.php
index 81ff255a..a26011bc 100644
--- a/includes/api/ApiQueryAllmessages.php
+++ b/includes/api/ApiQueryAllmessages.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Dec 1, 2007
*
@@ -43,12 +43,22 @@ class ApiQueryAllmessages extends ApiQueryBase {
public function execute() {
$params = $this->extractRequestParams();
- global $wgLang;
+ if ( is_null( $params['lang'] ) ) {
+ global $wgLang;
+ $langObj = $wgLang;
+ } else {
+ $langObj = Language::factory( $params['lang'] );
+ }
- $oldLang = null;
- if ( !is_null( $params['lang'] ) ) {
- $oldLang = $wgLang; // Keep $wgLang for restore later
- $wgLang = Language::factory( $params['lang'] );
+ if ( $params['enableparser'] ) {
+ if ( !is_null( $params['title'] ) ) {
+ $title = Title::newFromText( $params['title'] );
+ if ( !$title ) {
+ $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+ }
+ } else {
+ $title = Title::newFromText( 'API' );
+ }
}
$prop = array_flip( (array)$params['prop'] );
@@ -62,7 +72,26 @@ class ApiQueryAllmessages extends ApiQueryBase {
$messages_target = $params['messages'];
}
- // Filter messages
+ // Filter messages that have the specified prefix
+ // Because we sorted the message array earlier, they will appear in a clump:
+ if ( isset( $params['prefix'] ) ) {
+ $skip = false;
+ $messages_filtered = array();
+ foreach ( $messages_target as $message ) {
+ // === 0: must be at beginning of string (position 0)
+ if ( strpos( $message, $params['prefix'] ) === 0 ) {
+ if( !$skip ) {
+ $skip = true;
+ }
+ $messages_filtered[] = $message;
+ } elseif ( $skip ) {
+ break;
+ }
+ }
+ $messages_target = $messages_filtered;
+ }
+
+ // Filter messages that contain specified string
if ( isset( $params['filter'] ) ) {
$messages_filtered = array();
foreach ( $messages_target as $message ) {
@@ -74,6 +103,18 @@ class ApiQueryAllmessages extends ApiQueryBase {
$messages_target = $messages_filtered;
}
+ // Whether we have any sort of message customisation filtering
+ $customiseFilterEnabled = $params['customised'] !== 'all';
+ if ( $customiseFilterEnabled ) {
+ global $wgContLang;
+ $lang = $langObj->getCode();
+
+ $customisedMessages = AllmessagesTablePager::getCustomisedStatuses(
+ array_map( array( $langObj, 'ucfirst'), $messages_target ), $lang, $lang != $wgContLang->getCode() );
+
+ $customised = $params['customised'] === 'modified';
+ }
+
// Get all requested messages and print the result
$skip = !is_null( $params['from'] );
$useto = !is_null( $params['to'] );
@@ -83,39 +124,47 @@ class ApiQueryAllmessages extends ApiQueryBase {
if ( $skip && $message === $params['from'] ) {
$skip = false;
}
-
- if( $useto && $message > $params['to'] ) {
+
+ if ( $useto && $message > $params['to'] ) {
break;
}
if ( !$skip ) {
$a = array( 'name' => $message );
- $args = null;
+ $args = array();
if ( isset( $params['args'] ) && count( $params['args'] ) != 0 ) {
$args = $params['args'];
}
- // Check if the parser is enabled:
- if ( $params['enableparser'] ) {
- $msg = wfMsgExt( $message, array( 'parsemag' ), $args );
- } elseif ( $args ) {
- $msgString = wfMsgGetKey( $message, true, false, false );
- $msg = wfMsgReplaceArgs( $msgString, $args );
- } else {
- $msg = wfMsgGetKey( $message, true, false, false );
+
+ if ( $customiseFilterEnabled ) {
+ $messageIsCustomised = isset( $customisedMessages['pages'][ $langObj->ucfirst( $message ) ] );
+ if ( $customised === $messageIsCustomised ) {
+ if ( $customised ) {
+ $a['customised'] = '';
+ }
+ } else {
+ continue;
+ }
}
- if ( wfEmptyMsg( $message, $msg ) ) {
+ $msg = wfMessage( $message, $args )->inLanguage( $langObj );
+
+ if ( !$msg->exists() ) {
$a['missing'] = '';
} else {
- ApiResult::setContent( $a, $msg );
+ // Check if the parser is enabled:
+ if ( $params['enableparser'] ) {
+ $msgString = $msg->title( $title )->text();
+ } else {
+ $msgString = $msg->plain();
+ }
+ ApiResult::setContent( $a, $msgString );
if ( isset( $prop['default'] ) ) {
- $default = wfMsgGetKey( $message, false, false, false );
- if ( $default !== $msg ) {
- if ( wfEmptyMsg( $message, $default ) ) {
- $a['defaultmissing'] = '';
- } else {
- $a['default'] = $default;
- }
+ $default = wfMessage( $message )->inLanguage( $langObj )->useDatabase( false );
+ if ( !$default->exists() ) {
+ $a['defaultmissing'] = '';
+ } elseif ( $default->plain() != $msgString ) {
+ $a['default'] = $default->plain();
}
}
}
@@ -127,10 +176,6 @@ class ApiQueryAllmessages extends ApiQueryBase {
}
}
$result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'message' );
-
- if ( !is_null( $oldLang ) ) {
- $wgLang = $oldLang; // Restore $oldLang
- }
}
public function getCacheMode( $params ) {
@@ -160,23 +205,37 @@ class ApiQueryAllmessages extends ApiQueryBase {
),
'enableparser' => false,
'args' => array(
- ApiBase::PARAM_ISMULTI => true
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_ALLOW_DUPLICATES => true,
),
'filter' => array(),
+ 'customised' => array(
+ ApiBase::PARAM_DFLT => 'all',
+ ApiBase::PARAM_TYPE => array(
+ 'all',
+ 'modified',
+ 'unmodified'
+ )
+ ),
'lang' => null,
'from' => null,
'to' => null,
+ 'title' => null,
+ 'prefix' => null,
);
}
public function getParamDescription() {
return array(
- 'messages' => 'Which messages to output. "*" means all messages',
+ 'messages' => 'Which messages to output. "*" (default) means all messages',
'prop' => 'Which properties to get',
'enableparser' => array( 'Set to enable parser, will preprocess the wikitext of message',
'Will substitute magic words, handle templates etc.' ),
+ 'title' => 'Page name to use as context when parsing message (for enableparser option)',
'args' => 'Arguments to be substituted into message',
- 'filter' => 'Return only messages that contain this string',
+ 'prefix' => 'Return messages with this prefix',
+ 'filter' => 'Return only messages with names that contain this string',
+ 'customised' => 'Return only messages in this customisation state',
'lang' => 'Return messages in this language',
'from' => 'Return messages starting at this message',
'to' => 'Return messages ending at this message',
@@ -189,12 +248,16 @@ class ApiQueryAllmessages extends ApiQueryBase {
protected function getExamples() {
return array(
- 'api.php?action=query&meta=allmessages&amfilter=ipb-',
+ 'api.php?action=query&meta=allmessages&amprefix=ipb-',
'api.php?action=query&meta=allmessages&ammessages=august|mainpage&amlang=de',
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Meta#allmessages_.2F_am';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllmessages.php 73756 2010-09-25 17:08:23Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryAllmessages.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryAllpages.php b/includes/api/ApiQueryAllpages.php
index 21f72916..42928418 100644
--- a/includes/api/ApiQueryAllpages.php
+++ b/includes/api/ApiQueryAllpages.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 25, 2006
*
@@ -48,6 +48,10 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
return 'public';
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
public function executeGenerator( $resultPageSet ) {
if ( $resultPageSet->isResolvingRedirects() ) {
$this->dieUsage( 'Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator', 'params' );
@@ -56,6 +60,10 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$db = $this->getDB();
@@ -75,7 +83,7 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
$from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) );
$to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
$this->addWhereRange( 'page_title', $dir, $from, $to );
-
+
if ( isset( $params['prefix'] ) ) {
$this->addWhere( 'page_title' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
}
@@ -103,30 +111,38 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
}
// Page protection filtering
- if ( !empty( $params['prtype'] ) ) {
+ if ( count( $params['prtype'] ) || $params['prexpiry'] != 'all' ) {
$this->addTables( 'page_restrictions' );
$this->addWhere( 'page_id=pr_page' );
$this->addWhere( 'pr_expiry>' . $db->addQuotes( $db->timestamp() ) );
- $this->addWhereFld( 'pr_type', $params['prtype'] );
- if ( isset( $params['prlevel'] ) ) {
- // Remove the empty string and '*' from the prlevel array
- $prlevel = array_diff( $params['prlevel'], array( '', '*' ) );
+ if ( count( $params['prtype'] ) ) {
+ $this->addWhereFld( 'pr_type', $params['prtype'] );
- if ( !empty( $prlevel ) ) {
- $this->addWhereFld( 'pr_level', $prlevel );
- }
- }
- if ( $params['prfiltercascade'] == 'cascading' ) {
- $this->addWhereFld( 'pr_cascade', 1 );
- } elseif ( $params['prfiltercascade'] == 'noncascading' ) {
- $this->addWhereFld( 'pr_cascade', 0 );
- }
+ if ( isset( $params['prlevel'] ) ) {
+ // Remove the empty string and '*' from the prlevel array
+ $prlevel = array_diff( $params['prlevel'], array( '', '*' ) );
- $this->addOption( 'DISTINCT' );
+ if ( count( $prlevel ) ) {
+ $this->addWhereFld( 'pr_level', $prlevel );
+ }
+ }
+ if ( $params['prfiltercascade'] == 'cascading' ) {
+ $this->addWhereFld( 'pr_cascade', 1 );
+ } elseif ( $params['prfiltercascade'] == 'noncascading' ) {
+ $this->addWhereFld( 'pr_cascade', 0 );
+ }
+ $this->addOption( 'DISTINCT' );
+ }
$forceNameTitleIndex = false;
+ if ( $params['prexpiry'] == 'indefinite' ) {
+ $this->addWhere( "pr_expiry = {$db->addQuotes( $db->getInfinity() )} OR pr_expiry IS NULL" );
+ } elseif ( $params['prexpiry'] == 'definite' ) {
+ $this->addWhere( "pr_expiry != {$db->addQuotes( $db->getInfinity() )}" );
+ }
+
} elseif ( isset( $params['prlevel'] ) ) {
$this->dieUsage( 'prlevel may not be used without prtype', 'params' );
}
@@ -248,7 +264,15 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
'all'
),
ApiBase::PARAM_DFLT => 'all'
- )
+ ),
+ 'prexpiry' => array(
+ ApiBase::PARAM_TYPE => array(
+ 'indefinite',
+ 'definite',
+ 'all'
+ ),
+ ApiBase::PARAM_DFLT => 'all'
+ ),
);
}
@@ -267,7 +291,13 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
'prlevel' => "The protection level (must be used with {$p}prtype= parameter)",
'prfiltercascade' => "Filter protections based on cascadingness (ignored when {$p}prtype isn't set)",
'filterlanglinks' => 'Filter based on whether a page has langlinks',
- 'limit' => 'How many total pages to return.'
+ 'limit' => 'How many total pages to return.',
+ 'prexpiry' => array(
+ 'Which protection expiry to filter the page on',
+ ' indefinite - Get only pages with indefinite protection expiry',
+ ' definite - Get only pages with a definite (specific) protection expiry',
+ ' all - Get pages with any protections expiry'
+ ),
);
}
@@ -295,7 +325,11 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Allpages';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllpages.php 85354 2011-04-04 18:25:31Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryAllpages.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryBacklinks.php b/includes/api/ApiQueryBacklinks.php
index b412d2d6..472406ac 100644
--- a/includes/api/ApiQueryBacklinks.php
+++ b/includes/api/ApiQueryBacklinks.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 16, 2006
*
@@ -39,26 +39,44 @@ if ( !defined( 'MEDIAWIKI' ) ) {
*/
class ApiQueryBacklinks extends ApiQueryGeneratorBase {
- private $params, $rootTitle, $contID, $redirID, $redirect;
+ /**
+ * @var Title
+ */
+ private $rootTitle;
+
+ private $params, $contID, $redirID, $redirect;
private $bl_ns, $bl_from, $bl_table, $bl_code, $bl_title, $bl_sort, $bl_fields, $hasNS;
- private $pageMap, $resultArr;
+
+ /**
+ * Maps ns and title to pageid
+ *
+ * @var array
+ */
+ private $pageMap = array();
+ private $resultArr;
+
+ private $redirTitles = array();
+ private $continueStr = null;
// output element name, database column field prefix, database table
private $backlinksSettings = array(
'backlinks' => array(
'code' => 'bl',
'prefix' => 'pl',
- 'linktbl' => 'pagelinks'
+ 'linktbl' => 'pagelinks',
+ 'helpurl' => 'https://www.mediawiki.org/wiki/API:Backlinks',
),
'embeddedin' => array(
'code' => 'ei',
'prefix' => 'tl',
- 'linktbl' => 'templatelinks'
+ 'linktbl' => 'templatelinks',
+ 'helpurl' => 'https://www.mediawiki.org/wiki/API:Embeddedin',
),
'imageusage' => array(
'code' => 'iu',
'prefix' => 'il',
- 'linktbl' => 'imagelinks'
+ 'linktbl' => 'imagelinks',
+ 'helpurl' => 'https://www.mediawiki.org/wiki/API:Imageusage',
)
);
@@ -73,6 +91,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
$this->bl_from = $prefix . '_from';
$this->bl_table = $settings['linktbl'];
$this->bl_code = $code;
+ $this->helpUrl = $settings['helpurl'];
$this->hasNS = $moduleName !== 'imageusage';
if ( $this->hasNS ) {
@@ -103,6 +122,10 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function prepareFirstQuery( $resultPageSet = null ) {
/* SELECT page_id, page_title, page_namespace, page_is_redirect
* FROM pagelinks, page WHERE pl_from=page_id
@@ -141,6 +164,10 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
$this->addOption( 'STRAIGHT_JOIN' );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function prepareSecondQuery( $resultPageSet = null ) {
/* SELECT page_id, page_title, page_namespace, page_is_redirect, pl_title, pl_namespace
FROM pagelinks, page WHERE pl_from=page_id
@@ -199,14 +226,21 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
$this->addOption( 'USE INDEX', array( 'page' => 'PRIMARY' ) );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$this->params = $this->extractRequestParams( false );
$this->redirect = isset( $this->params['redirect'] ) && $this->params['redirect'];
$userMax = ( $this->redirect ? ApiBase::LIMIT_BIG1 / 2 : ApiBase::LIMIT_BIG1 );
$botMax = ( $this->redirect ? ApiBase::LIMIT_BIG2 / 2 : ApiBase::LIMIT_BIG2 );
+
+ $result = $this->getResult();
+
if ( $this->params['limit'] == 'max' ) {
$this->params['limit'] = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
- $this->getResult()->setParsedLimit( $this->getModuleName(), $this->params['limit'] );
+ $result->setParsedLimit( $this->getModuleName(), $this->params['limit'] );
}
$this->processContinue();
@@ -215,9 +249,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
$res = $this->select( __METHOD__ . '::firstQuery' );
$count = 0;
- $this->pageMap = array(); // Maps ns and title to pageid
- $this->continueStr = null;
- $this->redirTitles = array();
+
foreach ( $res as $row ) {
if ( ++ $count > $this->params['limit'] ) {
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
@@ -248,9 +280,9 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
// We need to keep the parent page of this redir in
if ( $this->hasNS ) {
- $parentID = $this->pageMap[$row->{$this->bl_ns}][$row->{$this->bl_title}];
+ $parentID = $this->pageMap[$row-> { $this->bl_ns } ][$row-> { $this->bl_title } ];
} else {
- $parentID = $this->pageMap[NS_IMAGE][$row->{$this->bl_title}];
+ $parentID = $this->pageMap[NS_IMAGE][$row-> { $this->bl_title } ];
}
$this->continueStr = $this->getContinueRedirStr( $parentID, $row->page_id );
break;
@@ -265,13 +297,13 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
}
if ( is_null( $resultPageSet ) ) {
// Try to add the result data in one go and pray that it fits
- $fit = $this->getResult()->addValue( 'query', $this->getModuleName(), array_values( $this->resultArr ) );
+ $fit = $result->addValue( 'query', $this->getModuleName(), array_values( $this->resultArr ) );
if ( !$fit ) {
// It didn't fit. Add elements one by one until the
// result is full.
foreach ( $this->resultArr as $pageID => $arr ) {
// Add the basic entry without redirlinks first
- $fit = $this->getResult()->addValue(
+ $fit = $result->addValue(
array( 'query', $this->getModuleName() ),
null, array_diff_key( $arr, array( 'redirlinks' => '' ) ) );
if ( !$fit ) {
@@ -280,8 +312,9 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
}
$hasRedirs = false;
- foreach ( (array)@$arr['redirlinks'] as $key => $redir ) {
- $fit = $this->getResult()->addValue(
+ $redirLinks = isset( $arr['redirlinks'] ) ? $arr['redirlinks'] : array();
+ foreach ( (array)$redirLinks as $key => $redir ) {
+ $fit = $result->addValue(
array( 'query', $this->getModuleName(), $pageID, 'redirlinks' ),
$key, $redir );
if ( !$fit ) {
@@ -291,7 +324,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
$hasRedirs = true;
}
if ( $hasRedirs ) {
- $this->getResult()->setIndexedTagName_internal(
+ $result->setIndexedTagName_internal(
array( 'query', $this->getModuleName(), $pageID, 'redirlinks' ),
$this->bl_code );
}
@@ -301,7 +334,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
}
}
- $this->getResult()->setIndexedTagName_internal(
+ $result->setIndexedTagName_internal(
array( 'query', $this->getModuleName() ),
$this->bl_code
);
@@ -383,9 +416,10 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
$this->dieUsage( 'Invalid continue param. You should pass the original value returned by the previous query', '_badcontinue' );
}
$this->contID = $contID;
- $redirID = intval( @$continueList[3] );
+ $id2 = isset( $continueList[3] ) ? $continueList[3] : null;
+ $redirID = intval( $id2 );
- if ( $redirID === 0 && @$continueList[3] !== '0' ) {
+ if ( $redirID === 0 && $id2 !== '0' ) {
// This one isn't required
return;
}
@@ -496,7 +530,11 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
return $examples[$this->getModuleName()];
}
+ public function getHelpUrls() {
+ return $this->helpUrl;
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryBacklinks.php 75921 2010-11-03 12:49:21Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryBacklinks.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php
index 61a5b4c8..69e0a893 100644
--- a/includes/api/ApiQueryBase.php
+++ b/includes/api/ApiQueryBase.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 7, 2006
*
@@ -54,6 +54,8 @@ abstract class ApiQueryBase extends ApiBase {
*
* Public caching will only be allowed if *all* the modules that supply
* data for a given request return a cache mode of public.
+ *
+ * @return string
*/
public function getCacheMode( $params ) {
return 'private';
@@ -84,23 +86,14 @@ abstract class ApiQueryBase extends ApiBase {
$this->tables = array_merge( $this->tables, $tables );
} else {
if ( !is_null( $alias ) ) {
- $tables = $this->getAliasedName( $tables, $alias );
+ $this->tables[$alias] = $tables;
+ } else {
+ $this->tables[] = $tables;
}
- $this->tables[] = $tables;
}
}
/**
- * Get the SQL for a table name with alias
- * @param $table string Table name
- * @param $alias string Alias
- * @return string SQL
- */
- protected function getAliasedName( $table, $alias ) {
- return $this->getDB()->tableName( $table ) . ' ' . $alias;
- }
-
- /**
* Add a set of JOIN conditions to the internal array
*
* JOIN conditions are formatted as array( tablename => array(jointype,
@@ -118,7 +111,7 @@ abstract class ApiQueryBase extends ApiBase {
/**
* Add a set of fields to select to the internal array
- * @param $value mixed Field name or array of field names
+ * @param $value array|string Field name or array of field names
*/
protected function addFields( $value ) {
if ( is_array( $value ) ) {
@@ -130,7 +123,7 @@ abstract class ApiQueryBase extends ApiBase {
/**
* Same as addFields(), but add the fields only if a condition is met
- * @param $value mixed See addFields()
+ * @param $value array|string See addFields()
* @param $condition bool If false, do nothing
* @return bool $condition
*/
@@ -227,6 +220,16 @@ abstract class ApiQueryBase extends ApiBase {
}
}
}
+ /**
+ * Add a WHERE clause corresponding to a range, similar to addWhereRange,
+ * but converts $start and $end to database timestamps.
+ * @see addWhereRange
+ */
+ protected function addTimestampWhereRange( $field, $dir, $start, $end, $sort = true ) {
+ $db = $this->getDb();
+ return $this->addWhereRange( $field, $dir,
+ $db->timestampOrNull( $start ), $db->timestampOrNull( $end ), $sort );
+ }
/**
* Add an option such as LIMIT or USE INDEX. If an option was set
@@ -359,14 +362,15 @@ abstract class ApiQueryBase extends ApiBase {
protected function setContinueEnumParameter( $paramName, $paramValue ) {
$paramName = $this->encodeParamName( $paramName );
$msg = array( $paramName => $paramValue );
- $this->getResult()->disableSizeCheck();
- $this->getResult()->addValue( 'query-continue', $this->getModuleName(), $msg );
- $this->getResult()->enableSizeCheck();
+ $result = $this->getResult();
+ $result->disableSizeCheck();
+ $result->addValue( 'query-continue', $this->getModuleName(), $msg );
+ $result->enableSizeCheck();
}
/**
* Get the Query database connection (read-only)
- * @return Database
+ * @return DatabaseBase
*/
protected function getDB() {
if ( is_null( $this->mDb ) ) {
@@ -450,6 +454,47 @@ abstract class ApiQueryBase extends ApiBase {
}
/**
+ * Gets the personalised direction parameter description
+ *
+ * @param string $p ModulePrefix
+ * @param string $extraDirText Any extra text to be appended on the description
+ * @return array
+ */
+ public function getDirectionDescription( $p = '', $extraDirText = '' ) {
+ return array(
+ "In which direction to enumerate{$extraDirText}",
+ " newer - List oldest first. Note: {$p}start has to be before {$p}end.",
+ " older - List newest first (default). Note: {$p}start has to be later than {$p}end.",
+ );
+ }
+
+ /**
+ * @param $query String
+ * @param $protocol String
+ * @return null|string
+ */
+ public function prepareUrlQuerySearchString( $query = null, $protocol = null) {
+ $db = $this->getDb();
+ if ( !is_null( $query ) || $query != '' ) {
+ if ( is_null( $protocol ) ) {
+ $protocol = 'http://';
+ }
+
+ $likeQuery = LinkFilter::makeLikeArray( $query, $protocol );
+ if ( !$likeQuery ) {
+ $this->dieUsage( 'Invalid query', 'bad_query' );
+ }
+
+ $likeQuery = LinkFilter::keepOneWildcard( $likeQuery );
+ return 'el_index ' . $db->buildLike( $likeQuery );
+ } elseif ( !is_null( $protocol ) ) {
+ return 'el_index ' . $db->buildLike( "$protocol", $db->anyString() );
+ }
+
+ return null;
+ }
+
+ /**
* Filters hidden users (where the user doesn't have the right to view them)
* Also adds relevant block information
*
@@ -479,6 +524,25 @@ abstract class ApiQueryBase extends ApiBase {
}
}
+ /**
+ * @param $hash string
+ * @return bool
+ */
+ public function validateSha1Hash( $hash ) {
+ return preg_match( '/[a-fA-F0-9]{40}/', $hash );
+ }
+
+ /**
+ * @param $hash string
+ * @return bool
+ */
+ public function validateSha1Base36Hash( $hash ) {
+ return preg_match( '/[a-zA-Z0-9]{31}/', $hash );
+ }
+
+ /**
+ * @return array
+ */
public function getPossibleErrors() {
return array_merge( parent::getPossibleErrors(), array(
array( 'invalidtitle', 'title' ),
@@ -491,7 +555,7 @@ abstract class ApiQueryBase extends ApiBase {
* @return string
*/
public static function getBaseVersion() {
- return __CLASS__ . ': $Id: ApiQueryBase.php 85435 2011-04-05 14:00:08Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryBase.php 103029 2011-11-14 20:58:30Z reedy $';
}
}
diff --git a/includes/api/ApiQueryBlocks.php b/includes/api/ApiQueryBlocks.php
index 4edda645..503af7c7 100644
--- a/includes/api/ApiQueryBlocks.php
+++ b/includes/api/ApiQueryBlocks.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 10, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,30 +30,33 @@ if ( !defined( 'MEDIAWIKI' ) ) {
}
/**
- * Query module to enumerate all available pages.
+ * Query module to enumerate all user blocks
*
* @ingroup API
*/
class ApiQueryBlocks extends ApiQueryBase {
- var $users;
+ /**
+ * @var Array
+ */
+ protected $usernames;
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'bk' );
}
public function execute() {
- global $wgUser;
+ global $wgUser, $wgContLang;
$params = $this->extractRequestParams();
- if ( isset( $params['users'] ) && isset( $params['ip'] ) ) {
- $this->dieUsage( 'bkusers and bkip cannot be used together', 'usersandip' );
- }
+ $this->requireMaxOneParameter( $params, 'users', 'ip' );
$prop = array_flip( $params['prop'] );
$fld_id = isset( $prop['id'] );
$fld_user = isset( $prop['user'] );
+ $fld_userid = isset( $prop['userid'] );
$fld_by = isset( $prop['by'] );
+ $fld_byid = isset( $prop['byid'] );
$fld_timestamp = isset( $prop['timestamp'] );
$fld_expiry = isset( $prop['expiry'] );
$fld_reason = isset( $prop['reason'] );
@@ -65,35 +68,20 @@ class ApiQueryBlocks extends ApiQueryBase {
$this->addTables( 'ipblocks' );
$this->addFields( 'ipb_auto' );
- if ( $fld_id ) {
- $this->addFields( 'ipb_id' );
- }
- if ( $fld_user ) {
- $this->addFields( array( 'ipb_address', 'ipb_user' ) );
- }
- if ( $fld_by ) {
- $this->addTables( 'user' );
- $this->addFields( array( 'ipb_by', 'user_name' ) );
- $this->addWhere( 'user_id = ipb_by' );
- }
- if ( $fld_timestamp ) {
- $this->addFields( 'ipb_timestamp' );
- }
- if ( $fld_expiry ) {
- $this->addFields( 'ipb_expiry' );
- }
- if ( $fld_reason ) {
- $this->addFields( 'ipb_reason' );
- }
- if ( $fld_range ) {
- $this->addFields( array( 'ipb_range_start', 'ipb_range_end' ) );
- }
- if ( $fld_flags ) {
- $this->addFields( array( 'ipb_anon_only', 'ipb_create_account', 'ipb_enable_autoblock', 'ipb_block_email', 'ipb_deleted', 'ipb_allow_usertalk' ) );
- }
+ $this->addFieldsIf ( 'ipb_id', $fld_id );
+ $this->addFieldsIf( array( 'ipb_address', 'ipb_user' ), $fld_user || $fld_userid );
+ $this->addFieldsIf( 'ipb_by_text', $fld_by );
+ $this->addFieldsIf( 'ipb_by', $fld_byid );
+ $this->addFieldsIf( 'ipb_timestamp', $fld_timestamp );
+ $this->addFieldsIf( 'ipb_expiry', $fld_expiry );
+ $this->addFieldsIf( 'ipb_reason', $fld_reason );
+ $this->addFieldsIf( array( 'ipb_range_start', 'ipb_range_end' ), $fld_range );
+ $this->addFieldsIf( array( 'ipb_anon_only', 'ipb_create_account', 'ipb_enable_autoblock',
+ 'ipb_block_email', 'ipb_deleted', 'ipb_allow_usertalk' ),
+ $fld_flags );
$this->addOption( 'LIMIT', $params['limit'] + 1 );
- $this->addWhereRange( 'ipb_timestamp', $params['dir'], $params['start'], $params['end'] );
+ $this->addTimestampWhereRange( 'ipb_timestamp', $params['dir'], $params['start'], $params['end'] );
if ( isset( $params['ids'] ) ) {
$this->addWhereFld( 'ipb_id', $params['ids'] );
}
@@ -151,14 +139,20 @@ class ApiQueryBlocks extends ApiQueryBase {
if ( $fld_user && !$row->ipb_auto ) {
$block['user'] = $row->ipb_address;
}
+ if ( $fld_userid && !$row->ipb_auto ) {
+ $block['userid'] = $row->ipb_user;
+ }
if ( $fld_by ) {
- $block['by'] = $row->user_name;
+ $block['by'] = $row->ipb_by_text;
+ }
+ if ( $fld_byid ) {
+ $block['byid'] = $row->ipb_by;
}
if ( $fld_timestamp ) {
$block['timestamp'] = wfTimestamp( TS_ISO_8601, $row->ipb_timestamp );
}
if ( $fld_expiry ) {
- $block['expiry'] = Block::decodeExpiry( $row->ipb_expiry, TS_ISO_8601 );
+ $block['expiry'] = $wgContLang->formatExpiry( $row->ipb_expiry, TS_ISO_8601 );
}
if ( $fld_reason ) {
$block['reason'] = $row->ipb_reason;
@@ -248,7 +242,9 @@ class ApiQueryBlocks extends ApiQueryBase {
ApiBase::PARAM_TYPE => array(
'id',
'user',
+ 'userid',
'by',
+ 'byid',
'timestamp',
'expiry',
'reason',
@@ -264,7 +260,7 @@ class ApiQueryBlocks extends ApiQueryBase {
return array(
'start' => 'The timestamp to start enumerating from',
'end' => 'The timestamp to stop enumerating at',
- 'dir' => 'The direction in which to enumerate',
+ 'dir' => $this->getDirectionDescription( $this->getModulePrefix() ),
'ids' => 'Pipe-separated list of block IDs to list (optional)',
'users' => 'Pipe-separated list of users to search for (optional)',
'ip' => array( 'Get all blocks applying to this IP or CIDR range, including range blocks.',
@@ -272,9 +268,11 @@ class ApiQueryBlocks extends ApiQueryBase {
'limit' => 'The maximum amount of blocks to list',
'prop' => array(
'Which properties to get',
- ' id - Adds the id of the block',
+ ' id - Adds the ID of the block',
' user - Adds the username of the blocked user',
- ' by - Adds the username of the blocking admin',
+ ' userid - Adds the user ID of the blocked user',
+ ' by - Adds the username of the blocking user',
+ ' byid - Adds the user ID of the blocking user',
' timestamp - Adds the timestamp of when the block was given',
' expiry - Adds the timestamp of when the block expires',
' reason - Adds the reason given for the block',
@@ -290,7 +288,7 @@ class ApiQueryBlocks extends ApiQueryBase {
public function getPossibleErrors() {
return array_merge( parent::getPossibleErrors(), array(
- array( 'code' => 'usersandip', 'info' => 'bkusers and bkip cannot be used together' ),
+ $this->getRequireOnlyOneParameterErrorMessages( array( 'users', 'ip' ) ),
array( 'code' => 'cidrtoobroad', 'info' => 'CIDR ranges broader than /16 are not accepted' ),
array( 'code' => 'param_user', 'info' => 'User parameter may not be empty' ),
array( 'code' => 'param_user', 'info' => 'User name user is not valid' ),
@@ -304,7 +302,11 @@ class ApiQueryBlocks extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Blocks';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryBlocks.php 73858 2010-09-28 01:21:15Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryBlocks.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryCategories.php b/includes/api/ApiQueryCategories.php
index b2769dc2..c2942493 100644
--- a/includes/api/ApiQueryCategories.php
+++ b/includes/api/ApiQueryCategories.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on May 13, 2007
*
@@ -52,6 +52,10 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return
+ */
private function run( $resultPageSet = null ) {
if ( $this->getPageSet()->getGoodTitleCount() == 0 ) {
return; // nothing to do
@@ -100,7 +104,7 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
}
if ( isset( $show['hidden'] ) && isset( $show['!hidden'] ) ) {
- $this->dieUsageMsg( array( 'show' ) );
+ $this->dieUsageMsg( 'show' );
}
if ( isset( $show['hidden'] ) || isset( $show['!hidden'] ) || isset( $prop['hidden'] ) )
{
@@ -246,7 +250,11 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#categories_.2F_cl';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryCategories.php 86474 2011-04-20 13:22:05Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryCategories.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryCategoryInfo.php b/includes/api/ApiQueryCategoryInfo.php
index d4b64025..dd3bc391 100644
--- a/includes/api/ApiQueryCategoryInfo.php
+++ b/includes/api/ApiQueryCategoryInfo.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on May 13, 2007
*
@@ -119,7 +119,11 @@ class ApiQueryCategoryInfo extends ApiQueryBase {
return 'api.php?action=query&prop=categoryinfo&titles=Category:Foo|Category:Bar';
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#categoryinfo_.2F_ci';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryCategoryInfo.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryCategoryInfo.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryCategoryMembers.php b/includes/api/ApiQueryCategoryMembers.php
index bbcf8b9b..e48789fc 100644
--- a/includes/api/ApiQueryCategoryMembers.php
+++ b/includes/api/ApiQueryCategoryMembers.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on June 14, 2007
*
@@ -52,13 +52,29 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$params = $this->extractRequestParams();
- $categoryTitle = Title::newFromText( $params['title'] );
+ $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
+
+ if ( isset( $params['title'] ) ) {
+ $categoryTitle = Title::newFromText( $params['title'] );
- if ( is_null( $categoryTitle ) || $categoryTitle->getNamespace() != NS_CATEGORY ) {
- $this->dieUsage( 'The category name you entered is not valid', 'invalidcategory' );
+ if ( is_null( $categoryTitle ) || $categoryTitle->getNamespace() != NS_CATEGORY ) {
+ $this->dieUsage( 'The category name you entered is not valid', 'invalidcategory' );
+ }
+ } elseif( isset( $params['pageid'] ) ) {
+ $categoryTitle = Title::newFromID( $params['pageid'] );
+
+ if ( !$categoryTitle ) {
+ $this->dieUsageMsg( array( 'nosuchpageid', $params['pageid'] ) );
+ } elseif ( $categoryTitle->getNamespace() != NS_CATEGORY ) {
+ $this->dieUsage( 'The category name you entered is not valid', 'invalidcategory' );
+ }
}
$prop = array_flip( $params['prop'] );
@@ -113,11 +129,11 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
'by the previous query', '_badcontinue'
);
}
-
+
// Remove the types to skip from $queryTypes
$contTypeIndex = array_search( $cont[0], $queryTypes );
$queryTypes = array_slice( $queryTypes, $contTypeIndex );
-
+
// Add a WHERE clause for sortkey and from
// pack( "H*", $foo ) is used to convert hex back to binary
$escSortkey = $this->getDB()->addQuotes( pack( "H*", $cont[1] ) );
@@ -127,13 +143,22 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
$contWhere = "cl_sortkey $op $escSortkey OR " .
"(cl_sortkey = $escSortkey AND " .
"cl_from $op= $from)";
-
+ // The below produces ORDER BY cl_sortkey, cl_from, possibly with DESC added to each of them
+ $this->addWhereRange( 'cl_sortkey', $dir, null, null );
+ $this->addWhereRange( 'cl_from', $dir, null, null );
} else {
+ $startsortkey = $params['startsortkeyprefix'] !== null ?
+ Collation::singleton()->getSortkey( $params['startsortkeyprefix'] ) :
+ $params['startsortkey'];
+ $endsortkey = $params['endsortkeyprefix'] !== null ?
+ Collation::singleton()->getSortkey( $params['endsortkeyprefix'] ) :
+ $params['endsortkey'];
+
// The below produces ORDER BY cl_sortkey, cl_from, possibly with DESC added to each of them
$this->addWhereRange( 'cl_sortkey',
$dir,
- $params['startsortkey'],
- $params['endsortkey'] );
+ $startsortkey,
+ $endsortkey );
$this->addWhereRange( 'cl_from', $dir, null, null );
}
$this->addOption( 'USE INDEX', 'cl_sortkey' );
@@ -173,6 +198,8 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
$res = $this->select( __METHOD__ );
$rows = iterator_to_array( $res );
}
+
+ $result = $this->getResult();
$count = 0;
foreach ( $rows as $row ) {
if ( ++ $count > $limit ) {
@@ -218,7 +245,7 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
if ( $fld_timestamp ) {
$vals['timestamp'] = wfTimestamp( TS_ISO_8601, $row->cl_timestamp );
}
- $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ),
+ $fit = $result->addValue( array( 'query', $this->getModuleName() ),
null, $vals );
if ( !$fit ) {
if ( $params['sort'] == 'timestamp' ) {
@@ -237,7 +264,7 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
}
if ( is_null( $resultPageSet ) ) {
- $this->getResult()->setIndexedTagName_internal(
+ $result->setIndexedTagName_internal(
array( 'query', $this->getModuleName() ), 'cm' );
}
}
@@ -246,7 +273,9 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
return array(
'title' => array(
ApiBase::PARAM_TYPE => 'string',
- ApiBase::PARAM_REQUIRED => true
+ ),
+ 'pageid' => array(
+ ApiBase::PARAM_TYPE => 'integer'
),
'prop' => array(
ApiBase::PARAM_DFLT => 'ids|title',
@@ -303,6 +332,8 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
),
'startsortkey' => null,
'endsortkey' => null,
+ 'startsortkeyprefix' => null,
+ 'endsortkeyprefix' => null,
);
}
@@ -310,7 +341,8 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
global $wgMiserMode;
$p = $this->getModulePrefix();
$desc = array(
- 'title' => 'Which category to enumerate (required). Must include Category: prefix',
+ 'title' => "Which category to enumerate (required). Must include Category: prefix. Cannot be used together with {$p}pageid",
+ 'pageid' => "Page ID of the category to enumerate. Cannot be used together with {$p}title",
'prop' => array(
'What pieces of information to include',
' ids - Adds the page ID',
@@ -326,17 +358,20 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
'dir' => 'In which direction to sort',
'start' => "Timestamp to start listing from. Can only be used with {$p}sort=timestamp",
'end' => "Timestamp to end listing at. Can only be used with {$p}sort=timestamp",
- 'startsortkey' => "Sortkey to start listing from. Can only be used with {$p}sort=sortkey",
- 'endsortkey' => "Sortkey to end listing at. Can only be used with {$p}sort=sortkey",
+ 'startsortkey' => "Sortkey to start listing from. Must be given in binary format. Can only be used with {$p}sort=sortkey",
+ 'endsortkey' => "Sortkey to end listing at. Must be given in binary format. Can only be used with {$p}sort=sortkey",
+ 'startsortkeyprefix' => "Sortkey prefix to start listing from. Can only be used with {$p}sort=sortkey. Overrides {$p}startsortkey",
+ 'endsortkeyprefix' => "Sortkey prefix to end listing BEFORE (not at, if this value occurs it will not be included!). Can only be used with {$p}sort=sortkey. Overrides {$p}endsortkey",
'continue' => 'For large categories, give the value retured from previous query',
'limit' => 'The maximum number of pages to return.',
);
+
if ( $wgMiserMode ) {
$desc['namespace'] = array(
$desc['namespace'],
- 'NOTE: Due to $wgMiserMode, using this may result in fewer than "limit" results',
+ "NOTE: Due to \$wgMiserMode, using this may result in fewer than \"{$p}limit\" results",
'returned before continuing; in extreme cases, zero results may be returned.',
- 'Note that you can use cmtype=subcat or cmtype=file instead of cmnamespace=14 or 6.',
+ "Note that you can use {$p}type=subcat or {$p}type=file instead of {$p}namespace=14 or 6.",
);
}
return $desc;
@@ -347,11 +382,14 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
}
public function getPossibleErrors() {
- return array_merge( parent::getPossibleErrors(), array(
- array( 'code' => 'notitle', 'info' => 'The cmtitle parameter is required' ),
- array( 'code' => 'invalidcategory', 'info' => 'The category name you entered is not valid' ),
- array( 'code' => 'badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
- ) );
+ return array_merge( parent::getPossibleErrors(),
+ $this->getRequireOnlyOneParameterErrorMessages( array( 'title', 'pageid' ) ),
+ array(
+ array( 'code' => 'invalidcategory', 'info' => 'The category name you entered is not valid' ),
+ array( 'code' => 'badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
+ array( 'nosuchpageid', 'pageid' ),
+ )
+ );
}
protected function getExamples() {
@@ -363,7 +401,11 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Categorymembers';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryCategoryMembers.php 86474 2011-04-20 13:22:05Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryCategoryMembers.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php
index 523862c0..f58b9ee5 100644
--- a/includes/api/ApiQueryDeletedrevs.php
+++ b/includes/api/ApiQueryDeletedrevs.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Jul 2, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,6 +50,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$db = $this->getDB();
$params = $this->extractRequestParams( false );
$prop = array_flip( $params['prop'] );
+ $fld_parentid = isset( $prop['parentid'] );
$fld_revid = isset( $prop['revid'] );
$fld_user = isset( $prop['user'] );
$fld_userid = isset( $prop['userid'] );
@@ -65,9 +66,9 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$titles = $pageSet->getTitles();
// This module operates in three modes:
- // 'revs': List deleted revs for certain titles
- // 'user': List deleted revs by a certain user
- // 'all': List all deleted revs
+ // 'revs': List deleted revs for certain titles (1)
+ // 'user': List deleted revs by a certain user (2)
+ // 'all': List all deleted revs in NS (3)
$mode = 'all';
if ( count( $titles ) > 0 ) {
$mode = 'revs';
@@ -75,6 +76,21 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$mode = 'user';
}
+ if ( $mode == 'revs' || $mode == 'user' ) {
+ // Ignore namespace and unique due to inability to know whether they were purposely set
+ foreach( array( 'from', 'to', 'prefix', /*'namespace',*/ 'continue', /*'unique'*/ ) as $p ) {
+ if ( !is_null( $params[$p] ) ) {
+ $this->dieUsage( "The '{$p}' parameter cannot be used in modes 1 or 2", 'badparams');
+ }
+ }
+ } else {
+ foreach( array( 'start', 'end' ) as $p ) {
+ if ( !is_null( $params[$p] ) ) {
+ $this->dieUsage( "The {$p} parameter cannot be used in mode 3", 'badparams');
+ }
+ }
+ }
+
if ( !is_null( $params['user'] ) && !is_null( $params['excludeuser'] ) ) {
$this->dieUsage( 'user and excludeuser cannot be used together', 'badparams' );
}
@@ -82,24 +98,15 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$this->addTables( 'archive' );
$this->addWhere( 'ar_deleted = 0' );
$this->addFields( array( 'ar_title', 'ar_namespace', 'ar_timestamp' ) );
- if ( $fld_revid ) {
- $this->addFields( 'ar_rev_id' );
- }
- if ( $fld_user ) {
- $this->addFields( 'ar_user_text' );
- }
- if ( $fld_userid ) {
- $this->addFields( 'ar_user' );
- }
- if ( $fld_comment || $fld_parsedcomment ) {
- $this->addFields( 'ar_comment' );
- }
- if ( $fld_minor ) {
- $this->addFields( 'ar_minor_edit' );
- }
- if ( $fld_len ) {
- $this->addFields( 'ar_len' );
- }
+
+ $this->addFieldsIf( 'ar_parent_id', $fld_parentid );
+ $this->addFieldsIf( 'ar_rev_id', $fld_revid );
+ $this->addFieldsIf( 'ar_user_text', $fld_user );
+ $this->addFieldsIf( 'ar_user', $fld_userid );
+ $this->addFieldsIf( 'ar_comment', $fld_comment || $fld_parsedcomment );
+ $this->addFieldsIf( 'ar_minor_edit', $fld_minor );
+ $this->addFieldsIf( 'ar_len', $fld_len );
+
if ( $fld_content ) {
$this->addTables( 'text' );
$this->addFields( array( 'ar_text', 'ar_text_id', 'old_text', 'old_flags' ) );
@@ -125,9 +132,11 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
if ( $fld_token ) {
// Undelete tokens are identical for all pages, so we cache one here
- $token = $wgUser->editToken();
+ $token = $wgUser->editToken( '', $this->getMain()->getRequest() );
}
+ $dir = $params['dir'];
+
// We need a custom WHERE clause that matches all titles.
if ( $mode == 'revs' ) {
$lb = new LinkBatch( $titles );
@@ -135,9 +144,13 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$this->addWhere( $where );
} elseif ( $mode == 'all' ) {
$this->addWhereFld( 'ar_namespace', $params['namespace'] );
- if ( !is_null( $params['from'] ) ) {
- $from = $this->getDB()->strencode( $this->titleToKey( $params['from'] ) );
- $this->addWhere( "ar_title >= '$from'" );
+
+ $from = is_null( $params['from'] ) ? null : $this->titleToKey( $params['from'] );
+ $to = is_null( $params['to'] ) ? null : $this->titleToKey( $params['to'] );
+ $this->addWhereRange( 'ar_title', $dir, $from, $to );
+
+ if ( isset( $params['prefix'] ) ) {
+ $this->addWhere( 'ar_title' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
}
}
@@ -148,8 +161,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$this->getDB()->addQuotes( $params['excludeuser'] ) );
}
- if ( !is_null( $params['continue'] ) && ( $mode == 'all' || $mode == 'revs' ) )
- {
+ if ( !is_null( $params['continue'] ) && ( $mode == 'all' || $mode == 'revs' ) ) {
$cont = explode( '|', $params['continue'] );
if ( count( $cont ) != 3 ) {
$this->dieUsage( 'Invalid continue param. You should pass the original value returned by the previous query', 'badcontinue' );
@@ -157,7 +169,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$ns = intval( $cont[0] );
$title = $this->getDB()->strencode( $this->titleToKey( $cont[1] ) );
$ts = $this->getDB()->strencode( $cont[2] );
- $op = ( $params['dir'] == 'newer' ? '>' : '<' );
+ $op = ( $dir == 'newer' ? '>' : '<' );
$this->addWhere( "ar_namespace $op $ns OR " .
"(ar_namespace = $ns AND " .
"(ar_title $op '$title' OR " .
@@ -170,17 +182,16 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
if ( $mode == 'all' ) {
if ( $params['unique'] ) {
$this->addOption( 'GROUP BY', 'ar_title' );
- $this->addOption( 'ORDER BY', 'ar_title' );
} else {
$this->addOption( 'ORDER BY', 'ar_title, ar_timestamp' );
}
} else {
if ( $mode == 'revs' ) {
// Sort by ns and title in the same order as timestamp for efficiency
- $this->addWhereRange( 'ar_namespace', $params['dir'], null, null );
- $this->addWhereRange( 'ar_title', $params['dir'], null, null );
+ $this->addWhereRange( 'ar_namespace', $dir, null, null );
+ $this->addWhereRange( 'ar_title', $dir, null, null );
}
- $this->addWhereRange( 'ar_timestamp', $params['dir'], $params['start'], $params['end'] );
+ $this->addTimestampWhereRange( 'ar_timestamp', $dir, $params['start'], $params['end'] );
}
$res = $this->select( __METHOD__ );
$pageMap = array(); // Maps ns&title to (fake) pageid
@@ -203,6 +214,9 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
if ( $fld_revid ) {
$rev['revid'] = intval( $row->ar_rev_id );
}
+ if ( $fld_parentid ) {
+ $rev['parentid'] = intval( $row->ar_parent_id );
+ }
if ( $fld_user ) {
$rev['user'] = $row->ar_user_text;
}
@@ -273,6 +287,8 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
ApiBase::PARAM_DFLT => 'older'
),
'from' => null,
+ 'to' => null,
+ 'prefix' => null,
'continue' => null,
'unique' => false,
'user' => array(
@@ -296,6 +312,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
ApiBase::PARAM_DFLT => 'user|comment',
ApiBase::PARAM_TYPE => array(
'revid',
+ 'parentid',
'user',
'userid',
'comment',
@@ -314,13 +331,17 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
return array(
'start' => 'The timestamp to start enumerating from (1,2)',
'end' => 'The timestamp to stop enumerating at (1,2)',
- 'dir' => 'The direction in which to enumerate (1,2)',
+ 'dir' => $this->getDirectionDescription( $this->getModulePrefix(), ' (1, 3)' ),
+ 'from' => 'Start listing at this title (3)',
+ 'to' => 'Stop listing at this title (3)',
+ 'prefix' => 'Search for all page titles that begin with this value (3)',
'limit' => 'The maximum amount of revisions to list',
'prop' => array(
'Which properties to get',
- ' revid - Adds the revision id of the deleted revision',
+ ' revid - Adds the revision ID of the deleted revision',
+ ' parentid - Adds the revision ID of the previous revision to the page',
' user - Adds the user who made the revision',
- ' userid - Adds the user id whom made the revision',
+ ' userid - Adds the user ID whom made the revision',
' comment - Adds the comment of the revision',
' parsedcomment - Adds the parsed comment of the revision',
' minor - Tags if the revision is minor',
@@ -331,19 +352,19 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
'namespace' => 'Only list pages in this namespace (3)',
'user' => 'Only list revisions by this user',
'excludeuser' => 'Don\'t list revisions by this user',
- 'from' => 'Start listing at this title (3)',
'continue' => 'When more results are available, use this to continue (3)',
'unique' => 'List only one revision for each page (3)',
);
}
public function getDescription() {
+ $p = $this->getModulePrefix();
return array(
'List deleted revisions.',
- 'This module operates in three modes:',
- '1) List deleted revisions for the given title(s), sorted by timestamp',
- '2) List deleted contributions for the given user, sorted by timestamp (no titles specified)',
- '3) List all deleted revisions in the given namespace, sorted by title and timestamp (no titles specified, druser not set)',
+ 'Operates in three modes:',
+ ' 1) List deleted revisions for the given title(s), sorted by timestamp',
+ ' 2) List deleted contributions for the given user, sorted by timestamp (no titles specified)',
+ " 3) List all deleted revisions in the given namespace, sorted by title and timestamp (no titles specified, {$p}user not set)",
'Certain parameters only apply to some modes and are ignored in others.',
'For instance, a parameter marked (1) only applies to mode 1 and is ignored in modes 2 and 3',
);
@@ -355,6 +376,12 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
array( 'code' => 'badparams', 'info' => 'user and excludeuser cannot be used together' ),
array( 'code' => 'permissiondenied', 'info' => 'You don\'t have permission to view deleted revision content' ),
array( 'code' => 'badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
+ array( 'code' => 'badparams', 'info' => "The 'from' parameter cannot be used in modes 1 or 2" ),
+ array( 'code' => 'badparams', 'info' => "The 'to' parameter cannot be used in modes 1 or 2" ),
+ array( 'code' => 'badparams', 'info' => "The 'prefix' parameter cannot be used in modes 1 or 2" ),
+ array( 'code' => 'badparams', 'info' => "The 'continue' parameter cannot be used in modes 1 or 2" ),
+ array( 'code' => 'badparams', 'info' => "The 'start' parameter cannot be used in mode 3" ),
+ array( 'code' => 'badparams', 'info' => "The 'end' parameter cannot be used in mode 3" ),
) );
}
@@ -371,7 +398,11 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Deletedrevs';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryDeletedrevs.php 77192 2010-11-23 22:05:27Z btongminh $';
+ return __CLASS__ . ': $Id: ApiQueryDeletedrevs.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryDisabled.php b/includes/api/ApiQueryDisabled.php
index b5712069..c9edd2e4 100644
--- a/includes/api/ApiQueryDisabled.php
+++ b/includes/api/ApiQueryDisabled.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 25, 2008
*
- * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -68,6 +68,6 @@ class ApiQueryDisabled extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryDisabled.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryDisabled.php 79969 2011-01-10 22:36:26Z reedy $';
}
}
diff --git a/includes/api/ApiQueryDuplicateFiles.php b/includes/api/ApiQueryDuplicateFiles.php
index ffe98038..4c7c1fc2 100644
--- a/includes/api/ApiQueryDuplicateFiles.php
+++ b/includes/api/ApiQueryDuplicateFiles.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 27, 2008
*
- * Copyright © 2008 Roan Kattow <Firstname>,<Lastname>@home.nl
+ * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,6 +52,10 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return
+ */
private function run( $resultPageSet = null ) {
$params = $this->extractRequestParams();
$namespaces = $this->getPageSet()->getAllTitlesByNamespace();
@@ -164,7 +168,11 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#duplicatefiles_.2F_df';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryDuplicateFiles.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryDuplicateFiles.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryExtLinksUsage.php b/includes/api/ApiQueryExtLinksUsage.php
index ecd9e699..89928372 100644
--- a/includes/api/ApiQueryExtLinksUsage.php
+++ b/includes/api/ApiQueryExtLinksUsage.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on July 7, 2007
*
@@ -50,45 +50,32 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$params = $this->extractRequestParams();
- $protocol = $params['protocol'];
$query = $params['query'];
+ $protocol = self::getProtocolPrefix( $params['protocol'] );
- // Find the right prefix
- global $wgUrlProtocols;
- if ( $protocol && !in_array( $protocol, $wgUrlProtocols ) ) {
- foreach ( $wgUrlProtocols as $p ) {
- if ( substr( $p, 0, strlen( $protocol ) ) === $protocol ) {
- $protocol = $p;
- break;
- }
- }
- } else {
- $protocol = null;
- }
-
- $db = $this->getDB();
$this->addTables( array( 'page', 'externallinks' ) ); // must be in this order for 'USE INDEX'
$this->addOption( 'USE INDEX', 'el_index' );
$this->addWhere( 'page_id=el_from' );
- $this->addWhereFld( 'page_namespace', $params['namespace'] );
- if ( !is_null( $query ) || $query != '' ) {
- if ( is_null( $protocol ) ) {
- $protocol = 'http://';
- }
+ global $wgMiserMode;
+ $miser_ns = array();
+ if ( $wgMiserMode ) {
+ $miser_ns = $params['namespace'];
+ } else {
+ $this->addWhereFld( 'page_namespace', $params['namespace'] );
+ }
- $likeQuery = LinkFilter::makeLikeArray( $query, $protocol );
- if ( !$likeQuery ) {
- $this->dieUsage( 'Invalid query', 'bad_query' );
- }
+ $whereQuery = $this->prepareUrlQuerySearchString( $query, $protocol );
- $likeQuery = LinkFilter::keepOneWildcard( $likeQuery );
- $this->addWhere( 'el_index ' . $db->buildLike( $likeQuery ) );
- } elseif ( !is_null( $protocol ) ) {
- $this->addWhere( 'el_index ' . $db->buildLike( "$protocol", $db->anyString() ) );
+ if ( $whereQuery !== null ) {
+ $this->addWhere( $whereQuery );
}
$prop = array_flip( $params['prop'] );
@@ -125,6 +112,10 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
break;
}
+ if ( count( $miser_ns ) && !in_array( $row->page_namespace, $miser_ns ) ) {
+ continue;
+ }
+
if ( is_null( $resultPageSet ) ) {
$vals = array();
if ( $fld_ids ) {
@@ -135,6 +126,7 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
ApiQueryBase::addTitleInfo( $vals, $title );
}
if ( $fld_url ) {
+ // We *could* run this through wfExpandUrl() but I think it's better to output the link verbatim, even if it's protocol-relative --Roan
$vals['url'] = $row->el_to;
}
$fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $vals );
@@ -154,12 +146,6 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
}
public function getAllowedParams() {
- global $wgUrlProtocols;
- $protocols = array( '' );
- foreach ( $wgUrlProtocols as $p ) {
- $protocols[] = substr( $p, 0, strpos( $p, ':' ) );
- }
-
return array(
'prop' => array(
ApiBase::PARAM_ISMULTI => true,
@@ -174,7 +160,7 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
ApiBase::PARAM_TYPE => 'integer'
),
'protocol' => array(
- ApiBase::PARAM_TYPE => $protocols,
+ ApiBase::PARAM_TYPE => self::prepareProtocols(),
ApiBase::PARAM_DFLT => '',
),
'query' => null,
@@ -192,13 +178,42 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
);
}
+ public static function prepareProtocols() {
+ global $wgUrlProtocols;
+ $protocols = array( '' );
+ foreach ( $wgUrlProtocols as $p ) {
+ if ( $p !== '//' ) {
+ $protocols[] = substr( $p, 0, strpos( $p, ':' ) );
+ }
+ }
+ return $protocols;
+ }
+
+ public static function getProtocolPrefix( $protocol ) {
+ // Find the right prefix
+ global $wgUrlProtocols;
+ if ( $protocol && !in_array( $protocol, $wgUrlProtocols ) ) {
+ foreach ( $wgUrlProtocols as $p ) {
+ if ( substr( $p, 0, strlen( $protocol ) ) === $protocol ) {
+ $protocol = $p;
+ break;
+ }
+ }
+
+ return $protocol;
+ } else {
+ return null;
+ }
+ }
+
public function getParamDescription() {
+ global $wgMiserMode;
$p = $this->getModulePrefix();
- return array(
+ $desc = array(
'prop' => array(
'What pieces of information to include',
- ' ids - Adds the id of page',
- ' title - Adds the title and namespace id of the page',
+ ' ids - Adds the ID of page',
+ ' title - Adds the title and namespace ID of the page',
' url - Adds the URL used in the page',
),
'offset' => 'Used for paging. Use the value returned for "continue"',
@@ -210,6 +225,16 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
'namespace' => 'The page namespace(s) to enumerate.',
'limit' => 'How many pages to return.'
);
+
+ if ( $wgMiserMode ) {
+ $desc['namespace'] = array(
+ $desc['namespace'],
+ "NOTE: Due to \$wgMiserMode, using this may result in fewer than \"{$p}limit\" results",
+ 'returned before continuing; in extreme cases, zero results may be returned',
+ );
+ }
+
+ return $desc;
}
public function getDescription() {
@@ -228,7 +253,11 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Exturlusage';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryExtLinksUsage.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryExtLinksUsage.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryExternalLinks.php b/includes/api/ApiQueryExternalLinks.php
index fbfcbfb9..ca1efbb1 100644
--- a/includes/api/ApiQueryExternalLinks.php
+++ b/includes/api/ApiQueryExternalLinks.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on May 13, 2007
*
@@ -46,6 +46,10 @@ class ApiQueryExternalLinks extends ApiQueryBase {
}
$params = $this->extractRequestParams();
+
+ $query = $params['query'];
+ $protocol = ApiQueryExtLinksUsage::getProtocolPrefix( $params['protocol'] );
+
$this->addFields( array(
'el_from',
'el_to'
@@ -54,13 +58,25 @@ class ApiQueryExternalLinks extends ApiQueryBase {
$this->addTables( 'externallinks' );
$this->addWhereFld( 'el_from', array_keys( $this->getPageSet()->getGoodTitles() ) );
+ $whereQuery = $this->prepareUrlQuerySearchString( $query, $protocol );
+
+ if ( $whereQuery !== null ) {
+ $this->addWhere( $whereQuery );
+ }
+
// Don't order by el_from if it's constant in the WHERE clause
if ( count( $this->getPageSet()->getGoodTitles() ) != 1 ) {
$this->addOption( 'ORDER BY', 'el_from' );
}
+ // If we're querying all protocols, use DISTINCT to avoid repeating protocol-relative links twice
+ if ( $protocol === null ) {
+ $this->addOption( 'DISTINCT' );
+ }
+
$this->addOption( 'LIMIT', $params['limit'] + 1 );
- if ( !is_null( $params['offset'] ) ) {
+ $offset = isset( $params['offset'] ) ? $params['offset'] : 0;
+ if ( $offset ) {
$this->addOption( 'OFFSET', $params['offset'] );
}
@@ -71,14 +87,15 @@ class ApiQueryExternalLinks extends ApiQueryBase {
if ( ++$count > $params['limit'] ) {
// We've reached the one extra which shows that
// there are additional pages to be had. Stop here...
- $this->setContinueEnumParameter( 'offset', @$params['offset'] + $params['limit'] );
+ $this->setContinueEnumParameter( 'offset', $offset + $params['limit'] );
break;
}
$entry = array();
+ // We *could* run this through wfExpandUrl() but I think it's better to output the link verbatim, even if it's protocol-relative --Roan
ApiResult::setContent( $entry, $row->el_to );
$fit = $this->addPageSubItem( $row->el_from, $entry );
if ( !$fit ) {
- $this->setContinueEnumParameter( 'offset', @$params['offset'] + $count - 1 );
+ $this->setContinueEnumParameter( 'offset', $offset + $count - 1 );
break;
}
}
@@ -97,14 +114,27 @@ class ApiQueryExternalLinks extends ApiQueryBase {
ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
),
- 'offset' => null,
+ 'offset' => array(
+ ApiBase::PARAM_TYPE => 'integer'
+ ),
+ 'protocol' => array(
+ ApiBase::PARAM_TYPE => ApiQueryExtLinksUsage::prepareProtocols(),
+ ApiBase::PARAM_DFLT => '',
+ ),
+ 'query' => null,
);
}
public function getParamDescription() {
+ $p = $this->getModulePrefix();
return array(
'limit' => 'How many links to return',
'offset' => 'When more results are available, use this to continue',
+ 'protocol' => array(
+ "Protocol of the url. If empty and {$p}query set, the protocol is http.",
+ "Leave both this and {$p}query empty to list all external links"
+ ),
+ 'query' => 'Search string without protocol. Useful for checking whether a certain page contains a certain external url',
);
}
@@ -112,6 +142,12 @@ class ApiQueryExternalLinks extends ApiQueryBase {
return 'Returns all external urls (not interwikies) from the given page(s)';
}
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(), array(
+ array( 'code' => 'bad_query', 'info' => 'Invalid query' ),
+ ) );
+ }
+
protected function getExamples() {
return array(
'Get a list of external links on the [[Main Page]]:',
@@ -119,7 +155,11 @@ class ApiQueryExternalLinks extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#extlinks_.2F_el';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryExternalLinks.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryExternalLinks.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryFilearchive.php b/includes/api/ApiQueryFilearchive.php
index 05ccb346..541b25fc 100644
--- a/includes/api/ApiQueryFilearchive.php
+++ b/includes/api/ApiQueryFilearchive.php
@@ -59,7 +59,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
$fld_user = isset( $prop['user'] );
$fld_size = isset( $prop['size'] );
$fld_dimensions = isset( $prop['dimensions'] );
- $fld_description = isset( $prop['description'] );
+ $fld_description = isset( $prop['description'] ) || isset( $prop['parseddescription'] );
$fld_mime = isset( $prop['mime'] );
$fld_metadata = isset( $prop['metadata'] );
$fld_bitdepth = isset( $prop['bitdepth'] );
@@ -69,45 +69,57 @@ class ApiQueryFilearchive extends ApiQueryBase {
$this->addFields( array( 'fa_name', 'fa_deleted' ) );
$this->addFieldsIf( 'fa_storage_key', $fld_sha1 );
$this->addFieldsIf( 'fa_timestamp', $fld_timestamp );
-
- if ( $fld_user ) {
- $this->addFields( array( 'fa_user', 'fa_user_text' ) );
- }
- $this->addFieldsIf( 'fa_size', $fld_size );
-
- if ( $fld_dimensions ) {
- $this->addFields( array( 'fa_height', 'fa_width' ) );
- }
-
+ $this->addFieldsIf( array( 'fa_user', 'fa_user_text' ), $fld_user );
+ $this->addFieldsIf( array( 'fa_height', 'fa_width', 'fa_size' ), $fld_dimensions || $fld_size );
$this->addFieldsIf( 'fa_description', $fld_description );
-
- if ( $fld_mime ) {
- $this->addFields( array( 'fa_major_mime', 'fa_minor_mime' ) );
- }
-
+ $this->addFieldsIf( array( 'fa_major_mime', 'fa_minor_mime' ), $fld_mime );
$this->addFieldsIf( 'fa_metadata', $fld_metadata );
$this->addFieldsIf( 'fa_bits', $fld_bitdepth );
// Image filters
$dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
$from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) );
- $this->addWhereRange( 'fa_name', $dir, $from, null );
+ $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) );
+ $this->addWhereRange( 'fa_name', $dir, $from, $to );
if ( isset( $params['prefix'] ) ) {
$this->addWhere( 'fa_name' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) );
}
-
+
+ $sha1Set = isset( $params['sha1'] );
+ $sha1base36Set = isset( $params['sha1base36'] );
+ if ( $sha1Set || $sha1base36Set ) {
+ global $wgMiserMode;
+ if ( $wgMiserMode ) {
+ $this->dieUsage( 'Search by hash disabled in Miser Mode', 'hashsearchdisabled' );
+ }
+
+ $sha1 = false;
+ if ( $sha1Set ) {
+ if ( !$this->validateSha1Hash( $params['sha1'] ) ) {
+ $this->dieUsage( 'The SHA1 hash provided is not valid', 'invalidsha1hash' );
+ }
+ $sha1 = wfBaseConvert( $params['sha1'], 16, 36, 31 );
+ } elseif ( $sha1base36Set ) {
+ if ( !$this->validateSha1Base36Hash( $params['sha1base36'] ) ) {
+ $this->dieUsage( 'The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash' );
+ }
+ $sha1 = $params['sha1base36'];
+ }
+ if ( $sha1 ) {
+ $this->addWhere( 'fa_storage_key ' . $db->buildLike( "{$sha1}.", $db->anyString() ) );
+ }
+ }
+
if ( !$wgUser->isAllowed( 'suppressrevision' ) ) {
// Filter out revisions that the user is not allowed to see. There
// is no way to indicate that we have skipped stuff because the
// continuation parameter is fa_name
-
+
// Note that this field is unindexed. This should however not be
// a big problem as files with fa_deleted are rare
$this->addWhereFld( 'fa_deleted', 0 );
}
-
-
$limit = $params['limit'];
$this->addOption( 'LIMIT', $limit + 1 );
$this->addOption( 'ORDER BY', 'fa_name' .
@@ -127,9 +139,11 @@ class ApiQueryFilearchive extends ApiQueryBase {
$file = array();
$file['name'] = $row->fa_name;
+ $title = Title::makeTitle( NS_FILE, $row->fa_name );
+ self::addTitleInfo( $file, $title );
if ( $fld_sha1 ) {
- $file['sha1'] = wfBaseConvert( $row->fa_storage_key, 36, 16, 40 );
+ $file['sha1'] = wfBaseConvert( LocalRepo::getHashFromKey( $row->fa_storage_key ), 36, 16, 40 );
}
if ( $fld_timestamp ) {
$file['timestamp'] = wfTimestamp( TS_ISO_8601, $row->fa_timestamp );
@@ -138,18 +152,28 @@ class ApiQueryFilearchive extends ApiQueryBase {
$file['userid'] = $row->fa_user;
$file['user'] = $row->fa_user_text;
}
- if ( $fld_size ) {
+ if ( $fld_size || $fld_dimensions ) {
$file['size'] = $row->fa_size;
- }
- if ( $fld_dimensions ) {
+
+ $pageCount = ArchivedFile::newFromRow( $row )->pageCount();
+ if ( $pageCount !== false ) {
+ $vals['pagecount'] = $pageCount;
+ }
+
$file['height'] = $row->fa_height;
$file['width'] = $row->fa_width;
}
if ( $fld_description ) {
$file['description'] = $row->fa_description;
+ if ( isset( $prop['parseddescription'] ) ) {
+ $file['parseddescription'] = $wgUser->getSkin()->formatComment(
+ $row->fa_description, $title );
+ }
}
if ( $fld_metadata ) {
- $file['metadata'] = $row->fa_metadata ? ApiQueryImageInfo::processMetaData( unserialize( $row->fa_metadata ), $result ) : null;
+ $file['metadata'] = $row->fa_metadata
+ ? ApiQueryImageInfo::processMetaData( unserialize( $row->fa_metadata ), $result )
+ : null;
}
if ( $fld_bitdepth ) {
$file['bitdepth'] = $row->fa_bits;
@@ -157,7 +181,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
if ( $fld_mime ) {
$file['mime'] = "$row->fa_major_mime/$row->fa_minor_mime";
}
-
+
if ( $row->fa_deleted & File::DELETED_FILE ) {
$file['filehidden'] = '';
}
@@ -172,7 +196,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
$file['suppressed'] = '';
}
-
+
$fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $file );
if ( !$fit ) {
$this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->fa_name ) );
@@ -186,6 +210,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
public function getAllowedParams() {
return array (
'from' => null,
+ 'to' => null,
'prefix' => null,
'limit' => array(
ApiBase::PARAM_DFLT => 10,
@@ -201,6 +226,8 @@ class ApiQueryFilearchive extends ApiQueryBase {
'descending'
)
),
+ 'sha1' => null,
+ 'sha1base36' => null,
'prop' => array(
ApiBase::PARAM_DFLT => 'timestamp',
ApiBase::PARAM_ISMULTI => true,
@@ -211,6 +238,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
'size',
'dimensions',
'description',
+ 'parseddescription',
'mime',
'metadata',
'bitdepth'
@@ -222,20 +250,24 @@ class ApiQueryFilearchive extends ApiQueryBase {
public function getParamDescription() {
return array(
'from' => 'The image title to start enumerating from',
+ 'to' => 'The image title to stop enumerating at',
'prefix' => 'Search for all image titles that begin with this value',
'dir' => 'The direction in which to list',
- 'limit' => 'How many total images to return',
+ 'limit' => 'How many images to return in total',
+ 'sha1' => "SHA1 hash of image. Overrides {$this->getModulePrefix()}sha1base36. Disabled in Miser Mode",
+ 'sha1base36' => 'SHA1 hash of image in base 36 (used in MediaWiki). Disabled in Miser Mode',
'prop' => array(
'What image information to get:',
- ' sha1 - Adds sha1 hash for the image',
- ' timestamp - Adds timestamp for the uploaded version',
- ' user - Adds user who uploaded the image version',
- ' size - Adds the size of the image in bytes',
- ' dimensions - Adds the height and width of the image',
- ' description - Adds description the image version',
- ' mime - Adds MIME of the image',
- ' metadata - Lists EXIF metadata for the version of the image',
- ' bitdepth - Adds the bit depth of the version',
+ ' sha1 - Adds SHA-1 hash for the image',
+ ' timestamp - Adds timestamp for the uploaded version',
+ ' user - Adds user who uploaded the image version',
+ ' size - Adds the size of the image in bytes and the height, width and page count (if applicable)',
+ ' dimensions - Alias for size',
+ ' description - Adds description the image version',
+ ' parseddescription - Parse the description on the version',
+ ' mime - Adds MIME of the image',
+ ' metadata - Lists EXIF metadata for the version of the image',
+ ' bitdepth - Adds the bit depth of the version',
),
);
}
@@ -247,6 +279,9 @@ class ApiQueryFilearchive extends ApiQueryBase {
public function getPossibleErrors() {
return array_merge( parent::getPossibleErrors(), array(
array( 'code' => 'permissiondenied', 'info' => 'You don\'t have permission to view deleted file information' ),
+ array( 'code' => 'hashsearchdisabled', 'info' => 'Search by hash disabled in Miser Mode' ),
+ array( 'code' => 'invalidsha1hash', 'info' => 'The SHA1 hash provided is not valid' ),
+ array( 'code' => 'invalidsha1base36hash', 'info' => 'The SHA1Base36 hash provided is not valid' ),
) );
}
@@ -259,6 +294,6 @@ class ApiQueryFilearchive extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryFilearchive.php 85354 2011-04-04 18:25:31Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryFilearchive.php 91246 2011-07-01 02:25:19Z reedy $';
}
}
diff --git a/includes/api/ApiQueryIWBacklinks.php b/includes/api/ApiQueryIWBacklinks.php
index 6958a253..1a8e9720 100644
--- a/includes/api/ApiQueryIWBacklinks.php
+++ b/includes/api/ApiQueryIWBacklinks.php
@@ -48,6 +48,10 @@ class ApiQueryIWBacklinks extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
public function run( $resultPageSet = null ) {
$params = $this->extractRequestParams();
@@ -115,11 +119,10 @@ class ApiQueryIWBacklinks extends ApiQueryGeneratorBase {
if ( !is_null( $resultPageSet ) ) {
$pages[] = Title::newFromRow( $row );
} else {
- $entry = array();
+ $entry = array( 'pageid' => $row->page_id );
- $entry['pageid'] = intval( $row->page_id );
- $entry['ns'] = intval( $row->page_namespace );
- $entry['title'] = $row->page_title;
+ $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+ ApiQueryBase::addTitleInfo( $entry, $title );
if ( $row->page_is_redirect ) {
$entry['redirect'] = '';
@@ -212,6 +215,6 @@ class ApiQueryIWBacklinks extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryIWBacklinks.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryIWBacklinks.php 84257 2011-03-18 19:15:33Z reedy $';
}
}
diff --git a/includes/api/ApiQueryIWLinks.php b/includes/api/ApiQueryIWLinks.php
index e980d6a5..3215a96e 100644
--- a/includes/api/ApiQueryIWLinks.php
+++ b/includes/api/ApiQueryIWLinks.php
@@ -47,6 +47,11 @@ class ApiQueryIWLinks extends ApiQueryBase {
}
$params = $this->extractRequestParams();
+
+ if ( isset( $params['title'] ) && !isset( $params['prefix'] ) ) {
+ $this->dieUsageMsg( array( 'missingparam', 'prefix' ) );
+ }
+
$this->addFields( array(
'iwl_from',
'iwl_prefix',
@@ -74,12 +79,23 @@ class ApiQueryIWLinks extends ApiQueryBase {
);
}
- // Don't order by iwl_from if it's constant in the WHERE clause
- if ( count( $this->getPageSet()->getGoodTitles() ) == 1 ) {
- $this->addOption( 'ORDER BY', 'iwl_prefix' );
+ if ( isset( $params['prefix'] ) ) {
+ $this->addWhereFld( 'iwl_prefix', $params['prefix'] );
+ if ( isset( $params['title'] ) ) {
+ $this->addWhereFld( 'iwl_title', $params['title'] );
+ $this->addOption( 'ORDER BY', 'iwl_from' );
+ } else {
+ $this->addOption( 'ORDER BY', 'iwl_title, iwl_from' );
+ }
} else {
- $this->addOption( 'ORDER BY', 'iwl_from, iwl_prefix' );
+ // Don't order by iwl_from if it's constant in the WHERE clause
+ if ( count( $this->getPageSet()->getGoodTitles() ) == 1 ) {
+ $this->addOption( 'ORDER BY', 'iwl_prefix' );
+ } else {
+ $this->addOption( 'ORDER BY', 'iwl_from, iwl_prefix' );
+ }
}
+
$this->addOption( 'LIMIT', $params['limit'] + 1 );
$res = $this->select( __METHOD__ );
@@ -96,7 +112,7 @@ class ApiQueryIWLinks extends ApiQueryBase {
if ( !is_null( $params['url'] ) ) {
$title = Title::newFromText( "{$row->iwl_prefix}:{$row->iwl_title}" );
if ( $title ) {
- $entry['url'] = $title->getFullURL();
+ $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
}
}
@@ -124,6 +140,8 @@ class ApiQueryIWLinks extends ApiQueryBase {
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
),
'continue' => null,
+ 'prefix' => null,
+ 'title' => null,
);
}
@@ -132,6 +150,8 @@ class ApiQueryIWLinks extends ApiQueryBase {
'url' => 'Whether to get the full URL',
'limit' => 'How many interwiki links to return',
'continue' => 'When more results are available, use this to continue',
+ 'prefix' => 'Prefix for the interwiki',
+ 'title' => "Interwiki link to search for. Must be used with {$this->getModulePrefix()}prefix",
);
}
@@ -141,6 +161,7 @@ class ApiQueryIWLinks extends ApiQueryBase {
public function getPossibleErrors() {
return array_merge( parent::getPossibleErrors(), array(
+ array( 'missingparam', 'prefix' ),
array( 'code' => '_badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
) );
}
@@ -153,6 +174,6 @@ class ApiQueryIWLinks extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryIWLinks.php 77080 2010-11-21 17:27:13Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryIWLinks.php 96475 2011-09-07 19:37:56Z catrope $';
}
}
diff --git a/includes/api/ApiQueryImageInfo.php b/includes/api/ApiQueryImageInfo.php
index 21696be2..5bacd636 100644
--- a/includes/api/ApiQueryImageInfo.php
+++ b/includes/api/ApiQueryImageInfo.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on July 6, 2007
*
@@ -108,17 +108,21 @@ class ApiQueryImageInfo extends ApiQueryBase {
break;
}
+ // Check if we can make the requested thumbnail, and get transform parameters.
+ $finalThumbParams = $this->mergeThumbParams( $img, $scale, $params['urlparam'] );
+
// Get information about the current version first
// Check that the current version is within the start-end boundaries
$gotOne = false;
if (
( is_null( $start ) || $img->getTimestamp() <= $start ) &&
( is_null( $params['end'] ) || $img->getTimestamp() >= $params['end'] )
- )
- {
+ ) {
$gotOne = true;
+
$fit = $this->addPageSubItem( $pageId,
- self::getInfo( $img, $prop, $result, $scale ) );
+ self::getInfo( $img, $prop, $result,
+ $finalThumbParams, $params['metadataversion'] ) );
if ( !$fit ) {
if ( count( $pageIds[NS_IMAGE] ) == 1 ) {
// See the 'the user is screwed' comment above
@@ -147,7 +151,8 @@ class ApiQueryImageInfo extends ApiQueryBase {
break;
}
$fit = $this->addPageSubItem( $pageId,
- self::getInfo( $oldie, $prop, $result ) );
+ self::getInfo( $oldie, $prop, $result,
+ $finalThumbParams, $params['metadataversion'] ) );
if ( !$fit ) {
if ( count( $pageIds[NS_IMAGE] ) == 1 ) {
$this->setContinueEnumParameter( 'start',
@@ -179,14 +184,16 @@ class ApiQueryImageInfo extends ApiQueryBase {
}
/**
- * From parameters, construct a 'scale' array
- * @param $params Array:
+ * From parameters, construct a 'scale' array
+ * @param $params Array: Parameters passed to api.
* @return Array or Null: key-val array of 'width' and 'height', or null
- */
+ */
public function getScale( $params ) {
$p = $this->getModulePrefix();
+
+ // Height and width.
if ( $params['urlheight'] != -1 && $params['urlwidth'] == -1 ) {
- $this->dieUsage( "${p}urlheight cannot be used without {$p}urlwidth", "{$p}urlwidth" );
+ $this->dieUsage( "{$p}urlheight cannot be used without {$p}urlwidth", "{$p}urlwidth" );
}
if ( $params['urlwidth'] != -1 ) {
@@ -195,10 +202,63 @@ class ApiQueryImageInfo extends ApiQueryBase {
$scale['height'] = $params['urlheight'];
} else {
$scale = null;
+ if ( $params['urlparam'] ) {
+ $this->dieUsage( "{$p}urlparam requires {$p}urlwidth", "urlparam_no_width" );
+ }
+ return $scale;
}
+
return $scale;
}
+ /** Validate and merge scale parameters with handler thumb parameters, give error if invalid.
+ *
+ * We do this later than getScale, since we need the image
+ * to know which handler, since handlers can make their own parameters.
+ * @param File $image Image that params are for.
+ * @param Array $thumbParams thumbnail parameters from getScale
+ * @param String $otherParams of otherParams (iiurlparam).
+ * @return Array of parameters for transform.
+ */
+ protected function mergeThumbParams ( $image, $thumbParams, $otherParams ) {
+ if ( !$otherParams ) {
+ return $thumbParams;
+ }
+ $p = $this->getModulePrefix();
+
+ $h = $image->getHandler();
+ if ( !$h ) {
+ $this->setWarning( 'Could not create thumbnail because ' .
+ $image->getName() . ' does not have an associated image handler' );
+ return $thumbParams;
+ }
+
+ $paramList = $h->parseParamString( $otherParams );
+ if ( !$paramList ) {
+ // Just set a warning (instead of dieUsage), as in many cases
+ // we could still render the image using width and height parameters,
+ // and this type of thing could happen between different versions of
+ // handlers.
+ $this->setWarning( "Could not parse {$p}urlparam for " . $image->getName()
+ . '. Using only width and height' );
+ return $thumbParams;
+ }
+
+ if ( isset( $paramList['width'] ) ) {
+ if ( intval( $paramList['width'] ) != intval( $thumbParams['width'] ) ) {
+ $this->dieUsage( "{$p}urlparam had width of {$paramList['width']} but "
+ . "{$p}urlwidth was {$thumbParams['width']}", "urlparam_urlwidth_mismatch" );
+ }
+ }
+
+ foreach ( $paramList as $name => $value ) {
+ if ( !$h->validateParam( $name, $value ) ) {
+ $this->dieUsage( "Invalid value for {$p}urlparam ($name=$value)", "urlparam" );
+ }
+ }
+
+ return $thumbParams + $paramList;
+ }
/**
* Get result information for an image revision
@@ -206,10 +266,11 @@ class ApiQueryImageInfo extends ApiQueryBase {
* @param $file File object
* @param $prop Array of properties to get (in the keys)
* @param $result ApiResult object
- * @param $scale Array containing 'width' and 'height' items, or null
+ * @param $thumbParams Array containing 'width' and 'height' items, or null
+ * @param $version string Version of image metadata (for things like jpeg which have different versions).
* @return Array: result array
*/
- static function getInfo( $file, $prop, $result, $scale = null ) {
+ static function getInfo( $file, $prop, $result, $thumbParams = null, $version = 'latest' ) {
$vals = array();
// Timestamp is shown even if the file is revdelete'd in interface
// so do same here.
@@ -242,7 +303,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
$vals['size'] = intval( $file->getSize() );
$vals['width'] = intval( $file->getWidth() );
$vals['height'] = intval( $file->getHeight() );
-
+
$pageCount = $file->pageCount();
if ( $pageCount !== false ) {
$vals['pagecount'] = $pageCount;
@@ -271,10 +332,11 @@ class ApiQueryImageInfo extends ApiQueryBase {
$sha1 = isset( $prop['sha1'] );
$meta = isset( $prop['metadata'] );
$mime = isset( $prop['mime'] );
+ $mediatype = isset( $prop['mediatype'] );
$archive = isset( $prop['archivename'] );
$bitdepth = isset( $prop['bitdepth'] );
- if ( ( $url || $sha1 || $meta || $mime || $archive || $bitdepth )
+ if ( ( $url || $sha1 || $meta || $mime || $mediatype || $archive || $bitdepth )
&& $file->isDeleted( File::DELETED_FILE ) ) {
$vals['filehidden'] = '';
@@ -283,10 +345,10 @@ class ApiQueryImageInfo extends ApiQueryBase {
}
if ( $url ) {
- if ( !is_null( $scale ) && !$file->isOld() ) {
- $mto = $file->transform( array( 'width' => $scale['width'], 'height' => $scale['height'] ) );
+ if ( !is_null( $thumbParams ) ) {
+ $mto = $file->transform( $thumbParams );
if ( $mto && !$mto->isError() ) {
- $vals['thumburl'] = wfExpandUrl( $mto->getUrl() );
+ $vals['thumburl'] = wfExpandUrl( $mto->getUrl(), PROTO_CURRENT );
// bug 23834 - If the URL's are the same, we haven't resized it, so shouldn't give the wanted
// thumbnail sizes for the thumbnail actual size
@@ -299,32 +361,39 @@ class ApiQueryImageInfo extends ApiQueryBase {
}
if ( isset( $prop['thumbmime'] ) && $file->getHandler() ) {
- list( $ext, $mime ) = $file->getHandler()->getThumbType(
- substr( $mto->getPath(), strrpos( $mto->getPath(), '.' ) + 1 ),
+ list( $ext, $mime ) = $file->getHandler()->getThumbType(
+ substr( $mto->getPath(), strrpos( $mto->getPath(), '.' ) + 1 ),
$file->getMimeType(), $thumbParams );
$vals['thumbmime'] = $mime;
}
- } else if ( $mto && $mto->isError() ) {
+ } elseif ( $mto && $mto->isError() ) {
$vals['thumberror'] = $mto->toText();
}
}
- $vals['url'] = $file->getFullURL();
- $vals['descriptionurl'] = wfExpandUrl( $file->getDescriptionUrl() );
+ $vals['url'] = wfExpandUrl( $file->getFullURL(), PROTO_CURRENT );
+ $vals['descriptionurl'] = wfExpandUrl( $file->getDescriptionUrl(), PROTO_CURRENT );
}
-
+
if ( $sha1 ) {
$vals['sha1'] = wfBaseConvert( $file->getSha1(), 36, 16, 40 );
}
if ( $meta ) {
- $metadata = $file->getMetadata();
- $vals['metadata'] = $metadata ? self::processMetaData( unserialize( $metadata ), $result ) : null;
+ $metadata = unserialize( $file->getMetadata() );
+ if ( $version !== 'latest' ) {
+ $metadata = $file->convertMetadataVersion( $metadata, $version );
+ }
+ $vals['metadata'] = $metadata ? self::processMetaData( $metadata, $result ) : null;
}
if ( $mime ) {
$vals['mime'] = $file->getMimeType();
}
+ if ( $mediatype ) {
+ $vals['mediatype'] = $file->getMediaType();
+ }
+
if ( $archive && $file->isOld() ) {
$vals['archivename'] = $file->getArchiveName();
}
@@ -336,7 +405,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
return $vals;
}
- /*
+ /**
*
* @param $metadata Array
* @param $result ApiResult
@@ -363,6 +432,10 @@ class ApiQueryImageInfo extends ApiQueryBase {
return 'public';
}
+ /**
+ * @param $img File
+ * @return string
+ */
private function getContinueStr( $img ) {
return $img->getOriginalTitle()->getText() .
'|' . $img->getTimestamp();
@@ -396,63 +469,86 @@ class ApiQueryImageInfo extends ApiQueryBase {
ApiBase::PARAM_TYPE => 'integer',
ApiBase::PARAM_DFLT => -1
),
+ 'metadataversion' => array(
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_DFLT => '1',
+ ),
+ 'urlparam' => array(
+ ApiBase::PARAM_DFLT => '',
+ ApiBase::PARAM_TYPE => 'string',
+ ),
'continue' => null,
);
}
/**
* Returns all possible parameters to iiprop
+ *
+ * @param array $filter List of properties to filter out
+ *
+ * @return Array
+ */
+ public static function getPropertyNames( $filter = array() ) {
+ return array_diff( array_keys( self::getProperties() ), $filter );
+ }
+
+ /**
+ * Returns array key value pairs of properties and their descriptions
+ *
+ * @return array
*/
- public static function getPropertyNames() {
+ private static function getProperties() {
return array(
- 'timestamp',
- 'user',
- 'userid',
- 'comment',
- 'parsedcomment',
- 'url',
- 'size',
- 'dimensions', // For backwards compatibility with Allimages
- 'sha1',
- 'mime',
- 'thumbmime',
- 'metadata',
- 'archivename',
- 'bitdepth',
+ 'timestamp' => ' timestamp - Adds timestamp for the uploaded version',
+ 'user' => ' user - Adds the user who uploaded the image version',
+ 'userid' => ' userid - Add the user ID that uploaded the image version',
+ 'comment' => ' comment - Comment on the version',
+ 'parsedcomment' => ' parsedcomment - Parse the comment on the version',
+ 'url' => ' url - Gives URL to the image and the description page',
+ 'size' => ' size - Adds the size of the image in bytes and the height, width and page count (if applicable)',
+ 'dimensions' => ' dimensions - Alias for size', // For backwards compatibility with Allimages
+ 'sha1' => ' sha1 - Adds SHA-1 hash for the image',
+ 'mime' => ' mime - Adds MIME type of the image',
+ 'thumbmime' => ' thumbmime - Adds MIME type of the image thumbnail (requires url)',
+ 'mediatype' => ' mediatype - Adds the media type of the image',
+ 'metadata' => ' metadata - Lists EXIF metadata for the version of the image',
+ 'archivename' => ' archivename - Adds the file name of the archive version for non-latest versions',
+ 'bitdepth' => ' bitdepth - Adds the bit depth of the version',
);
}
+ /**
+ * Returns the descriptions for the properties provided by getPropertyNames()
+ *
+ * @param array $filter List of properties to filter out
+ *
+ * @return array
+ */
+ public static function getPropertyDescriptions( $filter = array() ) {
+ return array_merge(
+ array( 'What image information to get:' ),
+ array_values( array_diff_key( self::getProperties(), array_flip( $filter ) ) )
+ );
+ }
/**
- * Return the API documentation for the parameters.
- * @return {Array} parameter documentation.
+ * Return the API documentation for the parameters.
+ * @return Array parameter documentation.
*/
public function getParamDescription() {
$p = $this->getModulePrefix();
return array(
- 'prop' => array(
- 'What image information to get:',
- ' timestamp - Adds timestamp for the uploaded version',
- ' user - Adds the user who uploaded the image version',
- ' userid - Add the user id that uploaded the image version',
- ' comment - Comment on the version',
- ' parsedcomment - Parse the comment on the version',
- ' url - Gives URL to the image and the description page',
- ' size - Adds the size of the image in bytes and the height and width',
- ' dimensions - Alias for size',
- ' sha1 - Adds sha1 hash for the image',
- ' mime - Adds MIME of the image',
- ' thumbmime - Adss MIME of the image thumbnail (requires url)',
- ' metadata - Lists EXIF metadata for the version of the image',
- ' archivename - Adds the file name of the archive version for non-latest versions',
- ' bitdepth - Adds the bit depth of the version',
- ),
+ 'prop' => self::getPropertyDescriptions(),
'urlwidth' => array( "If {$p}prop=url is set, a URL to an image scaled to this width will be returned.",
'Only the current version of the image can be scaled' ),
'urlheight' => "Similar to {$p}urlwidth. Cannot be used without {$p}urlwidth",
+ 'urlparam' => array( "A handler specific parameter string. For example, pdf's ",
+ "might use 'page15-100px'. {$p}urlwidth must be used and be consistent with {$p}urlparam" ),
'limit' => 'How many image revisions to return',
'start' => 'Timestamp to start listing from',
'end' => 'Timestamp to stop listing at',
+ 'metadataversion' => array( "Version of metadata to use. if 'latest' is specified, use latest version.",
+ "Defaults to '1' for backwards compatibility" ),
'continue' => 'If the query response includes a continue value, use it here to get another page of results'
);
}
@@ -462,8 +558,13 @@ class ApiQueryImageInfo extends ApiQueryBase {
}
public function getPossibleErrors() {
+ $p = $this->getModulePrefix();
return array_merge( parent::getPossibleErrors(), array(
- array( 'code' => 'iiurlwidth', 'info' => 'iiurlheight cannot be used without iiurlwidth' ),
+ array( 'code' => "{$p}urlwidth", 'info' => "{$p}urlheight cannot be used without {$p}urlwidth" ),
+ array( 'code' => 'urlparam', 'info' => "Invalid value for {$p}urlparam" ),
+ array( 'code' => 'urlparam_no_width', 'info' => "{$p}urlparam requires {$p}urlwidth" ),
+ array( 'code' => 'urlparam_urlwidth_mismatch', 'info' => "The width set in {$p}urlparm doesnt't " .
+ "match the one in {$p}urlwidth" ),
) );
}
@@ -474,7 +575,11 @@ class ApiQueryImageInfo extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#imageinfo_.2F_ii';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryImageInfo.php 85435 2011-04-05 14:00:08Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryImageInfo.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryImages.php b/includes/api/ApiQueryImages.php
index af2920c7..9dfdf341 100644
--- a/includes/api/ApiQueryImages.php
+++ b/includes/api/ApiQueryImages.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on May 13, 2007
*
@@ -48,6 +48,9 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ */
private function run( $resultPageSet = null ) {
if ( $this->getPageSet()->getGoodTitleCount() == 0 ) {
return; // nothing to do
@@ -84,6 +87,19 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
}
$this->addOption( 'LIMIT', $params['limit'] + 1 );
+ if ( !is_null( $params['images'] ) ) {
+ $images = array();
+ foreach ( $params['images'] as $img ) {
+ $title = Title::newFromText( $img );
+ if ( !$title || $title->getNamespace() != NS_FILE ) {
+ $this->setWarning( "``$img'' is not a file" );
+ } else {
+ $images[] = $title->getDBkey();
+ }
+ }
+ $this->addWhereFld( 'il_to', $images );
+ }
+
$res = $this->select( __METHOD__ );
if ( is_null( $resultPageSet ) ) {
@@ -136,6 +152,9 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
),
'continue' => null,
+ 'images' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ )
);
}
@@ -143,6 +162,7 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
return array(
'limit' => 'How many images to return',
'continue' => 'When more results are available, use this to continue',
+ 'images' => 'Only list these images. Useful for checking whether a certain page has a certain Image.',
);
}
@@ -165,7 +185,11 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#images_.2F_im';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryImages.php 73543 2010-09-22 16:50:09Z platonides $';
+ return __CLASS__ . ': $Id: ApiQueryImages.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php
index 59f61de1..fef1c6fc 100644
--- a/includes/api/ApiQueryInfo.php
+++ b/includes/api/ApiQueryInfo.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 25, 2006
*
@@ -41,12 +41,23 @@ class ApiQueryInfo extends ApiQueryBase {
$fld_readable = false, $fld_watched = false,
$fld_preload = false, $fld_displaytitle = false;
+ private $params, $titles, $missing, $everything, $pageCounter;
+
+ private $pageRestrictions, $pageIsRedir, $pageIsNew, $pageTouched,
+ $pageLatest, $pageLength;
+
+ private $protections, $watched, $talkids, $subjectids, $displaytitles;
+
private $tokenFunctions;
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'in' );
}
+ /**
+ * @param $pageSet ApiPageSet
+ * @return void
+ */
public function requestExtraData( $pageSet ) {
global $wgDisableCounters;
@@ -87,6 +98,7 @@ class ApiQueryInfo extends ApiQueryBase {
'unblock' => array( 'ApiQueryInfo', 'getUnblockToken' ),
'email' => array( 'ApiQueryInfo', 'getEmailToken' ),
'import' => array( 'ApiQueryInfo', 'getImportToken' ),
+ 'watch' => array( 'ApiQueryInfo', 'getWatchToken'),
);
wfRunHooks( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) );
return $this->tokenFunctions;
@@ -193,7 +205,7 @@ class ApiQueryInfo extends ApiQueryBase {
public static function getImportToken( $pageid, $title ) {
global $wgUser;
- if ( !$wgUser->isAllowed( 'import' ) ) {
+ if ( !$wgUser->isAllowedAny( 'import', 'importupload' ) ) {
return false;
}
@@ -206,6 +218,21 @@ class ApiQueryInfo extends ApiQueryBase {
return $cachedImportToken;
}
+ public static function getWatchToken( $pageid, $title ) {
+ global $wgUser;
+ if ( !$wgUser->isLoggedIn() ) {
+ return false;
+ }
+
+ static $cachedWatchToken = null;
+ if ( !is_null( $cachedWatchToken ) ) {
+ return $cachedWatchToken;
+ }
+
+ $cachedWatchToken = $wgUser->editToken( 'watch' );
+ return $cachedWatchToken;
+ }
+
public function execute() {
$this->params = $this->extractRequestParams();
if ( !is_null( $this->params['prop'] ) ) {
@@ -353,8 +380,8 @@ class ApiQueryInfo extends ApiQueryBase {
}
if ( $this->fld_url ) {
- $pageInfo['fullurl'] = $title->getFullURL();
- $pageInfo['editurl'] = $title->getFullURL( 'action=edit' );
+ $pageInfo['fullurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
+ $pageInfo['editurl'] = wfExpandUrl( $title->getFullURL( 'action=edit' ), PROTO_CURRENT );
}
if ( $this->fld_readable && $title->userCanRead() ) {
$pageInfo['readable'] = '';
@@ -386,6 +413,7 @@ class ApiQueryInfo extends ApiQueryBase {
* Get information about protections and put it in $protections
*/
private function getProtectionInfo() {
+ global $wgContLang;
$this->protections = array();
$db = $this->getDB();
@@ -404,7 +432,7 @@ class ApiQueryInfo extends ApiQueryBase {
$a = array(
'type' => $row->pr_type,
'level' => $row->pr_level,
- 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 )
+ 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 )
);
if ( $row->pr_cascade ) {
$a['cascade'] = '';
@@ -461,7 +489,7 @@ class ApiQueryInfo extends ApiQueryBase {
$this->protections[$row->pt_namespace][$row->pt_title][] = array(
'type' => 'create',
'level' => $row->pt_create_perm,
- 'expiry' => Block::decodeExpiry( $row->pt_expiry, TS_ISO_8601 )
+ 'expiry' => $wgContLang->formatExpiry( $row->pt_expiry, TS_ISO_8601 )
);
}
}
@@ -495,7 +523,7 @@ class ApiQueryInfo extends ApiQueryBase {
$this->protections[$row->tl_namespace][$row->tl_title][] = array(
'type' => $row->pr_type,
'level' => $row->pr_level,
- 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 ),
+ 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ),
'source' => $source->getPrefixedText()
);
}
@@ -518,7 +546,7 @@ class ApiQueryInfo extends ApiQueryBase {
$this->protections[NS_FILE][$row->il_to][] = array(
'type' => $row->pr_type,
'level' => $row->pr_level,
- 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 ),
+ 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ),
'source' => $source->getPrefixedText()
);
}
@@ -700,7 +728,11 @@ class ApiQueryInfo extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#info_.2F_in';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryInfo.php 78439 2010-12-15 14:23:46Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryInfo.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryLangBacklinks.php b/includes/api/ApiQueryLangBacklinks.php
new file mode 100644
index 00000000..e09384e5
--- /dev/null
+++ b/includes/api/ApiQueryLangBacklinks.php
@@ -0,0 +1,220 @@
+<?php
+/**
+ * API for MediaWiki 1.17+
+ *
+ * Created on May 14, 2011
+ *
+ * Copyright © 2011 Sam Reed
+ * Copyright © 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ // Eclipse helper - will be ignored in production
+ require_once( "ApiQueryBase.php" );
+}
+
+/**
+ * This gives links pointing to the given interwiki
+ * @ingroup API
+ */
+class ApiQueryLangBacklinks extends ApiQueryGeneratorBase {
+
+ public function __construct( $query, $moduleName ) {
+ parent::__construct( $query, $moduleName, 'lbl' );
+ }
+
+ public function execute() {
+ $this->run();
+ }
+
+ public function executeGenerator( $resultPageSet ) {
+ $this->run( $resultPageSet );
+ }
+
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
+ public function run( $resultPageSet = null ) {
+ $params = $this->extractRequestParams();
+
+ if ( isset( $params['title'] ) && !isset( $params['lang'] ) ) {
+ $this->dieUsageMsg( array( 'missingparam', 'lang' ) );
+ }
+
+ if ( !is_null( $params['continue'] ) ) {
+ $cont = explode( '|', $params['continue'] );
+ if ( count( $cont ) != 3 ) {
+ $this->dieUsage( 'Invalid continue param. You should pass the ' .
+ 'original value returned by the previous query', '_badcontinue' );
+ }
+
+ $prefix = $this->getDB()->strencode( $cont[0] );
+ $title = $this->getDB()->strencode( $this->titleToKey( $cont[1] ) );
+ $from = intval( $cont[2] );
+ $this->addWhere(
+ "ll_lang > '$prefix' OR " .
+ "(ll_lang = '$prefix' AND " .
+ "(ll_title > '$title' OR " .
+ "(ll_title = '$title' AND " .
+ "ll_from >= $from)))"
+ );
+ }
+
+ $prop = array_flip( $params['prop'] );
+ $lllang = isset( $prop['lllang'] );
+ $lltitle = isset( $prop['lltitle'] );
+
+ $this->addTables( array( 'langlinks', 'page' ) );
+ $this->addWhere( 'll_from = page_id' );
+
+ $this->addFields( array( 'page_id', 'page_title', 'page_namespace', 'page_is_redirect',
+ 'll_from', 'll_lang', 'll_title' ) );
+
+ if ( isset( $params['lang'] ) ) {
+ $this->addWhereFld( 'll_lang', $params['lang'] );
+ if ( isset( $params['title'] ) ) {
+ $this->addWhereFld( 'll_title', $params['title'] );
+ $this->addOption( 'ORDER BY', 'll_from' );
+ } else {
+ $this->addOption( 'ORDER BY', 'll_title, ll_from' );
+ }
+ } else {
+ $this->addOption( 'ORDER BY', 'll_lang, ll_title, ll_from' );
+ }
+
+ $this->addOption( 'LIMIT', $params['limit'] + 1 );
+
+ $res = $this->select( __METHOD__ );
+
+ $pages = array();
+
+ $count = 0;
+ $result = $this->getResult();
+ foreach ( $res as $row ) {
+ if ( ++ $count > $params['limit'] ) {
+ // We've reached the one extra which shows that there are additional pages to be had. Stop here...
+ // Continue string preserved in case the redirect query doesn't pass the limit
+ $this->setContinueEnumParameter( 'continue', "{$row->ll_lang}|{$row->ll_title}|{$row->ll_from}" );
+ break;
+ }
+
+ if ( !is_null( $resultPageSet ) ) {
+ $pages[] = Title::newFromRow( $row );
+ } else {
+ $entry = array( 'pageid' => $row->page_id );
+
+ $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+ ApiQueryBase::addTitleInfo( $entry, $title );
+
+ if ( $row->page_is_redirect ) {
+ $entry['redirect'] = '';
+ }
+
+ if ( $lllang ) {
+ $entry['lllang'] = $row->ll_lang;
+ }
+
+ if ( $lltitle ) {
+ $entry['lltitle'] = $row->ll_title;
+ }
+
+ $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $entry );
+ if ( !$fit ) {
+ $this->setContinueEnumParameter( 'continue', "{$row->ll_lang}|{$row->ll_title}|{$row->ll_from}" );
+ break;
+ }
+ }
+ }
+
+ if ( is_null( $resultPageSet ) ) {
+ $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'll' );
+ } else {
+ $resultPageSet->populateFromTitles( $pages );
+ }
+ }
+
+ public function getCacheMode( $params ) {
+ return 'public';
+ }
+
+ public function getAllowedParams() {
+ return array(
+ 'lang' => null,
+ 'title' => null,
+ 'continue' => null,
+ 'limit' => array(
+ ApiBase::PARAM_DFLT => 10,
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MIN => 1,
+ ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
+ ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
+ ),
+ 'prop' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_DFLT => '',
+ ApiBase::PARAM_TYPE => array(
+ 'lllang',
+ 'lltitle',
+ ),
+ ),
+ );
+ }
+
+ public function getParamDescription() {
+ return array(
+ 'lang' => 'Language for the language link',
+ 'title' => "Language link to search for. Must be used with {$this->getModulePrefix()}lang",
+ 'continue' => 'When more results are available, use this to continue',
+ 'prop' => array(
+ 'Which properties to get',
+ ' lllang - Adds the language code of the language link',
+ ' lltitle - Adds the title of the language ink',
+ ),
+ 'limit' => 'How many total pages to return',
+ );
+ }
+
+ public function getDescription() {
+ return array( 'Find all pages that link to the given language link.',
+ 'Can be used to find all links with a language code, or',
+ 'all links to a title (with a given language).',
+ 'Using neither parameter is effectively "All Language Links"',
+ );
+ }
+
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(), array(
+ array( 'missingparam', 'lang' ),
+ array( 'code' => '_badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
+ ) );
+ }
+
+ protected function getExamples() {
+ return array(
+ 'api.php?action=query&list=langbacklinks&lbltitle=Test&lbllang=fr',
+ 'api.php?action=query&generator=langbacklinks&glbltitle=Test&lbllang=fr&prop=info'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryLangBacklinks.php 88429 2011-05-19 21:13:03Z reedy $';
+ }
+}
diff --git a/includes/api/ApiQueryLangLinks.php b/includes/api/ApiQueryLangLinks.php
index c2ecbfee..b2a974ad 100644
--- a/includes/api/ApiQueryLangLinks.php
+++ b/includes/api/ApiQueryLangLinks.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on May 13, 2007
*
@@ -46,6 +46,11 @@ class ApiQueryLangLinks extends ApiQueryBase {
}
$params = $this->extractRequestParams();
+
+ if ( isset( $params['title'] ) && !isset( $params['lang'] ) ) {
+ $this->dieUsageMsg( array( 'missingparam', 'lang' ) );
+ }
+
$this->addFields( array(
'll_from',
'll_lang',
@@ -69,12 +74,23 @@ class ApiQueryLangLinks extends ApiQueryBase {
);
}
- // Don't order by ll_from if it's constant in the WHERE clause
- if ( count( $this->getPageSet()->getGoodTitles() ) == 1 ) {
- $this->addOption( 'ORDER BY', 'll_lang' );
+ if ( isset( $params['lang'] ) ) {
+ $this->addWhereFld( 'll_lang', $params['lang'] );
+ if ( isset( $params['title'] ) ) {
+ $this->addWhereFld( 'll_title', $params['title'] );
+ $this->addOption( 'ORDER BY', 'll_from' );
+ } else {
+ $this->addOption( 'ORDER BY', 'll_title, ll_from' );
+ }
} else {
- $this->addOption( 'ORDER BY', 'll_from, ll_lang' );
+ // Don't order by ll_from if it's constant in the WHERE clause
+ if ( count( $this->getPageSet()->getGoodTitles() ) == 1 ) {
+ $this->addOption( 'ORDER BY', 'll_lang' );
+ } else {
+ $this->addOption( 'ORDER BY', 'll_from, ll_lang' );
+ }
}
+
$this->addOption( 'LIMIT', $params['limit'] + 1 );
$res = $this->select( __METHOD__ );
@@ -90,7 +106,7 @@ class ApiQueryLangLinks extends ApiQueryBase {
if ( $params['url'] ) {
$title = Title::newFromText( "{$row->ll_lang}:{$row->ll_title}" );
if ( $title ) {
- $entry['url'] = $title->getFullURL();
+ $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
}
}
ApiResult::setContent( $entry, $row->ll_title );
@@ -117,6 +133,8 @@ class ApiQueryLangLinks extends ApiQueryBase {
),
'continue' => null,
'url' => false,
+ 'lang' => null,
+ 'title' => null,
);
}
@@ -125,6 +143,8 @@ class ApiQueryLangLinks extends ApiQueryBase {
'limit' => 'How many langlinks to return',
'continue' => 'When more results are available, use this to continue',
'url' => 'Whether to get the full URL',
+ 'lang' => 'Language code',
+ 'title' => "Link to search for. Must be used with {$this->getModulePrefix()}lang",
);
}
@@ -134,6 +154,7 @@ class ApiQueryLangLinks extends ApiQueryBase {
public function getPossibleErrors() {
return array_merge( parent::getPossibleErrors(), array(
+ array( 'missingparam', 'lang' ),
array( 'code' => '_badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
) );
}
@@ -145,7 +166,11 @@ class ApiQueryLangLinks extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#langlinks_.2F_ll';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryLangLinks.php 77660 2010-12-03 14:44:07Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryLangLinks.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryLinks.php b/includes/api/ApiQueryLinks.php
index 4f3bad3b..fa2495a9 100644
--- a/includes/api/ApiQueryLinks.php
+++ b/includes/api/ApiQueryLinks.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on May 12, 2007
*
@@ -39,7 +39,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
const LINKS = 'links';
const TEMPLATES = 'templates';
- private $table, $prefix, $description;
+ private $table, $prefix, $description, $helpUrl;
public function __construct( $query, $moduleName ) {
switch ( $moduleName ) {
@@ -48,12 +48,14 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
$this->prefix = 'pl';
$this->description = 'link';
$this->titlesParam = 'titles';
+ $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#links_.2F_pl';
break;
case self::TEMPLATES:
$this->table = 'templatelinks';
$this->prefix = 'tl';
$this->description = 'template';
$this->titlesParam = 'templates';
+ $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#templates_.2F_tl';
break;
default:
ApiBase::dieDebug( __METHOD__, 'Unknown module name' );
@@ -74,6 +76,10 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return
+ */
private function run( $resultPageSet = null ) {
if ( $this->getPageSet()->getGoodTitleCount() == 0 ) {
return; // nothing to do
@@ -213,7 +219,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
);
if ( $this->getModuleName() == self::LINKS ) {
$arr[$this->titlesParam] = 'Only list links to these titles. Useful for checking whether a certain page links to a certain title.';
- } else if ( $this->getModuleName() == self::TEMPLATES ) {
+ } elseif ( $this->getModuleName() == self::TEMPLATES ) {
$arr[$this->titlesParam] = 'Only list these templates. Useful for checking whether a certain page uses a certain template.';
}
return $arr;
@@ -234,7 +240,11 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return $this->helpUrl;
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryLinks.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryLinks.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php
index 7d69ca39..1420e0a7 100644
--- a/includes/api/ApiQueryLogEvents.php
+++ b/includes/api/ApiQueryLogEvents.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 16, 2006
*
@@ -86,13 +86,10 @@ class ApiQueryLogEvents extends ApiQueryBase {
'log_deleted',
) );
- $this->addFieldsIf( 'log_id', $this->fld_ids );
- $this->addFieldsIf( 'page_id', $this->fld_ids );
- $this->addFieldsIf( 'log_user', $this->fld_user );
- $this->addFieldsIf( 'user_name', $this->fld_user );
+ $this->addFieldsIf( array( 'log_id', 'page_id' ), $this->fld_ids );
+ $this->addFieldsIf( array( 'log_user', 'user_name' ), $this->fld_user );
$this->addFieldsIf( 'user_id', $this->fld_userid );
- $this->addFieldsIf( 'log_namespace', $this->fld_title || $this->fld_parsedcomment );
- $this->addFieldsIf( 'log_title', $this->fld_title || $this->fld_parsedcomment );
+ $this->addFieldsIf( array( 'log_namespace', 'log_title' ), $this->fld_title || $this->fld_parsedcomment );
$this->addFieldsIf( 'log_comment', $this->fld_comment || $this->fld_parsedcomment );
$this->addFieldsIf( 'log_params', $this->fld_details );
@@ -114,13 +111,12 @@ class ApiQueryLogEvents extends ApiQueryBase {
list( $type, $action ) = explode( '/', $params['action'] );
$this->addWhereFld( 'log_type', $type );
$this->addWhereFld( 'log_action', $action );
- }
- else if ( !is_null( $params['type'] ) ) {
+ } elseif ( !is_null( $params['type'] ) ) {
$this->addWhereFld( 'log_type', $params['type'] );
$index['logging'] = 'type_time';
}
- $this->addWhereRange( 'log_timestamp', $params['dir'], $params['start'], $params['end'] );
+ $this->addTimestampWhereRange( 'log_timestamp', $params['dir'], $params['start'], $params['end'] );
$limit = $params['limit'];
$this->addOption( 'LIMIT', $limit + 1 );
@@ -148,6 +144,22 @@ class ApiQueryLogEvents extends ApiQueryBase {
$index['logging'] = is_null( $user ) ? 'page_time' : array( 'page_time', 'user_time' );
}
+ $prefix = $params['prefix'];
+
+ if ( !is_null( $prefix ) ) {
+ global $wgMiserMode;
+ if ( $wgMiserMode ) {
+ $this->dieUsage( 'Prefix search disabled in Miser Mode', 'prefixsearchdisabled' );
+ }
+
+ $title = Title::newFromText( $prefix );
+ if ( is_null( $title ) ) {
+ $this->dieUsage( "Bad title value '$prefix'", 'param_prefix' );
+ }
+ $this->addWhereFld( 'log_namespace', $title->getNamespace() );
+ $this->addWhere( 'log_title ' . $db->buildLike( $title->getDBkey(), $db->anyString() ) );
+ }
+
$this->addOption( 'USE INDEX', $index );
// Paranoia: avoid brute force searches (bug 17342)
@@ -160,6 +172,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
$count = 0;
$res = $this->select( __METHOD__ );
+ $result = $this->getResult();
foreach ( $res as $row ) {
if ( ++ $count > $limit ) {
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
@@ -171,25 +184,25 @@ class ApiQueryLogEvents extends ApiQueryBase {
if ( !$vals ) {
continue;
}
- $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ), null, $vals );
+ $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $vals );
if ( !$fit ) {
$this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->log_timestamp ) );
break;
}
}
- $this->getResult()->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'item' );
+ $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'item' );
}
/**
- * @static
* @param $result ApiResult
- * @param $vals
- * @param $params
- * @param $type
+ * @param $vals array
+ * @param $params string
+ * @param $type string
+ * @param $action string
* @param $ts
* @return array
*/
- public static function addLogParams( $result, &$vals, $params, $type, $ts ) {
+ public static function addLogParams( $result, &$vals, $params, $type, $action, $ts ) {
$params = explode( "\n", $params );
switch ( $type ) {
case 'move':
@@ -219,11 +232,14 @@ class ApiQueryLogEvents extends ApiQueryBase {
$params = null;
break;
case 'block':
+ if ( $action == 'unblock' ) {
+ break;
+ }
$vals2 = array();
list( $vals2['duration'], $vals2['flags'] ) = $params;
// Indefinite blocks have no expiry time
- if ( Block::parseExpiryInput( $params[0] ) !== Block::infinity() ) {
+ if ( SpecialBlock::parseExpiryInput( $params[0] ) !== wfGetDB( DB_SLAVE )->getInfinity() ) {
$vals2['expiry'] = wfTimestamp( TS_ISO_8601,
strtotime( $params[0], wfTimestamp( TS_UNIX, $ts ) ) );
}
@@ -268,8 +284,11 @@ class ApiQueryLogEvents extends ApiQueryBase {
$vals['actionhidden'] = '';
} else {
self::addLogParams(
- $this->getResult(), $vals,
- $row->log_params, $row->log_type,
+ $this->getResult(),
+ $vals,
+ $row->log_params,
+ $row->log_type,
+ $row->log_action,
$row->log_timestamp
);
}
@@ -285,7 +304,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
if ( $this->fld_userid ) {
$vals['userid'] = $row->user_id;
}
-
+
if ( !$row->log_user ) {
$vals['anon'] = '';
}
@@ -372,6 +391,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
),
'user' => null,
'title' => null,
+ 'prefix' => null,
'tag' => null,
'limit' => array(
ApiBase::PARAM_DFLT => 10,
@@ -384,27 +404,29 @@ class ApiQueryLogEvents extends ApiQueryBase {
}
public function getParamDescription() {
+ $p = $this->getModulePrefix();
return array(
'prop' => array(
'Which properties to get',
- ' ids - Adds the id of the log event',
+ ' ids - Adds the ID of the log event',
' title - Adds the title of the page for the log event',
' type - Adds the type of log event',
' user - Adds the user responsible for the log event',
- ' userid - Adds the user id who was responsible for the log event',
+ ' userid - Adds the user ID who was responsible for the log event',
' timestamp - Adds the timestamp for the event',
' comment - Adds the comment of the event',
' parsedcomment - Adds the parsed comment of the event',
' details - Lists addtional details about the event',
' tags - Lists tags for the event',
),
- 'type' => 'Filter log entries to only this type(s)',
- 'action' => "Filter log actions to only this type. Overrides {$this->getModulePrefix()}type",
+ 'type' => 'Filter log entries to only this type',
+ 'action' => "Filter log actions to only this type. Overrides {$p}type",
'start' => 'The timestamp to start enumerating from',
'end' => 'The timestamp to end enumerating',
- 'dir' => 'In which direction to enumerate',
+ 'dir' => $this->getDirectionDescription( $p ),
'user' => 'Filter entries to those made by the given user',
'title' => 'Filter entries to those related to a page',
+ 'prefix' => 'Filter entries that start with this prefix. Disabled in Miser Mode',
'limit' => 'How many total event entries to return',
'tag' => 'Only list event entries tagged with this tag',
);
@@ -418,6 +440,8 @@ class ApiQueryLogEvents extends ApiQueryBase {
return array_merge( parent::getPossibleErrors(), array(
array( 'code' => 'param_user', 'info' => 'User name $user not found' ),
array( 'code' => 'param_title', 'info' => 'Bad title value \'title\'' ),
+ array( 'code' => 'param_prefix', 'info' => 'Bad title value \'prefix\'' ),
+ array( 'code' => 'prefixsearchdisabled', 'info' => 'Prefix search disabled in Miser Mode' ),
) );
}
@@ -427,7 +451,11 @@ class ApiQueryLogEvents extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Logevents';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryLogEvents.php 74535 2010-10-09 00:01:45Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryLogEvents.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryPageProps.php b/includes/api/ApiQueryPageProps.php
index 894e812d..64b8511d 100644
--- a/includes/api/ApiQueryPageProps.php
+++ b/includes/api/ApiQueryPageProps.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Aug 7, 2010
*
@@ -43,55 +43,59 @@ class ApiQueryPageProps extends ApiQueryBase {
}
public function execute() {
- $this->params = $this->extractRequestParams();
-
# Only operate on existing pages
$pages = $this->getPageSet()->getGoodTitles();
if ( !count( $pages ) ) {
# Nothing to do
return;
}
-
+
+ $this->params = $this->extractRequestParams();
+
$this->addTables( 'page_props' );
$this->addFields( array( 'pp_page', 'pp_propname', 'pp_value' ) );
$this->addWhereFld( 'pp_page', array_keys( $pages ) );
-
+
if ( $this->params['continue'] ) {
$this->addWhere( 'pp_page >=' . intval( $this->params['continue'] ) );
}
-
+
+ if ( $this->params['prop'] ) {
+ $this->addWhereFld( 'pp_propname', $this->params['prop'] );
+ }
+
# Force a sort order to ensure that properties are grouped by page
$this->addOption( 'ORDER BY', 'pp_page' );
-
+
$res = $this->select( __METHOD__ );
$currentPage = 0; # Id of the page currently processed
$props = array();
$result = $this->getResult();
-
+
foreach ( $res as $row ) {
if ( $currentPage != $row->pp_page ) {
- # Different page than previous row, so add the properties to
+ # Different page than previous row, so add the properties to
# the result and save the new page id
-
+
if ( $currentPage ) {
if ( !$this->addPageProps( $result, $currentPage, $props ) ) {
# addPageProps() indicated that the result did not fit
# so stop adding data. Reset props so that it doesn't
# get added again after loop exit
-
+
$props = array();
break;
}
-
+
$props = array();
}
-
+
$currentPage = $row->pp_page;
}
-
+
$props[$row->pp_propname] = $row->pp_value;
}
-
+
if ( count( $props ) ) {
# Add any remaining properties to the results
$this->addPageProps( $result, $currentPage, $props );
@@ -99,7 +103,7 @@ class ApiQueryPageProps extends ApiQueryBase {
}
/**
- * Add page properties to an ApiResult, adding a continue
+ * Add page properties to an ApiResult, adding a continue
* parameter if it doesn't fit.
*
* @param $result ApiResult
@@ -109,7 +113,7 @@ class ApiQueryPageProps extends ApiQueryBase {
*/
private function addPageProps( $result, $page, $props ) {
$fit = $result->addValue( array( 'query', 'pages', $page ), 'pageprops', $props );
-
+
if ( !$fit ) {
$this->setContinueEnumParameter( 'continue', $page );
}
@@ -120,31 +124,35 @@ class ApiQueryPageProps extends ApiQueryBase {
return 'public';
}
- public function getAllowedParams() {
- return array( 'continue' => null );
+ public function getAllowedParams() {
+ return array(
+ 'continue' => null,
+ 'prop' => null,
+ );
}
public function getParamDescription() {
- return array( 'continue' => 'When more results are available, use this to continue' );
+ return array(
+ 'continue' => 'When more results are available, use this to continue',
+ 'prop' => 'Page prop to look on the page for. Useful for checking whether a certain page uses a certain page prop.'
+ );
}
public function getDescription() {
return 'Get various properties defined in the page content';
}
- public function getPossibleErrors() {
- return array_merge( parent::getPossibleErrors(), array(
- array( 'code' => '_badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
- ) );
- }
-
protected function getExamples() {
return array(
'api.php?action=query&prop=pageprops&titles=Category:Foo',
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#pageprops_.2F_pp';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryPageProps.php 85211 2011-04-02 21:01:00Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryPageProps.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryProtectedTitles.php b/includes/api/ApiQueryProtectedTitles.php
index e647c39f..14df7446 100644
--- a/includes/api/ApiQueryProtectedTitles.php
+++ b/includes/api/ApiQueryProtectedTitles.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Feb 13, 2009
*
- * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,6 +48,10 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$params = $this->extractRequestParams();
@@ -60,7 +64,7 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
$this->addFieldsIf( 'pt_expiry', isset( $prop['expiry'] ) );
$this->addFieldsIf( 'pt_create_perm', isset( $prop['level'] ) );
- $this->addWhereRange( 'pt_timestamp', $params['dir'], $params['start'], $params['end'] );
+ $this->addTimestampWhereRange( 'pt_timestamp', $params['dir'], $params['start'], $params['end'] );
$this->addWhereFld( 'pt_namespace', $params['namespace'] );
$this->addWhereFld( 'pt_create_perm', $params['level'] );
@@ -77,6 +81,9 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
$count = 0;
$result = $this->getResult();
+
+ $titles = array();
+
foreach ( $res as $row ) {
if ( ++ $count > $params['limit'] ) {
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
@@ -110,7 +117,8 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
}
if ( isset( $prop['expiry'] ) ) {
- $vals['expiry'] = Block::decodeExpiry( $row->pt_expiry, TS_ISO_8601 );
+ global $wgContLang;
+ $vals['expiry'] = $wgContLang->formatExpiry( $row->pt_expiry, TS_ISO_8601 );
}
if ( isset( $prop['level'] ) ) {
@@ -165,8 +173,8 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
'dir' => array(
ApiBase::PARAM_DFLT => 'older',
ApiBase::PARAM_TYPE => array(
- 'older',
- 'newer'
+ 'newer',
+ 'older'
)
),
'start' => array(
@@ -196,13 +204,13 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
'namespace' => 'Only list titles in these namespaces',
'start' => 'Start listing at this protection timestamp',
'end' => 'Stop listing at this protection timestamp',
- 'dir' => 'The direction in which to list',
+ 'dir' => $this->getDirectionDescription( $this->getModulePrefix() ),
'limit' => 'How many total pages to return',
'prop' => array(
'Which properties to get',
' timestamp - Adds the timestamp of when protection was added',
- ' user - Adds the user to add the protection',
- ' userid - Adds the user id to add the protection',
+ ' user - Adds the user that added the protection',
+ ' userid - Adds the user id that added the protection',
' comment - Adds the comment for the protection',
' parsedcomment - Adds the parsed comment for the protection',
' expiry - Adds the timestamp of when the protection will be lifted',
@@ -222,7 +230,11 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Protectedtitles';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryProtectedTitles.php 71838 2010-08-28 01:18:18Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryProtectedTitles.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryQueryPage.php b/includes/api/ApiQueryQueryPage.php
new file mode 100644
index 00000000..e22cf8eb
--- /dev/null
+++ b/includes/api/ApiQueryQueryPage.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ *
+ *
+ * Created on Dec 22, 2010
+ *
+ * Copyright © 2010 Roan Kattouw <Firstname>.<Lastname>@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ // Eclipse helper - will be ignored in production
+ require_once( 'ApiQueryBase.php' );
+}
+
+/**
+ * Query module to get the results of a QueryPage-based special page
+ *
+ * @ingroup API
+ */
+class ApiQueryQueryPage extends ApiQueryGeneratorBase {
+ private $qpMap;
+
+ /**
+ * Some query pages are useless because they're available elsewhere in the API
+ */
+ private $uselessQueryPages = array(
+ 'MIMEsearch', // aiprop=mime
+ 'LinkSearch', // list=exturlusage
+ 'FileDuplicateSearch', // prop=duplicatefiles
+ );
+
+ public function __construct( $query, $moduleName ) {
+ parent::__construct( $query, $moduleName, 'qp' );
+ // We need to do this to make sure $wgQueryPages is set up
+ // This SUCKS
+ global $IP;
+ require_once( "$IP/includes/QueryPage.php" );
+
+ // Build mapping from special page names to QueryPage classes
+ global $wgQueryPages;
+ $this->qpMap = array();
+ foreach ( $wgQueryPages as $page ) {
+ if( !in_array( $page[1], $this->uselessQueryPages ) ) {
+ $this->qpMap[$page[1]] = $page[0];
+ }
+ }
+ }
+
+ public function execute() {
+ $this->run();
+ }
+
+ public function executeGenerator( $resultPageSet ) {
+ $this->run( $resultPageSet );
+ }
+
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
+ public function run( $resultPageSet = null ) {
+ global $wgUser;
+ $params = $this->extractRequestParams();
+ $result = $this->getResult();
+
+ $qp = new $this->qpMap[$params['page']]();
+ if ( !$qp->userCanExecute( $wgUser ) ) {
+ $this->dieUsageMsg( 'specialpage-cantexecute' );
+ }
+
+ $r = array( 'name' => $params['page'] );
+ if ( $qp->isCached() ) {
+ if ( !$qp->isCacheable() ) {
+ $r['disabled'] = '';
+ } else {
+ $r['cached'] = '';
+ $ts = $qp->getCachedTimestamp();
+ if ( $ts ) {
+ $r['cachedtimestamp'] = wfTimestamp( TS_ISO_8601, $ts );
+ }
+ }
+ }
+ $result->addValue( array( 'query' ), $this->getModuleName(), $r );
+
+ if ( $qp->isCached() && !$qp->isCacheable() ) {
+ // Disabled query page, don't run the query
+ return;
+ }
+
+ $res = $qp->doQuery( $params['offset'], $params['limit'] + 1 );
+ $count = 0;
+ $titles = array();
+ foreach ( $res as $row ) {
+ if ( ++$count > $params['limit'] ) {
+ // We've had enough
+ $this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] );
+ break;
+ }
+
+ $title = Title::makeTitle( $row->namespace, $row->title );
+ if ( is_null( $resultPageSet ) ) {
+ $data = array( 'value' => $row->value );
+ if ( $qp->usesTimestamps() ) {
+ $data['timestamp'] = wfTimestamp( TS_ISO_8601, $row->value );
+ }
+ self::addTitleInfo( $data, $title );
+
+ foreach ( $row as $field => $value ) {
+ if ( !in_array( $field, array( 'namespace', 'title', 'value', 'qc_type' ) ) ) {
+ $data['databaseResult'][$field] = $value;
+ }
+ }
+
+ $fit = $result->addValue( array( 'query', $this->getModuleName(), 'results' ), null, $data );
+ if ( !$fit ) {
+ $this->setContinueEnumParameter( 'offset', $params['offset'] + $count - 1 );
+ break;
+ }
+ } else {
+ $titles[] = $title;
+ }
+ }
+ if ( is_null( $resultPageSet ) ) {
+ $result->setIndexedTagName_internal( array( 'query', $this->getModuleName(), 'results' ), 'page' );
+ } else {
+ $resultPageSet->populateFromTitles( $titles );
+ }
+ }
+
+ public function getCacheMode( $params ) {
+ $qp = new $this->qpMap[$params['page']]();
+ if ( $qp->getRestriction() != '' ) {
+ return 'private';
+ }
+ return 'public';
+ }
+
+ public function getAllowedParams() {
+ return array(
+ 'page' => array(
+ ApiBase::PARAM_TYPE => array_keys( $this->qpMap ),
+ ApiBase::PARAM_REQUIRED => true
+ ),
+ 'offset' => 0,
+ 'limit' => array(
+ ApiBase::PARAM_DFLT => 10,
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MIN => 1,
+ ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
+ ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
+ ),
+ );
+ }
+
+ public function getParamDescription() {
+ return array(
+ 'page' => 'The name of the special page. Note, this is case sensitive',
+ 'offset' => 'When more results are available, use this to continue',
+ 'limit' => 'Number of results to return',
+ );
+ }
+
+ public function getDescription() {
+ return 'Get a list provided by a QueryPage-based special page';
+ }
+
+ public function getPossibleErrors() {
+ return array_merge( parent::getPossibleErrors(), array(
+ ) );
+ }
+
+ protected function getExamples() {
+ return array(
+ 'api.php?action=query&list=querypage&qppage=Ancientpages'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryQueryPage.php 99989 2011-10-16 22:24:58Z reedy $';
+ }
+}
diff --git a/includes/api/ApiQueryRandom.php b/includes/api/ApiQueryRandom.php
index b3b840fd..dea0b0f5 100644
--- a/includes/api/ApiQueryRandom.php
+++ b/includes/api/ApiQueryRandom.php
@@ -1,7 +1,7 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Monday, January 28, 2008
*
@@ -36,7 +36,7 @@ if ( !defined( 'MEDIAWIKI' ) ) {
* @ingroup API
*/
- class ApiQueryRandom extends ApiQueryGeneratorBase {
+class ApiQueryRandom extends ApiQueryGeneratorBase {
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'rn' );
@@ -50,6 +50,14 @@ if ( !defined( 'MEDIAWIKI' ) ) {
$this->run( $resultPageSet );
}
+ /**
+ * @param $randstr
+ * @param $limit
+ * @param $namespace
+ * @param $resultPageSet ApiPageSet
+ * @param $redirect
+ * @return void
+ */
protected function prepareQuery( $randstr, $limit, $namespace, &$resultPageSet, $redirect ) {
$this->resetQueryParams();
$this->addTables( 'page' );
@@ -65,7 +73,11 @@ if ( !defined( 'MEDIAWIKI' ) ) {
}
}
- protected function runQuery( &$resultPageSet ) {
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return int
+ */
+ protected function runQuery( $resultPageSet = null ) {
$res = $this->select( __METHOD__ );
$count = 0;
foreach ( $res as $row ) {
@@ -92,6 +104,10 @@ if ( !defined( 'MEDIAWIKI' ) ) {
return $count;
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
public function run( $resultPageSet = null ) {
$params = $this->extractRequestParams();
$result = $this->getResult();
diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php
index fb0d42b8..b144a7cf 100644
--- a/includes/api/ApiQueryRecentChanges.php
+++ b/includes/api/ApiQueryRecentChanges.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 19, 2006
*
@@ -35,7 +35,7 @@ if ( !defined( 'MEDIAWIKI' ) ) {
*
* @ingroup API
*/
-class ApiQueryRecentChanges extends ApiQueryBase {
+class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'rc' );
@@ -43,7 +43,8 @@ class ApiQueryRecentChanges extends ApiQueryBase {
private $fld_comment = false, $fld_parsedcomment = false, $fld_user = false, $fld_userid = false,
$fld_flags = false, $fld_timestamp = false, $fld_title = false, $fld_ids = false,
- $fld_sizes = false, $fld_redirect = false, $fld_patrolled = false, $fld_loginfo = false, $fld_tags = false;
+ $fld_sizes = false, $fld_redirect = false, $fld_patrolled = false, $fld_loginfo = false,
+ $fld_tags = false, $token = array();
private $tokenFunctions;
@@ -71,6 +72,12 @@ class ApiQueryRecentChanges extends ApiQueryBase {
return $this->tokenFunctions;
}
+ /**
+ * @param $pageid
+ * @param $title
+ * @param $rc RecentChange
+ * @return bool|String
+ */
public static function getPatrolToken( $pageid, $title, $rc ) {
global $wgUser;
if ( !$wgUser->useRCPatrol() && ( !$wgUser->useNPPatrol() ||
@@ -84,7 +91,7 @@ class ApiQueryRecentChanges extends ApiQueryBase {
if ( is_null( $cachedPatrolToken ) ) {
$cachedPatrolToken = $wgUser->editToken( 'patrol' );
}
-
+
return $cachedPatrolToken;
}
@@ -108,10 +115,20 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$this->fld_tags = isset( $prop['tags'] );
}
+ public function execute() {
+ $this->run();
+ }
+
+ public function executeGenerator( $resultPageSet ) {
+ $this->run( $resultPageSet );
+ }
+
/**
* Generates and outputs the result of this query based upon the provided parameters.
+ *
+ * @param $resultPageSet ApiPageSet
*/
- public function execute() {
+ public function run( $resultPageSet = null ) {
global $wgUser;
/* Get the parameters of the request. */
$params = $this->extractRequestParams();
@@ -123,7 +140,7 @@ class ApiQueryRecentChanges extends ApiQueryBase {
*/
$this->addTables( 'recentchanges' );
$index = array( 'recentchanges' => 'rc_timestamp' ); // May change
- $this->addWhereRange( 'rc_timestamp', $params['dir'], $params['start'], $params['end'] );
+ $this->addTimestampWhereRange( 'rc_timestamp', $params['dir'], $params['start'], $params['end'] );
$this->addWhereFld( 'rc_namespace', $params['namespace'] );
$this->addWhereFld( 'rc_deleted', 0 );
@@ -140,9 +157,8 @@ class ApiQueryRecentChanges extends ApiQueryBase {
|| ( isset( $show['anon'] ) && isset( $show['!anon'] ) )
|| ( isset( $show['redirect'] ) && isset( $show['!redirect'] ) )
|| ( isset( $show['patrolled'] ) && isset( $show['!patrolled'] ) )
- )
- {
- $this->dieUsageMsg( array( 'show' ) );
+ ) {
+ $this->dieUsageMsg( 'show' );
}
// Check permissions
@@ -195,6 +211,7 @@ class ApiQueryRecentChanges extends ApiQueryBase {
'rc_deleted'
) );
+ $showRedirects = false;
/* Determine what properties we need to display. */
if ( !is_null( $params['prop'] ) ) {
$prop = array_flip( $params['prop'] );
@@ -207,27 +224,15 @@ class ApiQueryRecentChanges extends ApiQueryBase {
}
/* Add fields to our query if they are specified as a needed parameter. */
- $this->addFieldsIf( 'rc_id', $this->fld_ids );
- $this->addFieldsIf( 'rc_this_oldid', $this->fld_ids );
- $this->addFieldsIf( 'rc_last_oldid', $this->fld_ids );
+ $this->addFieldsIf( array( 'rc_id', 'rc_this_oldid', 'rc_last_oldid' ), $this->fld_ids );
$this->addFieldsIf( 'rc_comment', $this->fld_comment || $this->fld_parsedcomment );
$this->addFieldsIf( 'rc_user', $this->fld_user );
$this->addFieldsIf( 'rc_user_text', $this->fld_user || $this->fld_userid );
- $this->addFieldsIf( 'rc_minor', $this->fld_flags );
- $this->addFieldsIf( 'rc_bot', $this->fld_flags );
- $this->addFieldsIf( 'rc_new', $this->fld_flags );
- $this->addFieldsIf( 'rc_old_len', $this->fld_sizes );
- $this->addFieldsIf( 'rc_new_len', $this->fld_sizes );
+ $this->addFieldsIf( array( 'rc_minor', 'rc_new', 'rc_bot' ) , $this->fld_flags );
+ $this->addFieldsIf( array( 'rc_old_len', 'rc_new_len' ), $this->fld_sizes );
$this->addFieldsIf( 'rc_patrolled', $this->fld_patrolled );
- $this->addFieldsIf( 'rc_logid', $this->fld_loginfo );
- $this->addFieldsIf( 'rc_log_type', $this->fld_loginfo );
- $this->addFieldsIf( 'rc_log_action', $this->fld_loginfo );
- $this->addFieldsIf( 'rc_params', $this->fld_loginfo );
- if ( $this->fld_redirect || isset( $show['redirect'] ) || isset( $show['!redirect'] ) ) {
- $this->addTables( 'page' );
- $this->addJoinConds( array( 'page' => array( 'LEFT JOIN', array( 'rc_namespace=page_namespace', 'rc_title=page_title' ) ) ) );
- $this->addFields( 'page_is_redirect' );
- }
+ $this->addFieldsIf( array( 'rc_logid', 'rc_log_type', 'rc_log_action', 'rc_params' ), $this->fld_loginfo );
+ $showRedirects = $this->fld_redirect || isset( $show['redirect'] ) || isset( $show['!redirect'] );
}
if ( $this->fld_tags ) {
@@ -236,6 +241,16 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$this->addFields( 'ts_tags' );
}
+ if ( $params['toponly'] || $showRedirects ) {
+ $this->addTables( 'page' );
+ $this->addJoinConds( array( 'page' => array( 'LEFT JOIN', array( 'rc_namespace=page_namespace', 'rc_title=page_title' ) ) ) );
+ $this->addFields( 'page_is_redirect' );
+
+ if ( $params['toponly'] ) {
+ $this->addWhere( 'rc_this_oldid = page_latest' );
+ }
+ }
+
if ( !is_null( $params['tag'] ) ) {
$this->addTables( 'change_tag' );
$this->addJoinConds( array( 'change_tag' => array( 'INNER JOIN', array( 'rc_id=ct_rc_id' ) ) ) );
@@ -252,6 +267,10 @@ class ApiQueryRecentChanges extends ApiQueryBase {
/* Perform the actual query. */
$res = $this->select( __METHOD__ );
+ $titles = array();
+
+ $result = $this->getResult();
+
/* Iterate through the rows, adding data extracted from them to our query result. */
foreach ( $res as $row ) {
if ( ++ $count > $params['limit'] ) {
@@ -260,22 +279,30 @@ class ApiQueryRecentChanges extends ApiQueryBase {
break;
}
- /* Extract the data from a single row. */
- $vals = $this->extractRowInfo( $row );
+ if ( is_null( $resultPageSet ) ) {
+ /* Extract the data from a single row. */
+ $vals = $this->extractRowInfo( $row );
- /* Add that row's data to our final output. */
- if ( !$vals ) {
- continue;
- }
- $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ), null, $vals );
- if ( !$fit ) {
- $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->rc_timestamp ) );
- break;
+ /* Add that row's data to our final output. */
+ if ( !$vals ) {
+ continue;
+ }
+ $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $vals );
+ if ( !$fit ) {
+ $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->rc_timestamp ) );
+ break;
+ }
+ } else {
+ $titles[] = Title::makeTitle( $row->rc_namespace, $row->rc_title );
}
}
- /* Format the result */
- $this->getResult()->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'rc' );
+ if ( is_null( $resultPageSet ) ) {
+ /* Format the result */
+ $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'rc' );
+ } else {
+ $resultPageSet->populateFromTitles( $titles );
+ }
}
/**
@@ -288,8 +315,7 @@ class ApiQueryRecentChanges extends ApiQueryBase {
public function extractRowInfo( $row ) {
/* If page was moved somewhere, get the title of the move target. */
$movedToTitle = false;
- if ( isset( $row->rc_moved_to_title ) && $row->rc_moved_to_title !== '' )
- {
+ if ( isset( $row->rc_moved_to_title ) && $row->rc_moved_to_title !== '' ) {
$movedToTitle = Title::makeTitle( $row->rc_moved_to_ns, $row->rc_moved_to_title );
}
@@ -405,8 +431,11 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$vals['logaction'] = $row->rc_log_action;
ApiQueryLogEvents::addLogParams(
$this->getResult(),
- $vals, $row->rc_params,
- $row->rc_log_type, $row->rc_timestamp
+ $vals,
+ $row->rc_params,
+ $row->rc_log_action,
+ $row->rc_log_type,
+ $row->rc_timestamp
);
}
@@ -550,15 +579,17 @@ class ApiQueryRecentChanges extends ApiQueryBase {
'new',
'log'
)
- )
+ ),
+ 'toponly' => false,
);
}
public function getParamDescription() {
+ $p = $this->getModulePrefix();
return array(
'start' => 'The timestamp to start enumerating from',
'end' => 'The timestamp to end enumerating',
- 'dir' => 'In which direction to enumerate',
+ 'dir' => $this->getDirectionDescription( $p ),
'namespace' => 'Filter log entries to only this namespace(s)',
'user' => 'Only list changes by this user',
'excludeuser' => 'Don\'t list changes by this user',
@@ -571,21 +602,22 @@ class ApiQueryRecentChanges extends ApiQueryBase {
' flags - Adds flags for the edit',
' timestamp - Adds timestamp of the edit',
' title - Adds the page title of the edit',
- ' ids - Adds the page id, recent changes id and the new and old revision id',
+ ' ids - Adds the page ID, recent changes ID and the new and old revision ID',
' sizes - Adds the new and old page length in bytes',
' redirect - Tags edit if page is a redirect',
- ' patrolled - Tags edits have have been patrolled',
+ ' patrolled - Tags edits that have been patrolled',
' loginfo - Adds log information (logid, logtype, etc) to log entries',
' tags - Lists tags for the entry',
),
'token' => 'Which tokens to obtain for each change',
'show' => array(
'Show only items that meet this criteria.',
- "For example, to see only minor edits done by logged-in users, set {$this->getModulePrefix()}show=minor|!anon"
+ "For example, to see only minor edits done by logged-in users, set {$p}show=minor|!anon"
),
'type' => 'Which types of changes to show',
'limit' => 'How many total changes to return',
'tag' => 'Only list changes tagged with this tag',
+ 'toponly' => 'Only list changes which are the latest revision',
);
}
@@ -607,7 +639,11 @@ class ApiQueryRecentChanges extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Recentchanges';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryRecentChanges.php 78437 2010-12-15 14:14:16Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryRecentChanges.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php
index 64a0a4ea..e6b21a92 100644
--- a/includes/api/ApiQueryRevisions.php
+++ b/includes/api/ApiQueryRevisions.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 7, 2006
*
@@ -39,7 +39,7 @@ if ( !defined( 'MEDIAWIKI' ) ) {
class ApiQueryRevisions extends ApiQueryBase {
private $diffto, $difftotext, $expandTemplates, $generateXML, $section,
- $token;
+ $token, $parseContent;
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'rv' );
@@ -73,6 +73,12 @@ class ApiQueryRevisions extends ApiQueryBase {
return $this->tokenFunctions;
}
+ /**
+ * @param $pageid
+ * @param $title Title
+ * @param $rev Revision
+ * @return bool|String
+ */
public static function getRollbackToken( $pageid, $title, $rev ) {
global $wgUser;
if ( !$wgUser->isAllowed( 'rollback' ) ) {
@@ -119,8 +125,7 @@ class ApiQueryRevisions extends ApiQueryBase {
$params['diffto'] = 0;
}
if ( ( !ctype_digit( $params['diffto'] ) || $params['diffto'] < 0 )
- && $params['diffto'] != 'prev' && $params['diffto'] != 'next' )
- {
+ && $params['diffto'] != 'prev' && $params['diffto'] != 'next' ) {
$this->dieUsage( 'rvdiffto must be set to a non-negative number, "prev", "next" or "cur"', 'diffto' );
}
// Check whether the revision exists and is readable,
@@ -169,7 +174,6 @@ class ApiQueryRevisions extends ApiQueryBase {
$this->getResult()->setParsedLimit( $this->getModuleName(), $limit );
}
-
if ( !is_null( $this->token ) || $pageCount > 0 ) {
$this->addFields( Revision::selectPageFields() );
}
@@ -224,10 +228,9 @@ class ApiQueryRevisions extends ApiQueryBase {
}
}
- //Bug 24166 - API error when using rvprop=tags
+ // Bug 24166 - API error when using rvprop=tags
$this->addTables( 'revision' );
-
if ( $enumRevMode ) {
// This is mostly to prevent parameter errors (and optimize SQL?)
if ( !is_null( $params['startid'] ) && !is_null( $params['start'] ) ) {
@@ -249,14 +252,14 @@ class ApiQueryRevisions extends ApiQueryBase {
// one row with the same timestamp for the same page.
// The order needs to be the same as start parameter to avoid SQL filesort.
if ( is_null( $params['startid'] ) && is_null( $params['endid'] ) ) {
- $this->addWhereRange( 'rev_timestamp', $params['dir'],
+ $this->addTimestampWhereRange( 'rev_timestamp', $params['dir'],
$params['start'], $params['end'] );
} else {
$this->addWhereRange( 'rev_id', $params['dir'],
$params['startid'], $params['endid'] );
// One of start and end can be set
// If neither is set, this does nothing
- $this->addWhereRange( 'rev_timestamp', $params['dir'],
+ $this->addTimestampWhereRange( 'rev_timestamp', $params['dir'],
$params['start'], $params['end'], false );
}
@@ -479,27 +482,7 @@ class ApiQueryRevisions extends ApiQueryBase {
$text = $wgParser->preprocess( $text, $title, new ParserOptions() );
}
if ( $this->parseContent ) {
- global $wgEnableParserCache;
-
- $popts = new ParserOptions();
- $popts->setTidy( true );
-
- $articleObj = new Article( $title );
-
- $p_result = false;
- $pcache = ParserCache::singleton();
- if ( $wgEnableParserCache ) {
- $p_result = $pcache->get( $articleObj, $popts );
- }
- if ( !$p_result ) {
- $p_result = $wgParser->parse( $text, $title, $popts );
-
- if ( $wgEnableParserCache ) {
- $pcache->save( $p_result, $articleObj, $popts );
- }
- }
-
- $text = $p_result->getText();
+ $text = $wgParser->parse( $text, $title, new ParserOptions() )->getText();
}
ApiResult::setContent( $vals, $text );
} elseif ( $this->fld_content ) {
@@ -627,9 +610,9 @@ class ApiQueryRevisions extends ApiQueryBase {
'endid' => 'Stop revision enumeration on this revid (enum)',
'start' => 'From which revision timestamp to start enumeration (enum)',
'end' => 'Enumerate up to this timestamp (enum)',
- 'dir' => 'Direction of enumeration - towards "newer" or "older" revisions (enum)',
- 'user' => 'Only include revisions made by user',
- 'excludeuser' => 'Exclude revisions made by user',
+ 'dir' => $this->getDirectionDescription( $p, ' (enum)' ),
+ 'user' => 'Only include revisions made by user (enum)',
+ 'excludeuser' => 'Exclude revisions made by user (enum)',
'expandtemplates' => 'Expand templates in revision content',
'generatexml' => 'Generate XML parse tree for revision content',
'parse' => 'Parse revision content. For performance reasons if this option is used, rvlimit is enforced to 1.',
@@ -647,7 +630,7 @@ class ApiQueryRevisions extends ApiQueryBase {
public function getDescription() {
return array(
'Get revision information',
- 'This module may be used in several ways:',
+ 'May be used in several ways:',
' 1) Get data about a set of pages (last revision), by setting titles or pageids parameter',
' 2) Get revisions for one given page, by using titles/pageids with start/end/limit params',
' 3) Get data about a set of revisions by setting their IDs with revids parameter',
@@ -685,7 +668,11 @@ class ApiQueryRevisions extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Properties#revisions_.2F_rv';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryRevisions.php 75521 2010-10-27 11:50:20Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryRevisions.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQuerySearch.php b/includes/api/ApiQuerySearch.php
index 3cf693af..42bed93a 100644
--- a/includes/api/ApiQuerySearch.php
+++ b/includes/api/ApiQuerySearch.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on July 30, 2007
*
@@ -48,6 +48,10 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
global $wgContLang;
$params = $this->extractRequestParams();
@@ -93,16 +97,17 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
$this->dieUsage( "{$what} search is disabled", "search-{$what}-disabled" );
}
+ $apiResult = $this->getResult();
// Add search meta data to result
if ( isset( $searchInfo['totalhits'] ) ) {
$totalhits = $matches->getTotalHits();
if ( $totalhits !== null ) {
- $this->getResult()->addValue( array( 'query', 'searchinfo' ),
+ $apiResult->addValue( array( 'query', 'searchinfo' ),
'totalhits', $totalhits );
}
}
if ( isset( $searchInfo['suggestion'] ) && $matches->hasSuggestion() ) {
- $this->getResult()->addValue( array( 'query', 'searchinfo' ),
+ $apiResult->addValue( array( 'query', 'searchinfo' ),
'suggestion', $matches->getSuggestionQuery() );
}
@@ -110,7 +115,9 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
$terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
$titles = array();
$count = 0;
- while ( $result = $matches->next() ) {
+ $result = $matches->next();
+
+ while ( $result ) {
if ( ++ $count > $limit ) {
// We've reached the one extra which shows that there are additional items to be had. Stop here...
$this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] );
@@ -119,6 +126,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
// Silently skip broken and missing titles
if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
+ $result = $matches->next();
continue;
}
@@ -155,7 +163,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
}
if ( !is_null( $result->getSectionTitle() ) ) {
if ( isset( $prop['sectiontitle'] ) ) {
- $vals['sectiontitle'] = $result->getSectionTitle();
+ $vals['sectiontitle'] = $result->getSectionTitle()->getFragment();
}
if ( isset( $prop['sectionsnippet'] ) ) {
$vals['sectionsnippet'] = $result->getSectionSnippet();
@@ -166,7 +174,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
}
// Add item to results and see whether it fits
- $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ),
+ $fit = $apiResult->addValue( array( 'query', $this->getModuleName() ),
null, $vals );
if ( !$fit ) {
$this->setContinueEnumParameter( 'offset', $params['offset'] + $count - 1 );
@@ -175,10 +183,12 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
} else {
$titles[] = $title;
}
+
+ $result = $matches->next();
}
if ( is_null( $resultPageSet ) ) {
- $this->getResult()->setIndexedTagName_internal( array(
+ $apiResult->setIndexedTagName_internal( array(
'query', $this->getModuleName()
), 'p' );
} else {
@@ -260,10 +270,10 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
' score - Adds the score (if any) from the search engine',
' snippet - Adds a parsed snippet of the page',
' titlesnippet - Adds a parsed snippet of the page title',
- ' redirectsnippet - Adds a parsed snippet of the redirect',
- ' redirecttitle - Adds a parsed snippet of the redirect title',
- ' sectionsnippet - Adds a parsed snippet of the matching section',
- ' sectiontitle - Adds a parsed snippet of the matching section title',
+ ' redirectsnippet - Adds a parsed snippet of the redirect title',
+ ' redirecttitle - Adds the title of the matching redirect',
+ ' sectionsnippet - Adds a parsed snippet of the matching section title',
+ ' sectiontitle - Adds the title of the matching section',
' hasrelated - Indicates whether a related search is available',
),
'redirects' => 'Include redirect pages in the search',
@@ -291,7 +301,11 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Search';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQuerySearch.php 76300 2010-11-08 12:23:24Z reedy $';
+ return __CLASS__ . ': $Id: ApiQuerySearch.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php
index 379a4228..b6cedc6c 100644
--- a/includes/api/ApiQuerySiteinfo.php
+++ b/includes/api/ApiQuerySiteinfo.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 25, 2006
*
@@ -85,6 +85,18 @@ class ApiQuerySiteinfo extends ApiQueryBase {
case 'languages':
$fit = $this->appendLanguages( $p );
break;
+ case 'skins':
+ $fit = $this->appendSkins( $p );
+ break;
+ case 'extensiontags':
+ $fit = $this->appendExtensionTags( $p );
+ break;
+ case 'functionhooks':
+ $fit = $this->appendFunctionHooks( $p );
+ break;
+ case 'showhooks':
+ $fit = $this->appendSubscribedHooks( $p );
+ break;
default:
ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
}
@@ -105,7 +117,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$data = array();
$mainPage = Title::newMainPage();
$data['mainpage'] = $mainPage->getPrefixedText();
- $data['base'] = $mainPage->getFullUrl();
+ $data['base'] = wfExpandUrl( $mainPage->getFullUrl(), PROTO_CURRENT );
$data['sitename'] = $GLOBALS['wgSitename'];
$data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}";
$data['phpversion'] = phpversion();
@@ -157,6 +169,12 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$data['wikiid'] = wfWikiID();
$data['time'] = wfTimestamp( TS_ISO_8601, time() );
+ if ( $GLOBALS['wgMiserMode'] ) {
+ $data['misermode'] = '';
+ }
+
+ wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
+
return $this->getResult()->addValue( 'query', $property, $data );
}
@@ -212,8 +230,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
protected function appendSpecialPageAliases( $property ) {
global $wgContLang;
$data = array();
- foreach ( $wgContLang->getSpecialPageAliases() as $specialpage => $aliases )
- {
+ foreach ( $wgContLang->getSpecialPageAliases() as $specialpage => $aliases ) {
$arr = array( 'realname' => $specialpage, 'aliases' => $aliases );
$this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
$data[] = $arr;
@@ -241,7 +258,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
protected function appendInterwikiMap( $property, $filter ) {
$this->resetQueryParams();
$this->addTables( 'interwiki' );
- $this->addFields( array( 'iw_prefix', 'iw_local', 'iw_url' ) );
+ $this->addFields( array( 'iw_prefix', 'iw_local', 'iw_url', 'iw_wikiid', 'iw_api' ) );
if ( $filter === 'local' ) {
$this->addWhere( 'iw_local = 1' );
@@ -267,7 +284,13 @@ class ApiQuerySiteinfo extends ApiQueryBase {
if ( isset( $langNames[$row->iw_prefix] ) ) {
$val['language'] = $langNames[$row->iw_prefix];
}
- $val['url'] = $row->iw_url;
+ $val['url'] = wfExpandUrl( $row->iw_url, PROTO_CURRENT );
+ if( isset( $row->iw_wikiid ) ) {
+ $val['wikiid'] = $row->iw_wikiid;
+ }
+ if( isset( $row->iw_api ) ) {
+ $val['api'] = $row->iw_api;
+ }
$data[] = $val;
}
@@ -279,12 +302,12 @@ class ApiQuerySiteinfo extends ApiQueryBase {
protected function appendDbReplLagInfo( $property, $includeAll ) {
global $wgShowHostnames;
$data = array();
+ $lb = wfGetLB();
if ( $includeAll ) {
if ( !$wgShowHostnames ) {
$this->dieUsage( 'Cannot view all servers info unless $wgShowHostnames is true', 'includeAllDenied' );
}
- $lb = wfGetLB();
$lags = $lb->getLagTimes();
foreach ( $lags as $i => $lag ) {
$data[] = array(
@@ -293,9 +316,11 @@ class ApiQuerySiteinfo extends ApiQueryBase {
);
}
} else {
- list( $host, $lag ) = wfGetLB()->getMaxLag();
+ list( $host, $lag, $index ) = $lb->getMaxLag();
$data[] = array(
- 'host' => $wgShowHostnames ? $host : '',
+ 'host' => $wgShowHostnames
+ ? $lb->getServerName( $index )
+ : '',
'lag' => intval( $lag )
);
}
@@ -324,46 +349,47 @@ class ApiQuerySiteinfo extends ApiQueryBase {
protected function appendUserGroups( $property, $numberInGroup ) {
global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
-
+
$data = array();
+ $result = $this->getResult();
foreach ( $wgGroupPermissions as $group => $permissions ) {
$arr = array(
'name' => $group,
'rights' => array_keys( $permissions, true ),
);
-
+
if ( $numberInGroup ) {
global $wgAutopromote;
-
+
if ( $group == 'user' ) {
$arr['number'] = SiteStats::users();
-
+
// '*' and autopromote groups have no size
} elseif ( $group !== '*' && !isset( $wgAutopromote[$group] ) ) {
$arr['number'] = SiteStats::numberInGroup( $group );
}
}
-
+
$groupArr = array(
'add' => $wgAddGroups,
'remove' => $wgRemoveGroups,
'add-self' => $wgGroupsAddToSelf,
'remove-self' => $wgGroupsRemoveFromSelf
);
-
- foreach( $groupArr as $type => $rights ) {
- if( isset( $rights[$group] ) ) {
+
+ foreach ( $groupArr as $type => $rights ) {
+ if ( isset( $rights[$group] ) ) {
$arr[$type] = $rights[$group];
- $this->getResult()->setIndexedTagName( $arr[$type], 'group' );
+ $result->setIndexedTagName( $arr[$type], 'group' );
}
}
-
- $this->getResult()->setIndexedTagName( $arr['rights'], 'permission' );
+
+ $result->setIndexedTagName( $arr['rights'], 'permission' );
$data[] = $arr;
}
-
- $this->getResult()->setIndexedTagName( $data, 'group' );
- return $this->getResult()->addValue( 'query', $property, $data );
+
+ $result->setIndexedTagName( $data, 'group' );
+ return $result->addValue( 'query', $property, $data );
}
protected function appendFileExtensions( $property ) {
@@ -423,11 +449,10 @@ class ApiQuerySiteinfo extends ApiQueryBase {
return $this->getResult()->addValue( 'query', $property, $data );
}
-
protected function appendRightsInfo( $property ) {
global $wgRightsPage, $wgRightsUrl, $wgRightsText;
$title = Title::newFromText( $wgRightsPage );
- $url = $title ? $title->getFullURL() : $wgRightsUrl;
+ $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $wgRightsUrl;
$text = $wgRightsText;
if ( !$text && $title ) {
$text = $title->getPrefixedText();
@@ -452,6 +477,57 @@ class ApiQuerySiteinfo extends ApiQueryBase {
return $this->getResult()->addValue( 'query', $property, $data );
}
+ public function appendSkins( $property ) {
+ $data = array();
+ foreach ( Skin::getSkinNames() as $name => $displayName ) {
+ $skin = array( 'code' => $name );
+ ApiResult::setContent( $skin, $displayName );
+ $data[] = $skin;
+ }
+ $this->getResult()->setIndexedTagName( $data, 'skin' );
+ return $this->getResult()->addValue( 'query', $property, $data );
+ }
+
+ public function appendExtensionTags( $property ) {
+ global $wgParser;
+ $wgParser->firstCallInit();
+ $tags = array_map( array( $this, 'formatParserTags'), $wgParser->getTags() );
+ $this->getResult()->setIndexedTagName( $tags, 't' );
+ return $this->getResult()->addValue( 'query', $property, $tags );
+ }
+
+ public function appendFunctionHooks( $property ) {
+ global $wgParser;
+ $wgParser->firstCallInit();
+ $hooks = $wgParser->getFunctionHooks();
+ $this->getResult()->setIndexedTagName( $hooks, 'h' );
+ return $this->getResult()->addValue( 'query', $property, $hooks );
+ }
+
+ private function formatParserTags( $item ) {
+ return "<{$item}>";
+ }
+
+ public function appendSubscribedHooks( $property ) {
+ global $wgHooks;
+ $myWgHooks = $wgHooks;
+ ksort( $myWgHooks );
+
+ $data = array();
+ foreach ( $myWgHooks as $hook => $hooks ) {
+ $arr = array(
+ 'name' => $hook,
+ 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $hooks ),
+ );
+
+ $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
+ $data[] = $arr;
+ }
+
+ $this->getResult()->setIndexedTagName( $data, 'hook' );
+ return $this->getResult()->addValue( 'query', $property, $data );
+ }
+
public function getCacheMode( $params ) {
return 'public';
}
@@ -475,6 +551,10 @@ class ApiQuerySiteinfo extends ApiQueryBase {
'fileextensions',
'rightsinfo',
'languages',
+ 'skins',
+ 'extensiontags',
+ 'functionhooks',
+ 'showhooks',
)
),
'filteriw' => array(
@@ -505,6 +585,10 @@ class ApiQuerySiteinfo extends ApiQueryBase {
' fileextensions - Returns list of file extensions allowed to be uploaded',
' rightsinfo - Returns wiki rights (license) information if available',
' languages - Returns a list of languages MediaWiki supports',
+ ' skins - Returns a list of all enabled skins',
+ ' extensiontags - Returns a list of parser extension tags',
+ ' functionhooks - Returns a list of parser function hooks',
+ ' showhooks - Returns a list of all subscribed hooks (contents of $wgHooks)'
),
'filteriw' => 'Return only local or only nonlocal entries of the interwiki map',
'showalldb' => 'List all database servers, not just the one lagging the most',
@@ -530,7 +614,11 @@ class ApiQuerySiteinfo extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQuerySiteinfo.php 77192 2010-11-23 22:05:27Z btongminh $';
+ return __CLASS__ . ': $Id: ApiQuerySiteinfo.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryStashImageInfo.php b/includes/api/ApiQueryStashImageInfo.php
index 769b3e9d..9a6e8530 100644
--- a/includes/api/ApiQueryStashImageInfo.php
+++ b/includes/api/ApiQueryStashImageInfo.php
@@ -38,58 +38,53 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
$prop = array_flip( $params['prop'] );
$scale = $this->getScale( $params );
-
+
$result = $this->getResult();
-
+
+ if ( !$params['filekey'] && !$params['sessionkey'] ) {
+ $this->dieUsage( "One of filekey or sessionkey must be supplied", 'nofilekey');
+ }
+
try {
$stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash();
-
- foreach ( $params['sessionkey'] as $sessionkey ) {
- $file = $stash->getFile( $sessionkey );
- $imageInfo = self::getInfo( $file, $prop, $result, $scale );
+
+ foreach ( $params['filekey'] as $filekey ) {
+ $file = $stash->getFile( $filekey );
+ $finalThumbParam = $this->mergeThumbParams( $file, $scale, $params['urlparam'] );
+ $imageInfo = ApiQueryImageInfo::getInfo( $file, $prop, $result, $finalThumbParam );
$result->addValue( array( 'query', $this->getModuleName() ), null, $imageInfo );
$result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), $modulePrefix );
}
-
+ //TODO: update exception handling here to understand current getFile exceptions
} catch ( UploadStashNotAvailableException $e ) {
$this->dieUsage( "Session not available: " . $e->getMessage(), "nosession" );
} catch ( UploadStashFileNotFoundException $e ) {
$this->dieUsage( "File not found: " . $e->getMessage(), "invalidsessiondata" );
} catch ( UploadStashBadPathException $e ) {
$this->dieUsage( "Bad path: " . $e->getMessage(), "invalidsessiondata" );
- }
-
- }
-
- /**
- * Returns all valid parameters to siiprop
- */
- public static function getPropertyNames() {
- return array(
- 'timestamp',
- 'url',
- 'size',
- 'dimensions', // For backwards compatibility with Allimages
- 'sha1',
- 'mime',
- 'thumbmime',
- 'metadata',
- 'bitdepth',
- );
+ }
}
+ private $propertyFilter = array(
+ 'user', 'userid', 'comment', 'parsedcomment',
+ 'mediatype', 'archivename',
+ );
public function getAllowedParams() {
return array(
- 'sessionkey' => array(
+ 'filekey' => array(
ApiBase::PARAM_ISMULTI => true,
- ApiBase::PARAM_REQUIRED => true,
+ ApiBase::PARAM_DFLT => null
+ ),
+ 'sessionkey' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_DEPRECATED => true,
ApiBase::PARAM_DFLT => null
),
'prop' => array(
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_DFLT => 'timestamp|url',
- ApiBase::PARAM_TYPE => self::getPropertyNames()
+ ApiBase::PARAM_TYPE => self::getPropertyNames( $this->propertyFilter )
),
'urlwidth' => array(
ApiBase::PARAM_TYPE => 'integer',
@@ -98,32 +93,28 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
'urlheight' => array(
ApiBase::PARAM_TYPE => 'integer',
ApiBase::PARAM_DFLT => -1
- )
+ ),
+ 'urlparam' => array(
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_DFLT => '',
+ ),
);
}
/**
* Return the API documentation for the parameters.
- * @return {Array} parameter documentation.
+ * @return Array parameter documentation.
*/
public function getParamDescription() {
$p = $this->getModulePrefix();
return array(
- 'prop' => array(
- 'What image information to get:',
- ' timestamp - Adds timestamp for the uploaded version',
- ' url - Gives URL to the image and the description page',
- ' size - Adds the size of the image in bytes and the height and width',
- ' dimensions - Alias for size',
- ' sha1 - Adds sha1 hash for the image',
- ' mime - Adds MIME of the image',
- ' thumbmime - Adss MIME of the image thumbnail (requires url)',
- ' metadata - Lists EXIF metadata for the version of the image',
- ' bitdepth - Adds the bit depth of the version',
- ),
- 'sessionkey' => 'Session key that identifies a previous upload that was stashed temporarily.',
+ 'prop' => self::getPropertyDescriptions( $this->propertyFilter ),
+ 'filekey' => 'Key that identifies a previous upload that was stashed temporarily.',
+ 'sessionkey' => 'Alias for filekey, for backward compatibility.',
'urlwidth' => "If {$p}prop=url is set, a URL to an image scaled to this width will be returned.",
- 'urlheight' => "Similar to {$p}urlwidth. Cannot be used without {$p}urlwidth"
+ 'urlheight' => "Similar to {$p}urlwidth. Cannot be used without {$p}urlwidth",
+ 'urlparam' => array( "A handler specific parameter string. For example, pdf's ",
+ "might use 'page15-100px'. {$p}urlwidth must be used and be consistent with {$p}urlparam" ),
);
}
@@ -131,21 +122,15 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
return 'Returns image information for stashed images';
}
- public function getPossibleErrors() {
- return array_merge( parent::getPossibleErrors(), array(
- array( 'code' => 'siiurlwidth', 'info' => 'siiurlheight cannot be used without iiurlwidth' ),
- ) );
- }
-
protected function getExamples() {
return array(
- 'api.php?action=query&prop=stashimageinfo&siisessionkey=124sd34rsdf567',
- 'api.php?action=query&prop=stashimageinfo&siisessionkey=b34edoe3|bceffd4&siiurlwidth=120&siiprop=url',
+ 'api.php?action=query&prop=stashimageinfo&siifilekey=124sd34rsdf567',
+ 'api.php?action=query&prop=stashimageinfo&siifilekey=b34edoe3|bceffd4&siiurlwidth=120&siiprop=url',
);
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryStashImageInfo.php 81000 2011-01-25 22:49:34Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryStashImageInfo.php 92459 2011-07-18 19:31:38Z raindrift $';
}
}
diff --git a/includes/api/ApiQueryTags.php b/includes/api/ApiQueryTags.php
index e88ec9b5..14ca14b7 100644
--- a/includes/api/ApiQueryTags.php
+++ b/includes/api/ApiQueryTags.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Jul 9, 2009
*
@@ -36,7 +36,12 @@ if ( !defined( 'MEDIAWIKI' ) ) {
*/
class ApiQueryTags extends ApiQueryBase {
- private $limit, $result;
+ /**
+ * @var ApiResult
+ */
+ private $result;
+
+ private $limit;
private $fld_displayname = false, $fld_description = false,
$fld_hitcount = false;
@@ -59,9 +64,7 @@ class ApiQueryTags extends ApiQueryBase {
$this->addTables( 'change_tag' );
$this->addFields( 'ct_tag' );
- if ( $this->fld_hitcount ) {
- $this->addFields( 'count(*) AS hitcount' );
- }
+ $this->addFieldsIf( 'count(*) AS hitcount', $this->fld_hitcount );
$this->addOption( 'LIMIT', $this->limit + 1 );
$this->addOption( 'GROUP BY', 'ct_tag' );
@@ -110,9 +113,8 @@ class ApiQueryTags extends ApiQueryBase {
}
if ( $this->fld_description ) {
- $msg = wfMsg( "tag-$tagName-description" );
- $msg = wfEmptyMsg( "tag-$tagName-description", $msg ) ? '' : $msg;
- $tag['description'] = $msg;
+ $msg = wfMessage( "tag-$tagName-description" );
+ $tag['description'] = $msg->exists() ? $msg->text() : '';
}
if ( $this->fld_hitcount ) {
@@ -183,6 +185,6 @@ class ApiQueryTags extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryTags.php 73858 2010-09-28 01:21:15Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryTags.php 90542 2011-06-21 20:05:00Z ialex $';
}
}
diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php
index 5d63fa60..e958c729 100644
--- a/includes/api/ApiQueryUserContributions.php
+++ b/includes/api/ApiQueryUserContributions.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 16, 2006
*
@@ -81,6 +81,7 @@ class ApiQueryContributions extends ApiQueryBase {
$this->prefixMode = false;
$this->multiUserMode = ( count( $this->params['user'] ) > 1 );
}
+
$this->prepareQuery();
// Do the actual query.
@@ -120,6 +121,8 @@ class ApiQueryContributions extends ApiQueryBase {
/**
* Validate the 'user' parameter and set the value to compare
* against `revision`.`rev_user_text`
+ *
+ * @param $user string
*/
private function prepareUsername( $user ) {
if ( !is_null( $user ) && $user !== '' ) {
@@ -179,7 +182,7 @@ class ApiQueryContributions extends ApiQueryBase {
if ( $this->multiUserMode ) {
$this->addWhereRange( 'rev_user_text', $this->params['dir'], null, null );
}
- $this->addWhereRange( 'rev_timestamp',
+ $this->addTimestampWhereRange( 'rev_timestamp',
$this->params['dir'], $this->params['start'], $this->params['end'] );
$this->addWhereFld( 'page_namespace', $this->params['namespace'] );
@@ -188,7 +191,7 @@ class ApiQueryContributions extends ApiQueryBase {
$show = array_flip( $show );
if ( ( isset( $show['minor'] ) && isset( $show['!minor'] ) )
|| ( isset( $show['patrolled'] ) && isset( $show['!patrolled'] ) ) ) {
- $this->dieUsageMsg( array( 'show' ) );
+ $this->dieUsageMsg( 'show' );
}
$this->addWhereIf( 'rev_minor_edit = 0', isset( $show['!minor'] ) );
@@ -246,8 +249,7 @@ class ApiQueryContributions extends ApiQueryBase {
// $this->addFieldsIf( 'rev_text_id', $this->fld_ids ); // Should this field be exposed?
$this->addFieldsIf( 'rev_comment', $this->fld_comment || $this->fld_parsedcomment );
$this->addFieldsIf( 'rev_len', $this->fld_size );
- $this->addFieldsIf( 'rev_minor_edit', $this->fld_flags );
- $this->addFieldsIf( 'rev_parent_id', $this->fld_flags );
+ $this->addFieldsIf( array( 'rev_minor_edit', 'rev_parent_id' ), $this->fld_flags );
$this->addFieldsIf( 'rc_patrolled', $this->fld_patrolled );
if ( $this->fld_tags ) {
@@ -264,6 +266,10 @@ class ApiQueryContributions extends ApiQueryBase {
$index['change_tag'] = $wgOldChangeTagsIndex ? 'ct_tag' : 'change_tag_tag_id';
}
+ if ( $this->params['toponly'] ) {
+ $this->addWhere( 'rev_id = page_latest' );
+ }
+
$this->addOption( 'USE INDEX', $index );
}
@@ -409,6 +415,7 @@ class ApiQueryContributions extends ApiQueryBase {
)
),
'tag' => null,
+ 'toponly' => false,
);
}
@@ -422,12 +429,12 @@ class ApiQueryContributions extends ApiQueryBase {
'continue' => 'When more results are available, use this to continue',
'user' => 'The users to retrieve contributions for',
'userprefix' => "Retrieve contibutions for all users whose names begin with this value. Overrides {$p}user",
- 'dir' => 'The direction to search (older or newer)',
+ 'dir' => $this->getDirectionDescription( $p ),
'namespace' => 'Only list contributions in these namespaces',
'prop' => array(
'Include additional pieces of information',
- ' ids - Adds the page id and revision id',
- ' title - Adds the title and namespace id of the page',
+ ' ids - Adds the page ID and revision ID',
+ ' title - Adds the title and namespace ID of the page',
' timestamp - Adds the timestamp of the edit',
' comment - Adds the comment of the edit',
' parsedcomment - Adds the parsed comment of the edit',
@@ -439,6 +446,7 @@ class ApiQueryContributions extends ApiQueryBase {
'show' => array( "Show only items that meet this criteria, e.g. non minor edits only: {$p}show=!minor",
"NOTE: if {$p}show=patrolled or {$p}show=!patrolled is set, revisions older than $wgRCMaxAge won\'t be shown", ),
'tag' => 'Only list revisions tagged with this tag',
+ 'toponly' => 'Only list changes which are the latest revision',
);
}
@@ -462,7 +470,11 @@ class ApiQueryContributions extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Usercontribs';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryUserContributions.php 75096 2010-10-20 18:50:33Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryUserContributions.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php
index ec7b74b3..8a8ce118 100644
--- a/includes/api/ApiQueryUserInfo.php
+++ b/includes/api/ApiQueryUserInfo.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on July 30, 2007
*
@@ -55,7 +55,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
}
protected function getCurrentUserInfo() {
- global $wgUser, $wgRequest;
+ global $wgUser, $wgRequest, $wgHiddenPrefs;
$result = $this->getResult();
$vals = array();
$vals['id'] = intval( $wgUser->getId() );
@@ -83,6 +83,11 @@ class ApiQueryUserInfo extends ApiQueryBase {
$result->setIndexedTagName( $vals['groups'], 'g' ); // even if empty
}
+ if ( isset( $this->prop['implicitgroups'] ) ) {
+ $vals['implicitgroups'] = ApiQueryUsers::getAutoGroups( $wgUser );
+ $result->setIndexedTagName( $vals['implicitgroups'], 'g' ); // even if empty
+ }
+
if ( isset( $this->prop['rights'] ) ) {
// User::getRights() may return duplicate values, strip them
$vals['rights'] = array_values( array_unique( $wgUser->getRights() ) );
@@ -101,12 +106,10 @@ class ApiQueryUserInfo extends ApiQueryBase {
$vals['options'] = $wgUser->getOptions();
}
- if (
- isset( $this->prop['preferencestoken'] ) &&
+ if ( isset( $this->prop['preferencestoken'] ) &&
is_null( $this->getMain()->getRequest()->getVal( 'callback' ) )
- )
- {
- $vals['preferencestoken'] = $wgUser->editToken();
+ ) {
+ $vals['preferencestoken'] = $wgUser->editToken( '', $this->getMain()->getRequest() );
}
if ( isset( $this->prop['editcount'] ) ) {
@@ -117,6 +120,10 @@ class ApiQueryUserInfo extends ApiQueryBase {
$vals['ratelimits'] = $this->getRateLimits();
}
+ if ( isset( $this->prop['realname'] ) && !in_array( 'realname', $wgHiddenPrefs ) ) {
+ $vals['realname'] = $wgUser->getRealName();
+ }
+
if ( isset( $this->prop['email'] ) ) {
$vals['email'] = $wgUser->getEmail();
$auth = $wgUser->getEmailAuthenticationTimestamp();
@@ -125,6 +132,13 @@ class ApiQueryUserInfo extends ApiQueryBase {
}
}
+ if ( isset( $this->prop['registrationdate'] ) ) {
+ $regDate = $wgUser->getRegistration();
+ if ( $regDate !== false ) {
+ $vals['registrationdate'] = wfTimestamp( TS_ISO_8601, $regDate );
+ }
+ }
+
if ( isset( $this->prop['acceptlang'] ) ) {
$langs = $wgRequest->getAcceptLang();
$acceptLang = array();
@@ -182,6 +196,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
'blockinfo',
'hasmsg',
'groups',
+ 'implicitgroups',
'rights',
'changeablegroups',
'options',
@@ -189,7 +204,9 @@ class ApiQueryUserInfo extends ApiQueryBase {
'editcount',
'ratelimits',
'email',
+ 'realname',
'acceptlang',
+ 'registrationdate'
)
)
);
@@ -202,13 +219,17 @@ class ApiQueryUserInfo extends ApiQueryBase {
' blockinfo - Tags if the current user is blocked, by whom, and for what reason',
' hasmsg - Adds a tag "message" if the current user has pending messages',
' groups - Lists all the groups the current user belongs to',
+ ' implicitgroups - Lists all the groups the current user is automatically a member of',
' rights - Lists all the rights the current user has',
' changeablegroups - Lists the groups the current user can add to and remove from',
' options - Lists all preferences the current user has set',
+ ' preferencestoken - Get a token to change current user\'s preferences',
' editcount - Adds the current user\'s edit count',
' ratelimits - Lists all rate limits applying to the current user',
+ ' realname - Adds the user\'s real name',
' email - Adds the user\'s email address and email authentication date',
' acceptlang - Echoes the Accept-Language header sent by the client in a structured format',
+ ' registrationdate - Adds the user\'s registration date',
)
);
}
@@ -224,7 +245,11 @@ class ApiQueryUserInfo extends ApiQueryBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Meta#userinfo_.2F_ui';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryUserInfo.php 75937 2010-11-03 17:01:21Z reedy $';
+ return __CLASS__ . ': $Id: ApiQueryUserInfo.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryUsers.php b/includes/api/ApiQueryUsers.php
index 2619d200..6eee1331 100644
--- a/includes/api/ApiQueryUsers.php
+++ b/includes/api/ApiQueryUsers.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on July 30, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@ if ( !defined( 'MEDIAWIKI' ) ) {
*
* @ingroup API
*/
- class ApiQueryUsers extends ApiQueryBase {
+class ApiQueryUsers extends ApiQueryBase {
private $tokenFunctions, $prop;
@@ -66,6 +66,10 @@ if ( !defined( 'MEDIAWIKI' ) ) {
return $this->tokenFunctions;
}
+ /**
+ * @param $user User
+ * @return String
+ */
public static function getUserrightsToken( $user ) {
global $wgUser;
// Since the permissions check for userrights is non-trivial,
@@ -104,14 +108,16 @@ if ( !defined( 'MEDIAWIKI' ) ) {
}
}
+ $result = $this->getResult();
+
if ( count( $goodNames ) ) {
- $this->addTables( 'user', 'u1' );
- $this->addFields( 'u1.*' );
- $this->addWhereFld( 'u1.user_name', $goodNames );
+ $this->addTables( 'user' );
+ $this->addFields( '*' );
+ $this->addWhereFld( 'user_name', $goodNames );
- if ( isset( $this->prop['groups'] ) ) {
+ if ( isset( $this->prop['groups'] ) || isset( $this->prop['rights'] ) ) {
$this->addTables( 'user_groups' );
- $this->addJoinConds( array( 'user_groups' => array( 'LEFT JOIN', 'ug_user=u1.user_id' ) ) );
+ $this->addJoinConds( array( 'user_groups' => array( 'LEFT JOIN', 'ug_user=user_id' ) ) );
$this->addFields( 'ug_group' );
}
@@ -119,9 +125,12 @@ if ( !defined( 'MEDIAWIKI' ) ) {
$data = array();
$res = $this->select( __METHOD__ );
+
foreach ( $res as $row ) {
$user = User::newFromRow( $row );
$name = $user->getName();
+
+ $data[$name]['userid'] = $user->getId();
$data[$name]['name'] = $name;
if ( isset( $this->prop['editcount'] ) ) {
@@ -132,19 +141,30 @@ if ( !defined( 'MEDIAWIKI' ) ) {
$data[$name]['registration'] = wfTimestampOrNull( TS_ISO_8601, $user->getRegistration() );
}
- if ( isset( $this->prop['groups'] ) && !is_null( $row->ug_group ) ) {
- // This row contains only one group, others will be added from other rows
- $data[$name]['groups'][] = $row->ug_group;
+ if ( isset( $this->prop['groups'] ) ) {
+ if ( !isset( $data[$name]['groups'] ) ) {
+ $data[$name]['groups'] = self::getAutoGroups( $user );
+ }
+
+ if ( !is_null( $row->ug_group ) ) {
+ // This row contains only one group, others will be added from other rows
+ $data[$name]['groups'][] = $row->ug_group;
+ }
+ }
+
+ if ( isset( $this->prop['implicitgroups'] ) && !isset( $data[$name]['implicitgroups'] ) ) {
+ $data[$name]['implicitgroups'] = self::getAutoGroups( $user );
}
- if ( isset( $this->prop['rights'] ) && !is_null( $row->ug_group ) ) {
+ if ( isset( $this->prop['rights'] ) ) {
if ( !isset( $data[$name]['rights'] ) ) {
- $data[$name]['rights'] = User::getGroupPermissions( User::getImplicitGroups() );
+ $data[$name]['rights'] = User::getGroupPermissions( $user->getAutomaticGroups() );
}
- $data[$name]['rights'] = array_unique( array_merge( $data[$name]['rights'],
- User::getGroupPermissions( array( $row->ug_group ) ) ) );
- $result->setIndexedTagName( $data[$name]['rights'], 'r' );
+ if ( !is_null( $row->ug_group ) ) {
+ $data[$name]['rights'] = array_unique( array_merge( $data[$name]['rights'],
+ User::getGroupPermissions( array( $row->ug_group ) ) ) );
+ }
}
if ( $row->ipb_deleted ) {
$data[$name]['hidden'] = '';
@@ -180,6 +200,7 @@ if ( !defined( 'MEDIAWIKI' ) ) {
}
}
}
+
// Second pass: add result data to $retval
foreach ( $goodNames as $u ) {
if ( !isset( $data[$u] ) ) {
@@ -207,13 +228,16 @@ if ( !defined( 'MEDIAWIKI' ) ) {
}
} else {
if ( isset( $this->prop['groups'] ) && isset( $data[$u]['groups'] ) ) {
- $autolist = ApiQueryUsers::getAutoGroups( User::newFromName( $u ) );
-
- $data[$u]['groups'] = array_merge( $autolist, $data[$u]['groups'] );
-
- $this->getResult()->setIndexedTagName( $data[$u]['groups'], 'g' );
+ $result->setIndexedTagName( $data[$u]['groups'], 'g' );
+ }
+ if ( isset( $this->prop['implicitgroups'] ) && isset( $data[$u]['implicitgroups'] ) ) {
+ $result->setIndexedTagName( $data[$u]['implicitgroups'], 'g' );
+ }
+ if ( isset( $this->prop['rights'] ) && isset( $data[$u]['rights'] ) ) {
+ $result->setIndexedTagName( $data[$u]['rights'], 'r' );
}
}
+
$fit = $result->addValue( array( 'query', $this->getModuleName() ),
null, $data[$u] );
if ( !$fit ) {
@@ -223,15 +247,17 @@ if ( !defined( 'MEDIAWIKI' ) ) {
}
$done[] = $u;
}
- return $this->getResult()->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'user' );
+ return $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'user' );
}
/**
- * Gets all the groups that a user is automatically a member of
+ * Gets all the groups that a user is automatically a member of (implicit groups)
+ * @param $user User
* @return array
*/
public static function getAutoGroups( $user ) {
- $groups = array( '*' );
+ $groups = array();
+ $groups[] = '*';
if ( !$user->isAnon() ) {
$groups[] = 'user';
@@ -256,6 +282,8 @@ if ( !defined( 'MEDIAWIKI' ) ) {
ApiBase::PARAM_TYPE => array(
'blockinfo',
'groups',
+ 'implicitgroups',
+ 'rights',
'editcount',
'registration',
'emailable',
@@ -276,13 +304,14 @@ if ( !defined( 'MEDIAWIKI' ) ) {
return array(
'prop' => array(
'What pieces of information to include',
- ' blockinfo - Tags if the user is blocked, by whom, and for what reason',
- ' groups - Lists all the groups the user(s) belongs to',
- ' rights - Lists all the rights the user(s) has',
- ' editcount - Adds the user\'s edit count',
- ' registration - Adds the user\'s registration timestamp',
- ' emailable - Tags if the user can and wants to receive e-mail through [[Special:Emailuser]]',
- ' gender - Tags the gender of the user. Returns "male", "female", or "unknown"',
+ ' blockinfo - Tags if the user is blocked, by whom, and for what reason',
+ ' groups - Lists all the groups the user(s) belongs to',
+ ' implicitgroups - Lists all the groups a user is automatically a member of',
+ ' rights - Lists all the rights the user(s) has',
+ ' editcount - Adds the user\'s edit count',
+ ' registration - Adds the user\'s registration timestamp',
+ ' emailable - Tags if the user can and wants to receive e-mail through [[Special:Emailuser]]',
+ ' gender - Tags the gender of the user. Returns "male", "female", or "unknown"',
),
'users' => 'A list of users to obtain the same information for',
'token' => 'Which tokens to obtain for each user',
@@ -297,7 +326,11 @@ if ( !defined( 'MEDIAWIKI' ) ) {
return 'api.php?action=query&list=users&ususers=brion|TimStarling&usprop=groups|editcount|gender';
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Users';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryUsers.php 85354 2011-04-04 18:25:31Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryUsers.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php
index 784f89c0..a5eb23eb 100644
--- a/includes/api/ApiQueryWatchlist.php
+++ b/includes/api/ApiQueryWatchlist.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 25, 2006
*
@@ -51,8 +51,12 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
private $fld_ids = false, $fld_title = false, $fld_patrol = false, $fld_flags = false,
$fld_timestamp = false, $fld_user = false, $fld_comment = false, $fld_parsedcomment = false, $fld_sizes = false,
- $fld_notificationtimestamp = false, $fld_userid = false;
+ $fld_notificationtimestamp = false, $fld_userid = false, $fld_loginfo = false;
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$this->selectNamedDB( 'watchlist', DB_SLAVE, 'watchlist' );
@@ -74,6 +78,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
$this->fld_sizes = isset( $prop['sizes'] );
$this->fld_patrol = isset( $prop['patrol'] );
$this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] );
+ $this->fld_loginfo = isset( $prop['loginfo'] );
if ( $this->fld_patrol ) {
if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
@@ -85,25 +90,25 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
$this->addFields( array(
'rc_namespace',
'rc_title',
- 'rc_timestamp'
+ 'rc_timestamp',
+ 'rc_type',
) );
if ( is_null( $resultPageSet ) ) {
$this->addFields( array(
'rc_cur_id',
- 'rc_this_oldid'
+ 'rc_this_oldid',
+ 'rc_last_oldid',
) );
- $this->addFieldsIf( 'rc_new', $this->fld_flags );
- $this->addFieldsIf( 'rc_minor', $this->fld_flags );
- $this->addFieldsIf( 'rc_bot', $this->fld_flags );
+ $this->addFieldsIf( array( 'rc_new', 'rc_minor', 'rc_bot' ), $this->fld_flags );
$this->addFieldsIf( 'rc_user', $this->fld_user || $this->fld_userid );
$this->addFieldsIf( 'rc_user_text', $this->fld_user );
$this->addFieldsIf( 'rc_comment', $this->fld_comment || $this->fld_parsedcomment );
$this->addFieldsIf( 'rc_patrolled', $this->fld_patrol );
- $this->addFieldsIf( 'rc_old_len', $this->fld_sizes );
- $this->addFieldsIf( 'rc_new_len', $this->fld_sizes );
+ $this->addFieldsIf( array( 'rc_old_len', 'rc_new_len' ), $this->fld_sizes );
$this->addFieldsIf( 'wl_notificationtimestamp', $this->fld_notificationtimestamp );
+ $this->addFieldsIf( array( 'rc_logid', 'rc_log_type', 'rc_log_action', 'rc_params' ), $this->fld_loginfo );
} elseif ( $params['allrev'] ) {
$this->addFields( 'rc_this_oldid' );
} else {
@@ -111,27 +116,33 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
}
$this->addTables( array(
+ 'recentchanges',
'watchlist',
- 'page',
- 'recentchanges'
) );
$userId = $user->getId();
+ $this->addJoinConds( array( 'watchlist' => array('INNER JOIN',
+ array(
+ 'wl_user' => $userId,
+ 'wl_namespace=rc_namespace',
+ 'wl_title=rc_title'
+ ) ) ) );
+
$this->addWhere( array(
- 'wl_namespace = rc_namespace',
- 'wl_title = rc_title',
- 'rc_cur_id = page_id',
- 'wl_user' => $userId,
'rc_deleted' => 0,
) );
-
+
$db = $this->getDB();
- $this->addWhereRange( 'rc_timestamp', $params['dir'],
- $db->timestamp( $params['start'] ),
- $db->timestamp( $params['end'] ) );
+ $this->addTimestampWhereRange( 'rc_timestamp', $params['dir'],
+ $params['start'], $params['end'] );
$this->addWhereFld( 'wl_namespace', $params['namespace'] );
- $this->addWhereIf( 'rc_this_oldid=page_latest', !$params['allrev'] );
+
+ if ( !$params['allrev'] ) {
+ $this->addTables( 'page' );
+ $this->addJoinConds( array( 'page' => array( 'LEFT JOIN','rc_cur_id=page_id' ) ) );
+ $this->addWhere( 'rc_this_oldid=page_latest OR rc_type=' . RC_LOG );
+ }
if ( !is_null( $params['show'] ) ) {
$show = array_flip( $params['show'] );
@@ -143,7 +154,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
|| ( isset ( $show['patrolled'] ) && isset ( $show['!patrolled'] ) )
)
{
- $this->dieUsageMsg( array( 'show' ) );
+ $this->dieUsageMsg( 'show' );
}
// Check permissions.
@@ -172,11 +183,9 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
$this->addWhereFld( 'rc_user_text', $params['user'] );
}
if ( !is_null( $params['excludeuser'] ) ) {
- $this->addWhere( 'rc_user_text != ' . $this->getDB()->addQuotes( $params['excludeuser'] ) );
+ $this->addWhere( 'rc_user_text != ' . $db->addQuotes( $params['excludeuser'] ) );
}
-
-
// This is an index optimization for mysql, as done in the Special:Watchlist page
$this->addWhereIf( "rc_timestamp > ''", !isset( $params['start'] ) && !isset( $params['end'] ) && $db->getType() == 'mysql' );
@@ -225,6 +234,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
if ( $this->fld_ids ) {
$vals['pageid'] = intval( $row->rc_cur_id );
$vals['revid'] = intval( $row->rc_this_oldid );
+ $vals['old_revid'] = intval( $row->rc_last_oldid );
}
$title = Title::makeTitle( $row->rc_namespace, $row->rc_title );
@@ -240,7 +250,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
}
if ( $this->fld_userid ) {
- $vals['user'] = $row->rc_user;
+ $vals['user'] = $row->rc_user;
}
if ( !$row->rc_user ) {
@@ -284,8 +294,21 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
}
if ( $this->fld_parsedcomment && isset( $row->rc_comment ) ) {
- global $wgUser;
- $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->rc_comment, $title );
+ $vals['parsedcomment'] = Linker::formatComment( $row->rc_comment, $title );
+ }
+
+ if ( $this->fld_loginfo && $row->rc_type == RC_LOG ) {
+ $vals['logid'] = intval( $row->rc_logid );
+ $vals['logtype'] = $row->rc_log_type;
+ $vals['logaction'] = $row->rc_log_action;
+ ApiQueryLogEvents::addLogParams(
+ $this->getResult(),
+ $vals,
+ $row->rc_params,
+ $row->rc_log_type,
+ $row->rc_log_action,
+ $row->rc_timestamp
+ );
}
return $vals;
@@ -338,7 +361,8 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
'timestamp',
'patrol',
'sizes',
- 'notificationtimestamp'
+ 'notificationtimestamp',
+ 'loginfo',
)
),
'show' => array(
@@ -364,6 +388,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
}
public function getParamDescription() {
+ $p = $this->getModulePrefix();
return array(
'allrev' => 'Include multiple revisions of the same page within given timeframe',
'start' => 'The timestamp to start enumerating from',
@@ -371,7 +396,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
'namespace' => 'Filter changes to only the given namespace(s)',
'user' => 'Only list changes by this user',
'excludeuser' => 'Don\'t list changes by this user',
- 'dir' => 'In which direction to enumerate pages',
+ 'dir' => $this->getDirectionDescription( $p ),
'limit' => 'How many total results to return per request',
'prop' => array(
'Which additional items to get (non-generator mode only).',
@@ -384,12 +409,13 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
' parsedcomment - Adds parsed comment of the edit',
' timestamp - Adds timestamp of the edit',
' patrol - Tags edits that are patrolled',
- ' size - Adds the old and new lengths of the page',
+ ' sizes - Adds the old and new lengths of the page',
' notificationtimestamp - Adds timestamp of when the user was last notified about the edit',
+ ' loginfo - Adds log information where appropriate',
),
'show' => array(
'Show only items that meet this criteria.',
- "For example, to see only minor edits done by logged-in users, set {$this->getModulePrefix()}show=minor|!anon"
+ "For example, to see only minor edits done by logged-in users, set {$p}show=minor|!anon"
),
'owner' => 'The name of the user whose watchlist you\'d like to access',
'token' => 'Give a security token (settable in preferences) to allow access to another user\'s watchlist'
@@ -423,7 +449,11 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Watchlist';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryWatchlist.php 85435 2011-04-05 14:00:08Z demon $';
+ return __CLASS__ . ': $Id: ApiQueryWatchlist.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiQueryWatchlistRaw.php b/includes/api/ApiQueryWatchlistRaw.php
index 0e5617e3..b008eab2 100644
--- a/includes/api/ApiQueryWatchlistRaw.php
+++ b/includes/api/ApiQueryWatchlistRaw.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Oct 4, 2008
*
- * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2008 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,6 +49,10 @@ class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase {
$this->run( $resultPageSet );
}
+ /**
+ * @param $resultPageSet ApiPageSet
+ * @return void
+ */
private function run( $resultPageSet = null ) {
$this->selectNamedDB( 'watchlist', DB_SLAVE, 'watchlist' );
@@ -59,7 +63,7 @@ class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase {
$prop = array_flip( (array)$params['prop'] );
$show = array_flip( (array)$params['show'] );
if ( isset( $show['changed'] ) && isset( $show['!changed'] ) ) {
- $this->dieUsageMsg( array( 'show' ) );
+ $this->dieUsageMsg( 'show' );
}
$this->addTables( 'watchlist' );
@@ -201,6 +205,6 @@ class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryWatchlistRaw.php 70647 2010-08-07 19:59:42Z ialex $';
+ return __CLASS__ . ': $Id: ApiQueryWatchlistRaw.php 88416 2011-05-19 17:51:16Z hashar $';
}
-} \ No newline at end of file
+}
diff --git a/includes/api/ApiResult.php b/includes/api/ApiResult.php
index 9d42a58e..f7ea0045 100644
--- a/includes/api/ApiResult.php
+++ b/includes/api/ApiResult.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 4, 2006
*
@@ -249,6 +249,12 @@ class ApiResult extends ApiBase {
* Path is an indexed array, each element specifying the branch at which to add the new value
* Setting $path to array('a','b','c') is equivalent to data['a']['b']['c'] = $value
* If $name is empty, the $value is added as a next list element data[] = $value
+ *
+ * @param $path
+ * @param $name string
+ * @param $value mixed
+ * @param $overwrite bool
+ *
* @return bool True if $value fits in the result, false if not
*/
public function addValue( $path, $name, $value, $overwrite = false ) {
@@ -257,6 +263,9 @@ class ApiResult extends ApiBase {
if ( $this->mCheckingSize ) {
$newsize = $this->mSize + self::size( $value );
if ( $newsize > $wgAPIMaxResultSize ) {
+ $this->setWarning(
+ "This result was truncated because it would otherwise be larger than the " .
+ "limit of {$wgAPIMaxResultSize} bytes" );
return false;
}
$this->mSize = $newsize;
@@ -327,6 +336,8 @@ class ApiResult extends ApiBase {
/**
* Callback function for cleanUpUTF8()
+ *
+ * @param $s string
*/
private static function cleanUp_helper( &$s ) {
if ( !is_string( $s ) ) {
@@ -336,11 +347,31 @@ class ApiResult extends ApiBase {
$s = $wgContLang->normalize( $s );
}
+ /**
+ * Converts a Status object to an array suitable for addValue
+ * @param Status $status
+ * @param string $errorType
+ * @return array
+ */
+ public function convertStatusToArray( $status, $errorType = 'error' ) {
+ if ( $status->isGood() ) {
+ return array();
+ }
+
+ $result = array();
+ foreach ( $status->getErrorsByType( $errorType ) as $error ) {
+ $this->setIndexedTagName( $error['params'], 'param' );
+ $result[] = $error;
+ }
+ $this->setIndexedTagName( $result, $errorType );
+ return $result;
+ }
+
public function execute() {
ApiBase::dieDebug( __METHOD__, 'execute() is not supported on Result object' );
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiResult.php 74230 2010-10-03 19:07:11Z reedy $';
+ return __CLASS__ . ': $Id: ApiResult.php 91144 2011-06-29 23:46:39Z reedy $';
}
}
diff --git a/includes/api/ApiRollback.php b/includes/api/ApiRollback.php
index e31bfed8..a149fcaf 100644
--- a/includes/api/ApiRollback.php
+++ b/includes/api/ApiRollback.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Jun 20, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,7 +38,15 @@ class ApiRollback extends ApiBase {
parent::__construct( $main, $action );
}
- private $mTitleObj = null, $mUser = null;
+ /**
+ * @var Title
+ */
+ private $mTitleObj = null;
+
+ /**
+ * @var User
+ */
+ private $mUser = null;
public function execute() {
$params = $this->extractRequestParams();
@@ -47,7 +55,7 @@ class ApiRollback extends ApiBase {
$titleObj = $this->getTitle();
$articleObj = new Article( $titleObj );
$summary = ( isset( $params['summary'] ) ? $params['summary'] : '' );
- $details = null;
+ $details = array();
$retval = $articleObj->doRollback( $this->getUser(), $summary, $params['token'], $params['markbot'], $details );
if ( $retval ) {
@@ -170,7 +178,7 @@ class ApiRollback extends ApiBase {
$this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
}
if ( !$this->mTitleObj->exists() ) {
- $this->dieUsageMsg( array( 'notanarticle' ) );
+ $this->dieUsageMsg( 'notanarticle' );
}
return $this->mTitleObj;
@@ -183,7 +191,11 @@ class ApiRollback extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Rollback';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiRollback.php 75602 2010-10-28 00:04:48Z reedy $';
+ return __CLASS__ . ': $Id: ApiRollback.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiRsd.php b/includes/api/ApiRsd.php
index 7bc4722c..f9a4d285 100644
--- a/includes/api/ApiRsd.php
+++ b/includes/api/ApiRsd.php
@@ -47,7 +47,8 @@ class ApiRsd extends ApiBase {
$service = array( 'apis' => $this->formatRsdApiList() );
ApiResult::setContent( $service, 'MediaWiki', 'engineName' );
- ApiResult::setContent( $service, 'http://www.mediawiki.org/', 'engineLink' );
+ ApiResult::setContent( $service, 'https://www.mediawiki.org/', 'engineLink' );
+ ApiResult::setContent( $service, Title::newMainPage()->getCanonicalUrl(), 'homePageLink' );
$result->setIndexedTagName( $service['apis'], 'api' );
@@ -67,7 +68,7 @@ class ApiRsd extends ApiBase {
}
public function getDescription() {
- return 'Export an RSD schema';
+ return 'Export an RSD (Really Simple Discovery) schema';
}
protected function getExamples() {
@@ -97,10 +98,10 @@ class ApiRsd extends ApiBase {
$apis = array(
'MediaWiki' => array(
// The API link is required for all RSD API entries.
- 'apiLink' => wfExpandUrl( wfScript( 'api' ) ),
+ 'apiLink' => wfExpandUrl( wfScript( 'api' ), PROTO_CURRENT ),
// Docs link is optional, but recommended.
- 'docs' => 'http://mediawiki.org/wiki/API',
+ 'docs' => 'https://www.mediawiki.org/wiki/API',
// Some APIs may need a blog ID, but it may be left blank.
'blogID' => '',
@@ -160,7 +161,7 @@ class ApiRsd extends ApiBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiRsd.php 76195 2010-11-06 15:57:15Z btongminh $';
+ return __CLASS__ . ': $Id: ApiRsd.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
@@ -169,12 +170,12 @@ class ApiFormatXmlRsd extends ApiFormatXml {
parent::__construct( $main, $format );
$this->setRootElement( 'rsd' );
}
-
+
public function getMimeType() {
return 'application/rsd+xml';
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiRsd.php 76195 2010-11-06 15:57:15Z btongminh $';
+ return __CLASS__ . ': $Id: ApiRsd.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiUnblock.php b/includes/api/ApiUnblock.php
index 4f6e4fb7..51ee0241 100644
--- a/includes/api/ApiUnblock.php
+++ b/includes/api/ApiUnblock.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Sep 7, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,40 +49,42 @@ class ApiUnblock extends ApiBase {
$params = $this->extractRequestParams();
if ( $params['gettoken'] ) {
- $res['unblocktoken'] = $wgUser->editToken();
+ $res['unblocktoken'] = $wgUser->editToken( '', $this->getMain()->getRequest() );
$this->getResult()->addValue( null, $this->getModuleName(), $res );
return;
}
if ( is_null( $params['id'] ) && is_null( $params['user'] ) ) {
- $this->dieUsageMsg( array( 'unblock-notarget' ) );
+ $this->dieUsageMsg( 'unblock-notarget' );
}
if ( !is_null( $params['id'] ) && !is_null( $params['user'] ) ) {
- $this->dieUsageMsg( array( 'unblock-idanduser' ) );
+ $this->dieUsageMsg( 'unblock-idanduser' );
}
if ( !$wgUser->isAllowed( 'block' ) ) {
- $this->dieUsageMsg( array( 'cantunblock' ) );
+ $this->dieUsageMsg( 'cantunblock' );
}
# bug 15810: blocked admins should have limited access here
if ( $wgUser->isBlocked() ) {
- $status = IPBlockForm::checkUnblockSelf( $params['user'] );
+ $status = SpecialBlock::checkUnblockSelf( $params['user'] );
if ( $status !== true ) {
- $this->dieUsageMsg( array( $status ) );
+ $this->dieUsageMsg( $status );
}
}
- $id = $params['id'];
- $user = $params['user'];
- $reason = ( is_null( $params['reason'] ) ? '' : $params['reason'] );
- $retval = IPUnblockForm::doUnblock( $id, $user, $reason, $range );
- if ( $retval ) {
- $this->dieUsageMsg( $retval );
+ $data = array(
+ 'Target' => is_null( $params['id'] ) ? $params['user'] : "#{$params['id']}",
+ 'Reason' => is_null( $params['reason'] ) ? '' : $params['reason']
+ );
+ $block = Block::newFromTarget( $data['Target'] );
+ $retval = SpecialUnblock::processUnblock( $data );
+ if ( $retval !== true ) {
+ $this->dieUsageMsg( $retval[0] );
}
- $res['id'] = intval( $id );
- $res['user'] = $user;
- $res['reason'] = $reason;
+ $res['id'] = $block->getId();
+ $res['user'] = $block->getType() == Block::TYPE_AUTO ? '' : $block->getTarget();
+ $res['reason'] = $params['reason'];
$this->getResult()->addValue( null, $this->getModuleName(), $res );
}
@@ -96,7 +98,9 @@ class ApiUnblock extends ApiBase {
public function getAllowedParams() {
return array(
- 'id' => null,
+ 'id' => array(
+ ApiBase::PARAM_TYPE => 'integer',
+ ),
'user' => null,
'token' => null,
'gettoken' => false,
@@ -144,7 +148,11 @@ class ApiUnblock extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Block';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiUnblock.php 74098 2010-10-01 20:12:50Z reedy $';
+ return __CLASS__ . ': $Id: ApiUnblock.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiUndelete.php b/includes/api/ApiUndelete.php
index 3c7d91a5..c2aa2a00 100644
--- a/includes/api/ApiUndelete.php
+++ b/includes/api/ApiUndelete.php
@@ -1,10 +1,10 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Jul 3, 2007
*
- * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2007 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -43,11 +43,11 @@ class ApiUndelete extends ApiBase {
$params = $this->extractRequestParams();
if ( !$wgUser->isAllowed( 'undelete' ) ) {
- $this->dieUsageMsg( array( 'permdenied-undelete' ) );
+ $this->dieUsageMsg( 'permdenied-undelete' );
}
if ( $wgUser->isBlocked() ) {
- $this->dieUsageMsg( array( 'blockedtext' ) );
+ $this->dieUsageMsg( 'blockedtext' );
}
$titleObj = Title::newFromText( $params['title'] );
@@ -69,7 +69,7 @@ class ApiUndelete extends ApiBase {
$pa = new PageArchive( $titleObj );
$retval = $pa->undelete( ( isset( $params['timestamps'] ) ? $params['timestamps'] : array() ), $params['reason'] );
if ( !is_array( $retval ) ) {
- $this->dieUsageMsg( array( 'cannotundelete' ) );
+ $this->dieUsageMsg( 'cannotundelete' );
}
if ( $retval[1] ) {
@@ -103,7 +103,8 @@ class ApiUndelete extends ApiBase {
'token' => null,
'reason' => '',
'timestamps' => array(
- ApiBase::PARAM_ISMULTI => true
+ ApiBase::PARAM_TYPE => 'timestamp',
+ ApiBase::PARAM_ISMULTI => true,
),
'watchlist' => array(
ApiBase::PARAM_DFLT => 'preferences',
@@ -158,7 +159,11 @@ class ApiUndelete extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Undelete';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiUndelete.php 74098 2010-10-01 20:12:50Z reedy $';
+ return __CLASS__ . ': $Id: ApiUndelete.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index e7d7b939..1dab0310 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Aug 21, 2008
*
@@ -33,7 +33,12 @@ if ( !defined( 'MEDIAWIKI' ) ) {
* @ingroup API
*/
class ApiUpload extends ApiBase {
+
+ /**
+ * @var UploadBase
+ */
protected $mUpload = null;
+
protected $mParams;
public function __construct( $main, $action ) {
@@ -45,7 +50,7 @@ class ApiUpload extends ApiBase {
// Check whether upload is enabled
if ( !UploadBase::isEnabled() ) {
- $this->dieUsageMsg( array( 'uploaddisabled' ) );
+ $this->dieUsageMsg( 'uploaddisabled' );
}
// Parameter handling
@@ -54,6 +59,11 @@ class ApiUpload extends ApiBase {
// Add the uploaded file to the params array
$this->mParams['file'] = $request->getFileName( 'file' );
+ // Copy the session key to the file key, for backward compatibility.
+ if( !$this->mParams['filekey'] && $this->mParams['sessionkey'] ) {
+ $this->mParams['filekey'] = $this->mParams['sessionkey'];
+ }
+
// Select an upload module
if ( !$this->selectUploadModule() ) {
// This is not a true upload, but a status request or similar
@@ -77,34 +87,40 @@ class ApiUpload extends ApiBase {
// Check if the uploaded file is sane
$this->verifyUpload();
- // Check permission to upload this file
- $permErrors = $this->mUpload->verifyPermissions( $wgUser );
- if ( $permErrors !== true ) {
- // TODO: stash the upload and allow choosing a new name
- $this->dieUsageMsg( array( 'badaccess-groups' ) );
+
+ // Check if the user has the rights to modify or overwrite the requested title
+ // (This check is irrelevant if stashing is already requested, since the errors
+ // can always be fixed by changing the title)
+ if ( ! $this->mParams['stash'] ) {
+ $permErrors = $this->mUpload->verifyTitlePermissions( $wgUser );
+ if ( $permErrors !== true ) {
+ $this->dieRecoverableError( $permErrors[0], 'filename' );
+ }
}
// Prepare the API result
$result = array();
-
+
$warnings = $this->getApiWarnings();
- if ( $warnings ) {
+ if ( $warnings ) {
$result['result'] = 'Warning';
$result['warnings'] = $warnings;
// in case the warnings can be fixed with some further user action, let's stash this upload
// and return a key they can use to restart it
- try {
- $result['sessionkey'] = $this->performStash();
- } catch ( MWException $e ) {
+ try {
+ $result['filekey'] = $this->performStash();
+ $result['sessionkey'] = $result['filekey']; // backwards compatibility
+ } catch ( MWException $e ) {
$result['warnings']['stashfailed'] = $e->getMessage();
}
- } elseif ( $this->mParams['stash'] ) {
+ } elseif ( $this->mParams['stash'] ) {
// Some uploads can request they be stashed, so as not to publish them immediately.
// In this case, a failure to stash ought to be fatal
try {
- $result['result'] = 'Success';
- $result['sessionkey'] = $this->performStash();
- } catch ( MWException $e ) {
+ $result['result'] = 'Success';
+ $result['filekey'] = $this->performStash();
+ $result['sessionkey'] = $result['filekey']; // backwards compatibility
+ } catch ( MWException $e ) {
$this->dieUsage( $e->getMessage(), 'stashfailed' );
}
} else {
@@ -113,52 +129,76 @@ class ApiUpload extends ApiBase {
$result = $this->performUpload();
}
- if ( $result['result'] === 'Success' ) {
+ if ( $result['result'] === 'Success' ) {
$result['imageinfo'] = $this->mUpload->getImageInfo( $this->getResult() );
}
$this->getResult()->addValue( null, $this->getModuleName(), $result );
-
+
// Cleanup any temporary mess
$this->mUpload->cleanupTempFile();
}
/**
- * Stash the file and return the session key
+ * Stash the file and return the file key
* Also re-raises exceptions with slightly more informative message strings (useful for API)
* @throws MWException
- * @return {String} session key
+ * @return String file key
*/
function performStash() {
try {
- $sessionKey = $this->mUpload->stashSessionFile()->getSessionKey();
+ $fileKey = $this->mUpload->stashFile()->getFileKey();
} catch ( MWException $e ) {
- throw new MWException( 'Stashing temporary file failed: ' . get_class($e) . ' ' . $e->getMessage() );
+ $message = 'Stashing temporary file failed: ' . get_class( $e ) . ' ' . $e->getMessage();
+ wfDebug( __METHOD__ . ' ' . $message . "\n");
+ throw new MWException( $message );
}
- return $sessionKey;
+ return $fileKey;
}
+ /**
+ * Throw an error that the user can recover from by providing a better
+ * value for $parameter
+ *
+ * @param $error array Error array suitable for passing to dieUsageMsg()
+ * @param $parameter string Parameter that needs revising
+ * @param $data array Optional extra data to pass to the user
+ * @throws UsageException
+ */
+ function dieRecoverableError( $error, $parameter, $data = array() ) {
+ try {
+ $data['filekey'] = $this->performStash();
+ $data['sessionkey'] = $data['filekey'];
+ } catch ( MWException $e ) {
+ $data['stashfailed'] = $e->getMessage();
+ }
+ $data['invalidparameter'] = $parameter;
+
+ $parsed = $this->parseMsg( $error );
+ $this->dieUsage( $parsed['info'], $parsed['code'], 0, $data );
+ }
/**
* Select an upload module and set it to mUpload. Dies on failure. If the
- * request was a status request and not a true upload, returns false;
+ * request was a status request and not a true upload, returns false;
* otherwise true
- *
+ *
* @return bool
*/
protected function selectUploadModule() {
- global $wgAllowAsyncCopyUploads;
$request = $this->getMain()->getRequest();
// One and only one of the following parameters is needed
$this->requireOnlyOneParameter( $this->mParams,
- 'sessionkey', 'file', 'url', 'statuskey' );
+ 'filekey', 'file', 'url', 'statuskey' );
+
+ if ( $this->mParams['statuskey'] ) {
+ $this->checkAsyncDownloadEnabled();
- if ( $wgAllowAsyncCopyUploads && $this->mParams['statuskey'] ) {
// Status request for an async upload
$sessionData = UploadFromUrlJob::getSessionData( $this->mParams['statuskey'] );
if ( !isset( $sessionData['result'] ) ) {
- $this->dieUsage( 'No result in session data', 'missingresult');
+ $this->dieUsage( 'No result in session data', 'missingresult' );
}
if ( $sessionData['result'] == 'Warning' ) {
$sessionData['warnings'] = $this->transformWarnings( $sessionData['warnings'] );
@@ -166,28 +206,24 @@ class ApiUpload extends ApiBase {
}
$this->getResult()->addValue( null, $this->getModuleName(), $sessionData );
return false;
-
- }
+ }
// The following modules all require the filename parameter to be set
if ( is_null( $this->mParams['filename'] ) ) {
$this->dieUsageMsg( array( 'missingparam', 'filename' ) );
}
-
- if ( $this->mParams['sessionkey'] ) {
+ if ( $this->mParams['filekey'] ) {
// Upload stashed in a previous request
- $sessionData = $request->getSessionData( UploadBase::getSessionKeyName() );
- if ( !UploadFromStash::isValidSessionKey( $this->mParams['sessionkey'], $sessionData ) ) {
- $this->dieUsageMsg( array( 'invalid-session-key' ) );
+ if ( !UploadFromStash::isValidKey( $this->mParams['filekey'] ) ) {
+ $this->dieUsageMsg( 'invalid-file-key' );
}
- $this->mUpload = new UploadFromStash();
- $this->mUpload->initialize( $this->mParams['filename'],
- $this->mParams['sessionkey'],
- $sessionData[$this->mParams['sessionkey']] );
-
+ // context allows access to the current user without creating new $wgUser references
+ $context = $this->createContext();
+ $this->mUpload = new UploadFromStash( $context->getUser() );
+ $this->mUpload->initialize( $this->mParams['filekey'], $this->mParams['filename'] );
} elseif ( isset( $this->mParams['file'] ) ) {
$this->mUpload = new UploadFromFile();
@@ -198,16 +234,18 @@ class ApiUpload extends ApiBase {
} elseif ( isset( $this->mParams['url'] ) ) {
// Make sure upload by URL is enabled:
if ( !UploadFromUrl::isEnabled() ) {
- $this->dieUsageMsg( array( 'copyuploaddisabled' ) );
+ $this->dieUsageMsg( 'copyuploaddisabled' );
}
$async = false;
if ( $this->mParams['asyncdownload'] ) {
+ $this->checkAsyncDownloadEnabled();
+
if ( $this->mParams['leavemessage'] && !$this->mParams['ignorewarnings'] ) {
$this->dieUsage( 'Using leavemessage without ignorewarnings is not supported',
'missing-ignorewarnings' );
}
-
+
if ( $this->mParams['leavemessage'] ) {
$async = 'async-leavemessage';
} else {
@@ -219,7 +257,7 @@ class ApiUpload extends ApiBase {
$this->mParams['url'], $async );
}
-
+
return true;
}
@@ -236,7 +274,7 @@ class ApiUpload extends ApiBase {
if ( !$user->isLoggedIn() ) {
$this->dieUsageMsg( array( 'mustbeloggedin', 'upload' ) );
} else {
- $this->dieUsageMsg( array( 'badaccess-groups' ) );
+ $this->dieUsageMsg( 'badaccess-groups' );
}
}
}
@@ -254,15 +292,29 @@ class ApiUpload extends ApiBase {
// TODO: Move them to ApiBase's message map
switch( $verification['status'] ) {
+ // Recoverable errors
+ case UploadBase::MIN_LENGTH_PARTNAME:
+ $this->dieRecoverableError( 'filename-tooshort', 'filename' );
+ break;
+ case UploadBase::ILLEGAL_FILENAME:
+ $this->dieRecoverableError( 'illegal-filename', 'filename',
+ array( 'filename' => $verification['filtered'] ) );
+ break;
+ case UploadBase::FILETYPE_MISSING:
+ $this->dieRecoverableError( 'filetype-missing', 'filename' );
+ break;
+ case UploadBase::WINDOWS_NONASCII_FILENAME:
+ $this->dieRecoverableError( 'windows-nonascii-filename', 'filename' );
+ break;
+
+ // Unrecoverable errors
case UploadBase::EMPTY_FILE:
$this->dieUsage( 'The file you submitted was empty', 'empty-file' );
break;
case UploadBase::FILE_TOO_LARGE:
$this->dieUsage( 'The file you submitted was too large', 'file-too-large' );
break;
- case UploadBase::FILETYPE_MISSING:
- $this->dieUsage( 'The file is missing an extension', 'filetype-missing' );
- break;
+
case UploadBase::FILETYPE_BADTYPE:
$this->dieUsage( 'This type of file is banned', 'filetype-banned',
0, array(
@@ -270,13 +322,6 @@ class ApiUpload extends ApiBase {
'allowed' => $wgFileExtensions
) );
break;
- case UploadBase::MIN_LENGTH_PARTNAME:
- $this->dieUsage( 'The filename is too short', 'filename-tooshort' );
- break;
- case UploadBase::ILLEGAL_FILENAME:
- $this->dieUsage( 'The filename is not allowed', 'illegal-filename',
- 0, array( 'filename' => $verification['filtered'] ) );
- break;
case UploadBase::VERIFICATION_ERROR:
$this->getResult()->setIndexedTagName( $verification['details'], 'detail' );
$this->dieUsage( 'This file did not pass file verification', 'verification-error',
@@ -306,30 +351,35 @@ class ApiUpload extends ApiBase {
if ( !$this->mParams['ignorewarnings'] ) {
$warnings = $this->mUpload->checkWarnings();
- if ( $warnings ) {
- // Add indices
- $this->getResult()->setIndexedTagName( $warnings, 'warning' );
-
- if ( isset( $warnings['duplicate'] ) ) {
- $dupes = array();
- foreach ( $warnings['duplicate'] as $dupe ) {
- $dupes[] = $dupe->getName();
- }
- $this->getResult()->setIndexedTagName( $dupes, 'duplicate' );
- $warnings['duplicate'] = $dupes;
- }
+ }
+ return $this->transformWarnings( $warnings );
+ }
+
+ protected function transformWarnings( $warnings ) {
+ if ( $warnings ) {
+ // Add indices
+ $result = $this->getResult();
+ $result->setIndexedTagName( $warnings, 'warning' );
- if ( isset( $warnings['exists'] ) ) {
- $warning = $warnings['exists'];
- unset( $warnings['exists'] );
- $warnings[$warning['warning']] = $warning['file']->getName();
+ if ( isset( $warnings['duplicate'] ) ) {
+ $dupes = array();
+ foreach ( $warnings['duplicate'] as $dupe ) {
+ $dupes[] = $dupe->getName();
}
+ $result->setIndexedTagName( $dupes, 'duplicate' );
+ $warnings['duplicate'] = $dupes;
}
- }
+ if ( isset( $warnings['exists'] ) ) {
+ $warning = $warnings['exists'];
+ unset( $warnings['exists'] );
+ $warnings[$warning['warning']] = $warning['file']->getName();
+ }
+ }
return $warnings;
}
+
/**
* Perform the actual upload. Returns a suitable result array on success;
* dies on failure.
@@ -376,10 +426,19 @@ class ApiUpload extends ApiBase {
$result['result'] = 'Success';
$result['filename'] = $file->getName();
-
return $result;
}
+ /**
+ * Checks if asynchronous copy uploads are enabled and throws an error if they are not.
+ */
+ protected function checkAsyncDownloadEnabled() {
+ global $wgAllowAsyncCopyUploads;
+ if ( !$wgAllowAsyncCopyUploads ) {
+ $this->dieUsage( 'Asynchronous copy uploads disabled', 'asynccopyuploaddisabled');
+ }
+ }
+
public function mustBePosted() {
return true;
}
@@ -413,18 +472,18 @@ class ApiUpload extends ApiBase {
'ignorewarnings' => false,
'file' => null,
'url' => null,
- 'sessionkey' => null,
+ 'filekey' => null,
+ 'sessionkey' => array(
+ ApiBase::PARAM_DFLT => null,
+ ApiBase::PARAM_DEPRECATED => true,
+ ),
'stash' => false,
+
+ 'asyncdownload' => false,
+ 'leavemessage' => false,
+ 'statuskey' => null,
);
- global $wgAllowAsyncCopyUploads;
- if ( $wgAllowAsyncCopyUploads ) {
- $params += array(
- 'asyncdownload' => false,
- 'leavemessage' => false,
- 'statuskey' => null,
- );
- }
return $params;
}
@@ -439,18 +498,14 @@ class ApiUpload extends ApiBase {
'ignorewarnings' => 'Ignore any warnings',
'file' => 'File contents',
'url' => 'Url to fetch the file from',
- 'sessionkey' => 'Session key that identifies a previous upload that was stashed temporarily.',
- 'stash' => 'If set, the server will not add the file to the repository and stash it temporarily.'
- );
+ 'filekey' => 'Key that identifies a previous upload that was stashed temporarily.',
+ 'sessionkey' => 'Same as filekey, maintained for backward compatibility.',
+ 'stash' => 'If set, the server will not add the file to the repository and stash it temporarily.',
- global $wgAllowAsyncCopyUploads;
- if ( $wgAllowAsyncCopyUploads ) {
- $params += array(
- 'asyncdownload' => 'Make fetching a URL asynchronous',
- 'leavemessage' => 'If asyncdownload is used, leave a message on the user talk page if finished',
- 'statuskey' => 'Fetch the upload status for this session key',
- );
- }
+ 'asyncdownload' => 'Make fetching a URL asynchronous',
+ 'leavemessage' => 'If asyncdownload is used, leave a message on the user talk page if finished',
+ 'statuskey' => 'Fetch the upload status for this file key',
+ );
return $params;
@@ -461,32 +516,32 @@ class ApiUpload extends ApiBase {
'Upload a file, or get the status of pending uploads. Several methods are available:',
' * Upload file contents directly, using the "file" parameter',
' * Have the MediaWiki server fetch a file from a URL, using the "url" parameter',
- ' * Complete an earlier upload that failed due to warnings, using the "sessionkey" parameter',
+ ' * Complete an earlier upload that failed due to warnings, using the "filekey" parameter',
'Note that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when',
- 'sending the "file". Note also that queries using session keys must be',
- 'done in the same login session as the query that originally returned the key (i.e. do not',
- 'log out and then log back in). Also you must get and send an edit token before doing any upload stuff'
+ 'sending the "file". Also you must get and send an edit token before doing any upload stuff'
);
}
public function getPossibleErrors() {
- return array_merge( parent::getPossibleErrors(), array(
- array( 'uploaddisabled' ),
- array( 'invalid-session-key' ),
- array( 'uploaddisabled' ),
- array( 'badaccess-groups' ),
- array( 'mustbeloggedin', 'upload' ),
- array( 'badaccess-groups' ),
- array( 'badaccess-groups' ),
- array( 'code' => 'fetchfileerror', 'info' => '' ),
- array( 'code' => 'nomodule', 'info' => 'No upload module set' ),
- array( 'code' => 'empty-file', 'info' => 'The file you submitted was empty' ),
- array( 'code' => 'filetype-missing', 'info' => 'The file is missing an extension' ),
- array( 'code' => 'filename-tooshort', 'info' => 'The filename is too short' ),
- array( 'code' => 'overwrite', 'info' => 'Overwriting an existing file is not allowed' ),
- array( 'code' => 'stashfailed', 'info' => 'Stashing temporary file failed' ),
- array( 'code' => 'internal-error', 'info' => 'An internal error occurred' ),
- ) );
+ return array_merge( parent::getPossibleErrors(),
+ $this->getRequireOnlyOneParameterErrorMessages( array( 'filekey', 'file', 'url', 'statuskey' ) ),
+ array(
+ array( 'uploaddisabled' ),
+ array( 'invalid-file-key' ),
+ array( 'uploaddisabled' ),
+ array( 'mustbeloggedin', 'upload' ),
+ array( 'badaccess-groups' ),
+ array( 'code' => 'fetchfileerror', 'info' => '' ),
+ array( 'code' => 'nomodule', 'info' => 'No upload module set' ),
+ array( 'code' => 'empty-file', 'info' => 'The file you submitted was empty' ),
+ array( 'code' => 'filetype-missing', 'info' => 'The file is missing an extension' ),
+ array( 'code' => 'filename-tooshort', 'info' => 'The filename is too short' ),
+ array( 'code' => 'overwrite', 'info' => 'Overwriting an existing file is not allowed' ),
+ array( 'code' => 'stashfailed', 'info' => 'Stashing temporary file failed' ),
+ array( 'code' => 'internal-error', 'info' => 'An internal error occurred' ),
+ array( 'code' => 'asynccopyuploaddisabled', 'info' => 'Asynchronous copy uploads disabled' ),
+ )
+ );
}
public function needsToken() {
@@ -502,11 +557,15 @@ class ApiUpload extends ApiBase {
'Upload from a URL:',
' api.php?action=upload&filename=Wiki.png&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png',
'Complete an upload that failed due to warnings:',
- ' api.php?action=upload&filename=Wiki.png&sessionkey=sessionkey&ignorewarnings=1',
+ ' api.php?action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1',
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Upload';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiUpload.php 51812 2009-06-12 23:45:20Z dale $';
+ return __CLASS__ . ': $Id: ApiUpload.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiUserrights.php b/includes/api/ApiUserrights.php
index f9fe9ad2..93d4ef25 100644
--- a/includes/api/ApiUserrights.php
+++ b/includes/api/ApiUserrights.php
@@ -1,11 +1,11 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Mar 24, 2009
*
- * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ * Copyright © 2009 Roan Kattouw <Firstname>.<Lastname>@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,9 +53,10 @@ class ApiUserrights extends ApiBase {
$user, (array)$params['add'],
(array)$params['remove'], $params['reason'] );
- $this->getResult()->setIndexedTagName( $r['added'], 'group' );
- $this->getResult()->setIndexedTagName( $r['removed'], 'group' );
- $this->getResult()->addValue( null, $this->getModuleName(), $r );
+ $result = $this->getResult();
+ $result->setIndexedTagName( $r['added'], 'group' );
+ $result->setIndexedTagName( $r['removed'], 'group' );
+ $result->addValue( null, $this->getModuleName(), $r );
}
/**
@@ -138,7 +139,11 @@ class ApiUserrights extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:User_group_membership';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiUserrights.php 75602 2010-10-28 00:04:48Z reedy $';
+ return __CLASS__ . ': $Id: ApiUserrights.php 104449 2011-11-28 15:52:04Z reedy $';
}
}
diff --git a/includes/api/ApiWatch.php b/includes/api/ApiWatch.php
index e9560a4d..6fc55905 100644
--- a/includes/api/ApiWatch.php
+++ b/includes/api/ApiWatch.php
@@ -1,6 +1,6 @@
<?php
/**
- * API for MediaWiki 1.8+
+ *
*
* Created on Jan 4, 2008
*
@@ -49,40 +49,52 @@ class ApiWatch extends ApiBase {
$params = $this->extractRequestParams();
$title = Title::newFromText( $params['title'] );
- if ( !$title ) {
+ if ( !$title || $title->getNamespace() < 0 ) {
$this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
}
- $article = new Article( $title );
+ $article = new Article( $title, 0 );
$res = array( 'title' => $title->getPrefixedText() );
if ( $params['unwatch'] ) {
$res['unwatched'] = '';
$res['message'] = wfMsgExt( 'removedwatchtext', array( 'parse' ), $title->getPrefixedText() );
- $success = $article->doUnwatch();
+ $success = WatchAction::doUnwatch( $title, $wgUser );
} else {
$res['watched'] = '';
$res['message'] = wfMsgExt( 'addedwatchtext', array( 'parse' ), $title->getPrefixedText() );
- $success = $article->doWatch();
+ $success = UnwatchAction::doWatch( $title, $wgUser );
}
if ( !$success ) {
- $this->dieUsageMsg( array( 'hookaborted' ) );
+ $this->dieUsageMsg( 'hookaborted' );
}
$this->getResult()->addValue( null, $this->getModuleName(), $res );
}
+ public function mustBePosted() {
+ return true;
+ }
+
public function isWriteMode() {
return true;
}
+ public function needsToken() {
+ return true;
+ }
+
+ public function getTokenSalt() {
+ return 'watch';
+ }
+
public function getAllowedParams() {
return array(
'title' => array(
ApiBase::PARAM_TYPE => 'string',
ApiBase::PARAM_REQUIRED => true
),
-
'unwatch' => false,
+ 'token' => null,
);
}
@@ -90,6 +102,7 @@ class ApiWatch extends ApiBase {
return array(
'title' => 'The page to (un)watch',
'unwatch' => 'If set the page will be unwatched rather than watched',
+ 'token' => 'A token previously acquired via prop=info',
);
}
@@ -112,7 +125,11 @@ class ApiWatch extends ApiBase {
);
}
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Watch';
+ }
+
public function getVersion() {
- return __CLASS__ . ': $Id: ApiWatch.php 77192 2010-11-23 22:05:27Z btongminh $';
+ return __CLASS__ . ': $Id: ApiWatch.php 104449 2011-11-28 15:52:04Z reedy $';
}
}