From d9022f63880ce039446fba8364f68e656b7bf4cb Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Thu, 3 May 2012 13:01:35 +0200 Subject: Update to MediaWiki 1.19.0 --- includes/api/ApiBase.php | 177 +++++++++++++++-------- includes/api/ApiBlock.php | 25 ++-- includes/api/ApiComparePages.php | 6 +- includes/api/ApiDelete.php | 116 +++++++-------- includes/api/ApiDisabled.php | 9 +- includes/api/ApiEditPage.php | 120 ++++++++-------- includes/api/ApiEmailUser.php | 13 +- includes/api/ApiExpandTemplates.php | 17 +-- includes/api/ApiFeedContributions.php | 11 +- includes/api/ApiFeedWatchlist.php | 24 ++-- includes/api/ApiFileRevert.php | 15 +- includes/api/ApiFormatBase.php | 20 +-- includes/api/ApiFormatDbg.php | 5 - includes/api/ApiFormatDump.php | 5 - includes/api/ApiFormatJson.php | 5 - includes/api/ApiFormatPhp.php | 5 - includes/api/ApiFormatRaw.php | 5 - includes/api/ApiFormatTxt.php | 5 - includes/api/ApiFormatWddx.php | 7 +- includes/api/ApiFormatXml.php | 17 ++- includes/api/ApiFormatYaml.php | 5 - includes/api/ApiHelp.php | 22 +-- includes/api/ApiImport.php | 18 +-- includes/api/ApiLogin.php | 47 ++++--- includes/api/ApiLogout.php | 17 +-- includes/api/ApiMain.php | 92 ++++++------ includes/api/ApiMove.php | 15 +- includes/api/ApiOpenSearch.php | 9 +- includes/api/ApiPageSet.php | 17 +-- includes/api/ApiParamInfo.php | 137 ++++++++++++------ includes/api/ApiParse.php | 71 +++++----- includes/api/ApiPatrol.php | 10 +- includes/api/ApiProtect.php | 27 ++-- includes/api/ApiPurge.php | 82 ++++++----- includes/api/ApiQuery.php | 27 ++-- includes/api/ApiQueryAllCategories.php | 8 +- includes/api/ApiQueryAllLinks.php | 7 +- includes/api/ApiQueryAllUsers.php | 32 +++-- includes/api/ApiQueryAllimages.php | 21 ++- includes/api/ApiQueryAllmessages.php | 32 +++-- includes/api/ApiQueryAllpages.php | 26 ++-- includes/api/ApiQueryBacklinks.php | 7 +- includes/api/ApiQueryBase.php | 31 +++-- includes/api/ApiQueryBlocks.php | 58 ++++++-- includes/api/ApiQueryCategories.php | 32 +++-- includes/api/ApiQueryCategoryInfo.php | 7 +- includes/api/ApiQueryCategoryMembers.php | 15 +- includes/api/ApiQueryDeletedrevs.php | 48 ++++--- includes/api/ApiQueryDisabled.php | 9 +- includes/api/ApiQueryDuplicateFiles.php | 18 ++- includes/api/ApiQueryExtLinksUsage.php | 7 +- includes/api/ApiQueryExternalLinks.php | 10 +- includes/api/ApiQueryFilearchive.php | 22 ++- includes/api/ApiQueryIWBacklinks.php | 7 +- includes/api/ApiQueryIWLinks.php | 37 +++-- includes/api/ApiQueryImageInfo.php | 10 +- includes/api/ApiQueryImages.php | 33 +++-- includes/api/ApiQueryInfo.php | 33 ++--- includes/api/ApiQueryLangBacklinks.php | 7 +- includes/api/ApiQueryLangLinks.php | 33 +++-- includes/api/ApiQueryLinks.php | 50 +++---- includes/api/ApiQueryLogEvents.php | 50 ++++--- includes/api/ApiQueryPageProps.php | 7 +- includes/api/ApiQueryProtectedTitles.php | 10 +- includes/api/ApiQueryQueryPage.php | 14 +- includes/api/ApiQueryRandom.php | 7 +- includes/api/ApiQueryRecentChanges.php | 20 +-- includes/api/ApiQueryRevisions.php | 57 +++++--- includes/api/ApiQuerySearch.php | 10 +- includes/api/ApiQuerySiteinfo.php | 79 +++++++---- includes/api/ApiQueryStashImageInfo.php | 7 +- includes/api/ApiQueryTags.php | 7 +- includes/api/ApiQueryUserContributions.php | 21 ++- includes/api/ApiQueryUserInfo.php | 61 ++++---- includes/api/ApiQueryUsers.php | 9 +- includes/api/ApiQueryWatchlist.php | 11 +- includes/api/ApiQueryWatchlistRaw.php | 7 +- includes/api/ApiResult.php | 15 +- includes/api/ApiRollback.php | 19 +-- includes/api/ApiRsd.php | 6 +- includes/api/ApiUnblock.php | 19 +-- includes/api/ApiUndelete.php | 14 +- includes/api/ApiUpload.php | 217 ++++++++++++++++++++--------- includes/api/ApiUserrights.php | 13 +- includes/api/ApiWatch.php | 24 ++-- 85 files changed, 1309 insertions(+), 1198 deletions(-) (limited to 'includes/api') diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php index 9fe96199..a586f688 100644 --- a/includes/api/ApiBase.php +++ b/includes/api/ApiBase.php @@ -39,7 +39,7 @@ * * @ingroup API */ -abstract class ApiBase { +abstract class ApiBase extends ContextSource { // These constants allow modules to specify exactly how to treat incoming parameters. @@ -72,6 +72,10 @@ abstract class ApiBase { $this->mMainModule = $mainModule; $this->mModuleName = $moduleName; $this->mModulePrefix = $modulePrefix; + + if ( !$this->isMain() ) { + $this->setContext( $mainModule->getContext() ); + } } /***************************************************************************** @@ -179,16 +183,12 @@ abstract class ApiBase { * The object will have the WebRequest and the User object set to the ones * used in this instance. * - * @return RequestContext + * @deprecated since 1.19 use getContext to get the current context + * @return DerivativeContext */ 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; + wfDeprecated( __METHOD__, '1.19' ); + return new DerivativeContext( $this->getContext() ); } /** @@ -236,7 +236,7 @@ abstract class ApiBase { public function makeHelpMsg() { static $lnPrfx = "\n "; - $msg = $this->getDescription(); + $msg = $this->getFinalDescription(); if ( $msg !== false ) { @@ -267,7 +267,30 @@ abstract class ApiBase { $msg .= "Parameters:\n$paramsMsg"; } - $msg .= $this->makeHelpArrayToString( $lnPrfx, "Example", $this->getExamples() ); + $examples = $this->getExamples(); + if ( $examples !== false && $examples !== '' ) { + if ( !is_array( $examples ) ) { + $examples = array( + $examples + ); + } + $msg .= "Example" . ( count( $examples ) > 1 ? 's' : '' ) . ":\n"; + foreach( $examples as $k => $v ) { + + if ( is_numeric( $k ) ) { + $msg .= " $v\n"; + } else { + $v .= ":"; + if ( is_array( $v ) ) { + $msgExample = implode( "\n", array_map( array( $this, 'indentExampleText' ), $v ) ); + } else { + $msgExample = " $v"; + } + $msg .= wordwrap( $msgExample, 100, "\n" ) . "\n $k\n"; + } + } + } + $msg .= $this->makeHelpArrayToString( $lnPrfx, "Help page", $this->getHelpUrls() ); if ( $this->getMain()->getShowVersions() ) { @@ -291,6 +314,14 @@ abstract class ApiBase { return $msg; } + /** + * @param $item string + * @return string + */ + private function indentExampleText( $item ) { + return " " . $item; + } + /** * @param $prefix string Text to split output items * @param $title string What is being output @@ -341,20 +372,20 @@ abstract class ApiBase { } $deprecated = isset( $paramSettings[self::PARAM_DEPRECATED] ) ? - $paramSettings[self::PARAM_DEPRECATED] : false; + $paramSettings[self::PARAM_DEPRECATED] : false; if ( $deprecated ) { $desc = "DEPRECATED! $desc"; } $required = isset( $paramSettings[self::PARAM_REQUIRED] ) ? - $paramSettings[self::PARAM_REQUIRED] : false; + $paramSettings[self::PARAM_REQUIRED] : false; if ( $required ) { $desc .= $paramPrefix . "This parameter is required"; } $type = isset( $paramSettings[self::PARAM_TYPE] ) ? $paramSettings[self::PARAM_TYPE] : null; if ( isset( $type ) ) { - if ( isset( $paramSettings[self::PARAM_ISMULTI] ) ) { + if ( isset( $paramSettings[self::PARAM_ISMULTI] ) && $paramSettings[self::PARAM_ISMULTI] ) { $prompt = 'Values (separate with \'|\'): '; } else { $prompt = 'One value: '; @@ -411,7 +442,7 @@ abstract class ApiBase { if ( !$isArray || $isArray && count( $paramSettings[self::PARAM_TYPE] ) > self::LIMIT_SML1 ) { $desc .= $paramPrefix . "Maximum number of values " . - self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)"; + self::LIMIT_SML1 . " (" . self::LIMIT_SML2 . " for bots)"; } } } @@ -437,6 +468,7 @@ abstract class ApiBase { * Callback for preg_replace_callback() call in makeHelpMsg(). * Replaces a source file name with a link to ViewVC * + * @param $matches array * @return string */ public function makeHelpMsg_callback( $matches ) { @@ -464,8 +496,8 @@ abstract class ApiBase { // returning the version string for ApiBase work if ( $path ) { return "{$matches[0]}\n https://svn.wikimedia.org/" . - "viewvc/mediawiki/trunk/" . dirname( $path ) . - "/{$matches[2]}"; + "viewvc/mediawiki/trunk/" . dirname( $path ) . + "/{$matches[2]}"; } return $matches[0]; } @@ -510,6 +542,7 @@ abstract class ApiBase { /** * Get final list of parameters, after hooks have had a chance to * tweak it as needed. + * * @return array or false */ public function getFinalParams() { @@ -519,8 +552,9 @@ abstract class ApiBase { } /** - * Get final description, after hooks have had a chance to tweak it as + * Get final parameter descriptions, after hooks have had a chance to tweak it as * needed. + * * @return array */ public function getFinalParamDescription() { @@ -529,6 +563,18 @@ abstract class ApiBase { return $desc; } + /** + * Get final module description, after hooks have had a chance to tweak it as + * needed. + * + * @return array + */ + public function getFinalDescription() { + $desc = $this->getDescription(); + wfRunHooks( 'APIGetDescription', array( &$this, &$desc ) ); + return $desc; + } + /** * This method mangles parameter name based on the prefix supplied to the constructor. * Override this method to change parameter name during runtime @@ -586,7 +632,7 @@ abstract class ApiBase { array_shift( $required ); $intersection = array_intersect( array_keys( array_filter( $params, - array( $this, "parameterNotEmpty" ) ) ), $required ); + array( $this, "parameterNotEmpty" ) ) ), $required ); if ( count( $intersection ) > 1 ) { $this->dieUsage( 'The parameters ' . implode( ', ', $intersection ) . ' can not be used together', 'invalidparammix' ); @@ -621,7 +667,7 @@ abstract class ApiBase { array_shift( $required ); $intersection = array_intersect( array_keys( array_filter( $params, - array( $this, "parameterNotEmpty" ) ) ), $required ); + array( $this, "parameterNotEmpty" ) ) ), $required ); if ( count( $intersection ) > 1 ) { $this->dieUsage( 'The parameters ' . implode( ', ', $intersection ) . ' can not be used together', 'invalidparammix' ); @@ -655,8 +701,11 @@ abstract class ApiBase { /** * @deprecated since 1.17 use MWNamespace::getValidNamespaces() + * + * @return array */ public static function getValidNamespaces() { + wfDeprecated( __METHOD__, '1.17' ); return MWNamespace::getValidNamespaces(); } @@ -672,7 +721,6 @@ abstract class ApiBase { $userWatching = $titleObj->userIsWatching(); - global $wgUser; switch ( $watchlist ) { case 'watch': return true; @@ -688,10 +736,10 @@ abstract class ApiBase { # If no user option was passed, use watchdefault or watchcreation if ( is_null( $userOption ) ) { $userOption = $titleObj->exists() - ? 'watchdefault' : 'watchcreations'; + ? 'watchdefault' : 'watchcreations'; } # Watch the article based on the user preference - return (bool)$wgUser->getOption( $userOption ); + return (bool)$this->getUser()->getOption( $userOption ); case 'nochange': return $userWatching; @@ -713,11 +761,11 @@ abstract class ApiBase { return; } - global $wgUser; + $user = $this->getUser(); if ( $value ) { - WatchAction::doWatch( $titleObj, $wgUser ); + WatchAction::doWatch( $titleObj, $user ); } else { - WatchAction::doUnwatch( $titleObj, $wgUser ); + WatchAction::doUnwatch( $titleObj, $user ); } } @@ -765,9 +813,9 @@ abstract class ApiBase { ApiBase::dieDebug( __METHOD__, "Boolean param $encParamName's default is set to '$default'" ); } - $value = $this->getMain()->getRequest()->getCheck( $encParamName ); + $value = $this->getRequest()->getCheck( $encParamName ); } else { - $value = $this->getMain()->getRequest()->getVal( $encParamName, $default ); + $value = $this->getRequest()->getVal( $encParamName, $default ); if ( isset( $value ) && $type == 'namespace' ) { $type = MWNamespace::getValidNamespaces(); @@ -904,13 +952,18 @@ abstract class ApiBase { // This is a bit awkward, but we want to avoid calling canApiHighLimits() because it unstubs $wgUser $valuesList = explode( '|', $value, self::LIMIT_SML2 + 1 ); $sizeLimit = count( $valuesList ) > self::LIMIT_SML1 && $this->mMainModule->canApiHighLimits() ? - self::LIMIT_SML2 : self::LIMIT_SML1; + self::LIMIT_SML2 : self::LIMIT_SML1; if ( self::truncateArray( $valuesList, $sizeLimit ) ) { $this->setWarning( "Too many values supplied for parameter '$valueName': the limit is $sizeLimit" ); } if ( !$allowMultiple && count( $valuesList ) != 1 ) { + // Bug 33482 - Allow entries with | in them for non-multiple values + if ( in_array( $value, $allowedValues ) ) { + return $value; + } + $possibleValues = is_array( $allowedValues ) ? "of '" . implode( "', '", $allowedValues ) . "'" : ''; $this->dieUsage( "Only one $possibleValues is allowed for parameter '$valueName'", "multival_$valueName" ); } @@ -1037,17 +1090,17 @@ abstract class ApiBase { */ public static $messageMap = array( // This one MUST be present, or dieUsageMsg() will recurse infinitely - 'unknownerror' => array( 'code' => 'unknownerror', 'info' => "Unknown error: ``\$1''" ), + 'unknownerror' => array( 'code' => 'unknownerror', 'info' => "Unknown error: \"\$1\"" ), 'unknownerror-nocode' => array( 'code' => 'unknownerror', 'info' => 'Unknown error' ), // Messages from Title::getUserPermissionsErrors() '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" ), + 'namespaceprotected' => array( 'code' => 'protectednamespace', 'info' => "You're not allowed to edit pages in the \"\$1\" namespace" ), '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" ), + '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" ), 'badaccess-group0' => array( 'code' => 'permissiondenied', 'info' => "Permission denied" ), // Generic permission denied message 'badaccess-groups' => array( 'code' => 'permissiondenied', 'info' => "Permission denied" ), @@ -1066,7 +1119,7 @@ abstract class ApiBase { 'cantrollback' => array( 'code' => 'onlyauthor', 'info' => "The page you tried to rollback only has one author" ), 'readonlytext' => array( 'code' => 'readonly', 'info' => "The wiki is currently in read-only mode" ), 'sessionfailure' => array( 'code' => 'badtoken', 'info' => "Invalid token" ), - 'cannotdelete' => array( 'code' => 'cantdelete', 'info' => "Couldn't delete ``\$1''. Maybe it was deleted already by someone else" ), + 'cannotdelete' => array( 'code' => 'cantdelete', 'info' => "Couldn't delete \"\$1\". Maybe it was deleted already by someone else" ), 'notanarticle' => array( 'code' => 'missingtitle', 'info' => "The page you requested doesn't exist" ), 'selfmove' => array( 'code' => 'selfmove', 'info' => "Can't move a page to itself" ), 'immobile_namespace' => array( 'code' => 'immobilenamespace', 'info' => "You tried to move pages from or to a namespace that is protected from moving" ), @@ -1084,7 +1137,7 @@ abstract class ApiBase { 'badipaddress' => array( 'code' => 'invalidip', 'info' => "Invalid IP address specified" ), 'ipb_expiry_invalid' => array( 'code' => 'invalidexpiry', 'info' => "Invalid expiry time" ), 'ipb_already_blocked' => array( 'code' => 'alreadyblocked', 'info' => "The user you tried to block was already blocked" ), - 'ipb_blocked_as_range' => array( 'code' => 'blockedasrange', 'info' => "IP address ``\$1'' was blocked as part of range ``\$2''. You can't unblock the IP invidually, but you can unblock the range as a whole." ), + 'ipb_blocked_as_range' => array( 'code' => 'blockedasrange', 'info' => "IP address \"\$1\" was blocked as part of range \"\$2\". You can't unblock the IP invidually, but you can unblock the range as a whole." ), 'ipb_cant_unblock' => array( 'code' => 'cantunblock', 'info' => "The block you specified was not found. It may have been unblocked already" ), 'mailnologin' => array( 'code' => 'cantsend', 'info' => "You are not logged in, you do not have a confirmed e-mail address, or you are not allowed to send e-mail to other users, so you cannot send e-mail" ), 'ipbblocked' => array( 'code' => 'ipbblocked', 'info' => 'You cannot block or unblock users while you are yourself blocked' ), @@ -1098,9 +1151,9 @@ abstract class ApiBase { 'delete-toobig' => array( 'code' => 'bigdelete', 'info' => "You can't delete this page because it has more than \$1 revisions" ), 'movenotallowedfile' => array( 'code' => 'cantmovefile', 'info' => "You don't have permission to move files" ), 'userrights-no-interwiki' => array( 'code' => 'nointerwikiuserrights', 'info' => "You don't have permission to change user rights on other wikis" ), - 'userrights-nodatabase' => array( 'code' => 'nosuchdatabase', 'info' => "Database ``\$1'' does not exist or is not local" ), - 'nouserspecified' => array( 'code' => 'invaliduser', 'info' => "Invalid username ``\$1''" ), - 'noname' => array( 'code' => 'invaliduser', 'info' => "Invalid username ``\$1''" ), + 'userrights-nodatabase' => array( 'code' => 'nosuchdatabase', 'info' => "Database \"\$1\" does not exist or is not local" ), + 'nouserspecified' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ), + 'noname' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ), 'summaryrequired' => array( 'code' => 'summaryrequired', 'info' => 'Summary required' ), // API-specific messages @@ -1108,13 +1161,13 @@ abstract class ApiBase { 'writedisabled' => array( 'code' => 'noapiwrite', 'info' => "Editing of this wiki through the API is disabled. Make sure the \$wgEnableWriteAPI=true; statement is included in the wiki's LocalSettings.php file" ), 'writerequired' => array( 'code' => 'writeapidenied', 'info' => "You're not allowed to edit this wiki through the API" ), 'missingparam' => array( 'code' => 'no$1', 'info' => "The \$1 parameter must be set" ), - 'invalidtitle' => array( 'code' => 'invalidtitle', 'info' => "Bad title ``\$1''" ), + 'invalidtitle' => array( 'code' => 'invalidtitle', 'info' => "Bad title \"\$1\"" ), 'nosuchpageid' => array( 'code' => 'nosuchpageid', 'info' => "There is no page with ID \$1" ), 'nosuchrevid' => array( 'code' => 'nosuchrevid', 'info' => "There is no revision with ID \$1" ), - 'nosuchuser' => array( 'code' => 'nosuchuser', 'info' => "User ``\$1'' doesn't exist" ), - 'invaliduser' => array( 'code' => 'invaliduser', 'info' => "Invalid username ``\$1''" ), - 'invalidexpiry' => array( 'code' => 'invalidexpiry', 'info' => "Invalid expiry time ``\$1''" ), - 'pastexpiry' => array( 'code' => 'pastexpiry', 'info' => "Expiry time ``\$1'' is in the past" ), + 'nosuchuser' => array( 'code' => 'nosuchuser', 'info' => "User \"\$1\" doesn't exist" ), + 'invaliduser' => array( 'code' => 'invaliduser', 'info' => "Invalid username \"\$1\"" ), + 'invalidexpiry' => array( 'code' => 'invalidexpiry', 'info' => "Invalid expiry time \"\$1\"" ), + 'pastexpiry' => array( 'code' => 'pastexpiry', 'info' => "Expiry time \"\$1\" is in the past" ), 'create-titleexists' => array( 'code' => 'create-titleexists', 'info' => "Existing titles can't be protected with 'create'" ), 'missingtitle-createonly' => array( 'code' => 'missingtitle-createonly', 'info' => "Missing titles can only be protected with 'create'" ), 'cantblock' => array( 'code' => 'cantblock', 'info' => "You don't have permission to block users" ), @@ -1127,9 +1180,9 @@ abstract class ApiBase { 'permdenied-undelete' => array( 'code' => 'permissiondenied', 'info' => "You don't have permission to restore deleted revisions" ), 'createonly-exists' => array( 'code' => 'articleexists', 'info' => "The article you tried to create has been created already" ), 'nocreate-missing' => array( 'code' => 'missingtitle', 'info' => "The article you tried to edit doesn't exist" ), - 'nosuchrcid' => array( 'code' => 'nosuchrcid', 'info' => "There is no change with rcid ``\$1''" ), - 'protect-invalidaction' => array( 'code' => 'protect-invalidaction', 'info' => "Invalid protection type ``\$1''" ), - 'protect-invalidlevel' => array( 'code' => 'protect-invalidlevel', 'info' => "Invalid protection level ``\$1''" ), + 'nosuchrcid' => array( 'code' => 'nosuchrcid', 'info' => "There is no change with rcid \"\$1\"" ), + 'protect-invalidaction' => array( 'code' => 'protect-invalidaction', 'info' => "Invalid protection type \"\$1\"" ), + 'protect-invalidlevel' => array( 'code' => 'protect-invalidlevel', 'info' => "Invalid protection level \"\$1\"" ), 'toofewexpiries' => array( 'code' => 'toofewexpiries', 'info' => "\$1 expiry timestamps were provided where \$2 were needed" ), 'cantimport' => array( 'code' => 'cantimport', 'info' => "You don't have permission to import pages" ), 'cantimport-upload' => array( 'code' => 'cantimport-upload', 'info' => "You don't have permission to import uploaded pages" ), @@ -1141,17 +1194,19 @@ abstract class ApiBase { 'importcantopen' => array( 'code' => 'cantopenfile', 'info' => "Couldn't open the uploaded file" ), 'import-noarticle' => array( 'code' => 'badinterwiki', 'info' => 'Invalid interwiki title specified' ), 'importbadinterwiki' => array( 'code' => 'badinterwiki', 'info' => 'Invalid interwiki title specified' ), - 'import-unknownerror' => array( 'code' => 'import-unknownerror', 'info' => "Unknown error on import: ``\$1''" ), + 'import-unknownerror' => array( 'code' => 'import-unknownerror', 'info' => "Unknown error on import: \"\$1\"" ), 'cantoverwrite-sharedfile' => array( 'code' => 'cantoverwrite-sharedfile', 'info' => 'The target file exists on a shared repository and you do not have permission to override it' ), '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" ), + 'invalidoldimage' => array( 'code' => 'invalidoldimage', 'info' => 'The oldimage parameter has invalid format' ), + 'nodeleteablefile' => array( 'code' => 'nodeleteablefile', 'info' => 'No such old version of the file' ), // ApiEditPage messages 'noimageredirect-anon' => array( 'code' => 'noimageredirect-anon', 'info' => "Anonymous users can't create image redirects" ), 'noimageredirect-logged' => array( 'code' => 'noimageredirect', 'info' => "You don't have permission to create image redirects" ), - 'spamdetected' => array( 'code' => 'spamdetected', 'info' => "Your edit was refused because it contained a spam fragment: ``\$1''" ), + 'spamdetected' => array( 'code' => 'spamdetected', 'info' => "Your edit was refused because it contained a spam fragment: \"\$1\"" ), 'filtered' => array( 'code' => 'filtered', 'info' => "The filter callback function refused your edit" ), 'contenttoobig' => array( 'code' => 'contenttoobig', 'info' => "The content you supplied exceeds the article size limit of \$1 kilobytes" ), 'noedit-anon' => array( 'code' => 'noedit-anon', 'info' => "Anonymous users can't edit pages" ), @@ -1162,9 +1217,9 @@ abstract class ApiBase { 'hashcheckfailed' => array( 'code' => 'badmd5', 'info' => "The supplied MD5 hash was incorrect" ), 'missingtext' => array( 'code' => 'notext', 'info' => "One of the text, appendtext, prependtext and undo parameters must be set" ), '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''" ), + '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" ), @@ -1178,8 +1233,11 @@ abstract class ApiBase { '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' ), + 'filename-toolong' => array( 'code' => 'filename-toolong', 'info' => 'The filename is too long' ), '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' ), + + 'mustbeloggedin' => array( 'code' => 'mustbeloggedin', 'info' => 'You must be logged in to $1.' ) ); /** @@ -1211,6 +1269,7 @@ abstract class ApiBase { * @return array('code' => code, 'info' => info) */ public function parseMsg( $error ) { + $error = (array)$error; // It seems strings sometimes make their way in here $key = array_shift( $error ); // Check whether the error array was nested @@ -1222,8 +1281,8 @@ abstract class ApiBase { if ( isset( self::$messageMap[$key] ) ) { return array( 'code' => - wfMsgReplaceArgs( self::$messageMap[$key]['code'], $error ), - 'info' => + wfMsgReplaceArgs( self::$messageMap[$key]['code'], $error ), + 'info' => wfMsgReplaceArgs( self::$messageMap[$key]['info'], $error ) ); } @@ -1282,7 +1341,7 @@ 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 - * @return bool + * @return bool|string */ public function getTokenSalt() { return false; @@ -1295,10 +1354,9 @@ abstract class ApiBase { * @return User */ public function getWatchlistUser( $params ) { - global $wgUser; if ( !is_null( $params['owner'] ) && !is_null( $params['token'] ) ) { $user = User::newFromName( $params['owner'], false ); - if ( !$user->getId() ) { + if ( !($user && $user->getId()) ) { $this->dieUsage( 'Specified user does not exist', 'bad_wlowner' ); } $token = $user->getOption( 'watchlisttoken' ); @@ -1306,10 +1364,10 @@ abstract class ApiBase { $this->dieUsage( 'Incorrect watchlist token provided -- please set a correct token in Special:Preferences', 'bad_wltoken' ); } } else { - if ( !$wgUser->isLoggedIn() ) { + if ( !$this->getUser()->isLoggedIn() ) { $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' ); } - $user = $wgUser; + $user = $this->getUser(); } return $user; } @@ -1481,6 +1539,13 @@ abstract class ApiBase { return $this->mDBTime; } + /** + * @return DatabaseBase + */ + protected function getDB() { + return wfGetDB( DB_SLAVE, 'api' ); + } + /** * Debugging function that prints a value and an optional backtrace * @param $value mixed Value to print diff --git a/includes/api/ApiBlock.php b/includes/api/ApiBlock.php index bb2bb253..351ac6b7 100644 --- a/includes/api/ApiBlock.php +++ b/includes/api/ApiBlock.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API module that facilitates the blocking of users. Requires API write mode * to be enabled. @@ -48,29 +43,29 @@ class ApiBlock extends ApiBase { * of success. If it fails, the result will specify the nature of the error. */ public function execute() { - global $wgUser; + $user = $this->getUser(); $params = $this->extractRequestParams(); if ( $params['gettoken'] ) { - $res['blocktoken'] = $wgUser->editToken( '', $this->getMain()->getRequest() ); + $res['blocktoken'] = $user->getEditToken( '', $this->getMain()->getRequest() ); $this->getResult()->addValue( null, $this->getModuleName(), $res ); return; } - if ( !$wgUser->isAllowed( 'block' ) ) { + if ( !$user->isAllowed( 'block' ) ) { $this->dieUsageMsg( 'cantblock' ); } # bug 15810: blocked admins should have limited access here - if ( $wgUser->isBlocked() ) { - $status = SpecialBlock::checkUnblockSelf( $params['user'] ); + if ( $user->isBlocked() ) { + $status = SpecialBlock::checkUnblockSelf( $params['user'], $user ); if ( $status !== true ) { $this->dieUsageMsg( array( $status ) ); } } - if ( $params['hidename'] && !$wgUser->isAllowed( 'hideuser' ) ) { + if ( $params['hidename'] && !$user->isAllowed( 'hideuser' ) ) { $this->dieUsageMsg( 'canthide' ); } - if ( $params['noemail'] && !SpecialBlock::canBlockEmail( $wgUser ) ) { + if ( $params['noemail'] && !SpecialBlock::canBlockEmail( $user ) ) { $this->dieUsageMsg( 'cantblock-email' ); } @@ -87,13 +82,13 @@ class ApiBlock extends ApiBase { 'AutoBlock' => $params['autoblock'], 'DisableEmail' => $params['noemail'], 'HideUser' => $params['hidename'], - 'DisableUTEdit' => $params['allowusertalk'], + 'DisableUTEdit' => !$params['allowusertalk'], 'AlreadyBlocked' => $params['reblock'], 'Watch' => $params['watchuser'], 'Confirm' => true, ); - $retval = SpecialBlock::processForm( $data ); + $retval = SpecialBlock::processForm( $data, $this->getContext() ); if ( $retval !== true ) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg( $retval ); @@ -208,7 +203,7 @@ class ApiBlock extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=block&user=123.5.5.12&expiry=3%20days&reason=First%20strike', 'api.php?action=block&user=Vandal&expiry=never&reason=Vandalism&nocreate=&autoblock=&noemail=' diff --git a/includes/api/ApiComparePages.php b/includes/api/ApiComparePages.php index 59f8555b..4bb94c4a 100644 --- a/includes/api/ApiComparePages.php +++ b/includes/api/ApiComparePages.php @@ -35,7 +35,7 @@ class ApiComparePages extends ApiBase { $rev1 = $this->revisionOrTitle( $params['fromrev'], $params['fromtitle'] ); $rev2 = $this->revisionOrTitle( $params['torev'], $params['totitle'] ); - $de = new DifferenceEngine( null, + $de = new DifferenceEngine( $this->getContext(), $rev1, $rev2, null, // rcid @@ -118,9 +118,9 @@ class ApiComparePages extends ApiBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'api.php?action=compare&fromrev=1&torev=2', + 'api.php?action=compare&fromrev=1&torev=2' => 'Create a diff between revision 1 and 2', ); } diff --git a/includes/api/ApiDelete.php b/includes/api/ApiDelete.php index d6cc21b3..cfaf6cc1 100644 --- a/includes/api/ApiDelete.php +++ b/includes/api/ApiDelete.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API module that facilitates deleting pages. The API equivalent of action=delete. * Requires API write mode to be enabled. @@ -69,67 +64,56 @@ class ApiDelete extends ApiBase { } $reason = ( isset( $params['reason'] ) ? $params['reason'] : null ); + $pageObj = WikiPage::factory( $titleObj ); + $user = $this->getUser(); + if ( $titleObj->getNamespace() == NS_FILE ) { - $retval = self::deleteFile( $params['token'], $titleObj, $params['oldimage'], $reason, false ); - if ( count( $retval ) ) { - $this->dieUsageMsg( reset( $retval ) ); // We don't care about multiple errors, just report one of them - } + $retval = self::deleteFile( $pageObj, $user, $params['token'], $params['oldimage'], $reason, false ); } else { - $articleObj = new Article( $titleObj ); - $retval = self::delete( $articleObj, $params['token'], $reason ); + $retval = self::delete( $pageObj, $user, $params['token'], $reason ); + } - if ( count( $retval ) ) { - $this->dieUsageMsg( reset( $retval ) ); // We don't care about multiple errors, just report one of them - } + if ( count( $retval ) ) { + $this->dieUsageMsg( reset( $retval ) ); // We don't care about multiple errors, just report one of them + } - // Deprecated parameters - if ( $params['watch'] ) { - $watch = 'watch'; - } elseif ( $params['unwatch'] ) { - $watch = 'unwatch'; - } else { - $watch = $params['watchlist']; - } - $this->setWatch( $watch, $titleObj, 'watchdeletion' ); + // Deprecated parameters + if ( $params['watch'] ) { + $watch = 'watch'; + } elseif ( $params['unwatch'] ) { + $watch = 'unwatch'; + } else { + $watch = $params['watchlist']; } + $this->setWatch( $watch, $titleObj, 'watchdeletion' ); $r = array( 'title' => $titleObj->getPrefixedText(), 'reason' => $reason ); $this->getResult()->addValue( null, $this->getModuleName(), $r ); } /** - * - * @param &$title Title + * @param $title Title + * @param $user User doing the action * @param $token String + * @return array */ - private static function getPermissionsError( &$title, $token ) { - global $wgUser; - + private static function getPermissionsError( $title, $user, $token ) { // Check permissions - $errors = $title->getUserPermissionsErrors( 'delete', $wgUser ); - if ( count( $errors ) > 0 ) { - return $errors; - } - - return array(); + return $title->getUserPermissionsErrors( 'delete', $user ); } /** * We have our own delete() function, since Article.php's implementation is split in two phases * - * @param $article Article object to work on + * @param $page WikiPage object to work on + * @param $user User doing the action * @param $token String: delete token (same as edit token) * @param $reason String: reason for the deletion. Autogenerated if NULL * @return Title::getUserPermissionsErrors()-like array */ - public static function delete( &$article, $token, &$reason = null ) { - global $wgUser; - if ( $article->isBigDeletion() && !$wgUser->isAllowed( 'bigdelete' ) ) { - global $wgDeleteRevisionsLimit; - return array( array( 'delete-toobig', $wgDeleteRevisionsLimit ) ); - } - $title = $article->getTitle(); - $errors = self::getPermissionsError( $title, $token ); + public static function delete( Page $page, User $user, $token, &$reason = null ) { + $title = $page->getTitle(); + $errors = self::getPermissionsError( $title, $user, $token ); if ( count( $errors ) ) { return $errors; } @@ -139,54 +123,58 @@ class ApiDelete extends ApiBase { // Need to pass a throwaway variable because generateReason expects // a reference $hasHistory = false; - $reason = $article->generateReason( $hasHistory ); + $reason = $page->getAutoDeleteReason( $hasHistory ); if ( $reason === false ) { - return array( array( 'cannotdelete' ) ); + return array( array( 'cannotdelete', $title->getPrefixedText() ) ); } } $error = ''; // Luckily, Article.php provides a reusable delete function that does the hard work for us - if ( $article->doDeleteArticle( $reason, false, 0, true, $error ) ) { + if ( $page->doDeleteArticle( $reason, false, 0, true, $error ) ) { return array(); } else { - return array( array( 'cannotdelete', $article->getTitle()->getPrefixedText() ) ); + return array( array( 'cannotdelete', $title->getPrefixedText() ) ); } } /** + * @param $page WikiPage object to work on + * @param $user User doing the action * @param $token - * @param $title Title * @param $oldimage * @param $reason * @param $suppress bool * @return \type|array|Title */ - public static function deleteFile( $token, &$title, $oldimage, &$reason = null, $suppress = false ) { - $errors = self::getPermissionsError( $title, $token ); + public static function deleteFile( Page $page, User $user, $token, $oldimage, &$reason = null, $suppress = false ) { + $title = $page->getTitle(); + $errors = self::getPermissionsError( $title, $user, $token ); if ( count( $errors ) ) { return $errors; } - if ( $oldimage && !FileDeleteForm::isValidOldSpec( $oldimage ) ) { - return array( array( 'invalidoldimage' ) ); + $file = $page->getFile(); + if ( !$file->exists() || !$file->isLocal() || $file->getRedirected() ) { + return self::delete( $page, $user, $token, $reason ); } - $file = wfFindFile( $title, array( 'ignoreRedirect' => true ) ); - $oldfile = false; - if ( $oldimage ) { + if ( !FileDeleteForm::isValidOldSpec( $oldimage ) ) { + return array( array( 'invalidoldimage' ) ); + } $oldfile = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $title, $oldimage ); + if ( !$oldfile->exists() || !$oldfile->isLocal() || $oldfile->getRedirected() ) { + return array( array( 'nodeleteablefile' ) ); + } + } else { + $oldfile = false; } - if ( !FileDeleteForm::haveDeletableFile( $file, $oldfile, $oldimage ) ) { - return self::delete( new Article( $title ), $token, $reason ); - } if ( is_null( $reason ) ) { // Log and RC don't like null reasons $reason = ''; } $status = FileDeleteForm::doDelete( $title, $file, $oldimage, $reason, $suppress ); - if ( !$status->isGood() ) { return array( array( 'cannotdelete', $title->getPrefixedText() ) ); } @@ -257,6 +245,10 @@ class ApiDelete extends ApiBase { array( 'nosuchpageid', 'pageid' ), array( 'notanarticle' ), array( 'hookaborted', 'error' ), + array( 'delete-toobig', 'limit' ), + array( 'cannotdelete', 'title' ), + array( 'invalidoldimage' ), + array( 'nodeleteablefile' ), ) ); } @@ -269,10 +261,10 @@ class ApiDelete extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( - 'api.php?action=delete&title=Main%20Page&token=123ABC', - 'api.php?action=delete&title=Main%20Page&token=123ABC&reason=Preparing%20for%20move' + 'api.php?action=delete&title=Main%20Page&token=123ABC' => 'Delete the Main Page', + 'api.php?action=delete&title=Main%20Page&token=123ABC&reason=Preparing%20for%20move' => 'Delete the Main Page with the reason "Preparing for move"', ); } diff --git a/includes/api/ApiDisabled.php b/includes/api/ApiDisabled.php index ad731bb4..55754896 100644 --- a/includes/api/ApiDisabled.php +++ b/includes/api/ApiDisabled.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API module that dies with an error immediately. * @@ -46,7 +41,7 @@ class ApiDisabled extends ApiBase { } public function execute() { - $this->dieUsage( "The ``{$this->getModuleName()}'' module has been disabled.", 'moduledisabled' ); + $this->dieUsage( "The \"{$this->getModuleName()}\" module has been disabled.", 'moduledisabled' ); } public function isReadMode() { @@ -65,7 +60,7 @@ class ApiDisabled extends ApiBase { return 'This module has been disabled'; } - protected function getExamples() { + public function getExamples() { return array(); } diff --git a/includes/api/ApiEditPage.php b/includes/api/ApiEditPage.php index 2b949ba9..9ed6d08d 100644 --- a/includes/api/ApiEditPage.php +++ b/includes/api/ApiEditPage.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * A module that allows for editing and creating pages. * @@ -43,7 +38,7 @@ class ApiEditPage extends ApiBase { } public function execute() { - global $wgUser; + $user = $this->getUser(); $params = $this->extractRequestParams(); if ( is_null( $params['text'] ) && is_null( $params['appendtext'] ) && @@ -87,10 +82,6 @@ class ApiEditPage extends ApiBase { } } - // Some functions depend on $wgTitle == $ep->mTitle - global $wgTitle; - $wgTitle = $titleObj; - if ( $params['createonly'] && $titleObj->exists() ) { $this->dieUsageMsg( 'createonly-exists' ); } @@ -99,15 +90,16 @@ class ApiEditPage extends ApiBase { } // Now let's check whether we're even allowed to do this - $errors = $titleObj->getUserPermissionsErrors( 'edit', $wgUser ); + $errors = $titleObj->getUserPermissionsErrors( 'edit', $user ); if ( !$titleObj->exists() ) { - $errors = array_merge( $errors, $titleObj->getUserPermissionsErrors( 'create', $wgUser ) ); + $errors = array_merge( $errors, $titleObj->getUserPermissionsErrors( 'create', $user ) ); } if ( count( $errors ) ) { $this->dieUsageMsg( $errors[0] ); } - $articleObj = new Article( $titleObj ); + $articleObj = Article::newFromTitle( $titleObj, $this->getContext() ); + $toMD5 = $params['text']; if ( !is_null( $params['appendtext'] ) || !is_null( $params['prependtext'] ) ) { @@ -178,41 +170,42 @@ class ApiEditPage extends ApiBase { $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( + $requestArray = array( 'wpTextbox1' => $params['text'], 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '' ); if ( !is_null( $params['summary'] ) ) { - $reqArr['wpSummary'] = $params['summary']; + $requestArray['wpSummary'] = $params['summary']; + } + + if ( !is_null( $params['sectiontitle'] ) ) { + $requestArray['wpSectionTitle'] = $params['sectiontitle']; } // Watch out for basetimestamp == '' // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) { - $reqArr['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] ); + $requestArray['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] ); } else { - $reqArr['wpEdittime'] = $articleObj->getTimestamp(); + $requestArray['wpEdittime'] = $articleObj->getTimestamp(); } if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) { - $reqArr['wpStarttime'] = wfTimestamp( TS_MW, $params['starttimestamp'] ); + $requestArray['wpStarttime'] = wfTimestamp( TS_MW, $params['starttimestamp'] ); } else { - $reqArr['wpStarttime'] = wfTimestampNow(); // Fake wpStartime + $requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime } - if ( $params['minor'] || ( !$params['notminor'] && $wgUser->getOption( 'minordefault' ) ) ) { - $reqArr['wpMinoredit'] = ''; + if ( $params['minor'] || ( !$params['notminor'] && $user->getOption( 'minordefault' ) ) ) { + $requestArray['wpMinoredit'] = ''; } if ( $params['recreate'] ) { - $reqArr['wpRecreate'] = ''; + $requestArray['wpRecreate'] = ''; } if ( !is_null( $params['section'] ) ) { @@ -220,9 +213,9 @@ class ApiEditPage extends ApiBase { if ( $section == 0 && $params['section'] != '0' && $params['section'] != 'new' ) { $this->dieUsage( "The section parameter must be set to an integer or 'new'", "invalidsection" ); } - $reqArr['wpSection'] = $params['section']; + $requestArray['wpSection'] = $params['section']; } else { - $reqArr['wpSection'] = ''; + $requestArray['wpSection'] = ''; } $watch = $this->getWatchlistValue( $params['watchlist'], $titleObj ); @@ -235,22 +228,23 @@ class ApiEditPage extends ApiBase { } if ( $watch ) { - $reqArr['wpWatchthis'] = ''; + $requestArray['wpWatchthis'] = ''; } - $req = new FauxRequest( $reqArr, true ); + global $wgTitle, $wgRequest; + + $req = new DerivativeRequest( $this->getRequest(), $requestArray, true ); + + // Some functions depend on $wgTitle == $ep->mTitle + // TODO: Make them not or check if they still do + $wgTitle = $titleObj; + + $ep = new EditPage( $articleObj ); + $ep->setContextTitle( $titleObj ); $ep->importFormData( $req ); // Run hooks - // Handle CAPTCHA parameters - global $wgRequest; - if ( !is_null( $params['captchaid'] ) ) { - $wgRequest->setVal( 'wpCaptchaId', $params['captchaid'] ); - } - if ( !is_null( $params['captchaword'] ) ) { - $wgRequest->setVal( 'wpCaptchaWord', $params['captchaword'] ); - } - + // Handle APIEditBeforeSave parameters $r = array(); if ( !wfRunHooks( 'APIEditBeforeSave', array( $ep, $ep->textbox1, &$r ) ) ) { if ( count( $r ) ) { @@ -270,7 +264,7 @@ class ApiEditPage extends ApiBase { $oldRequest = $wgRequest; $wgRequest = $req; - $status = $ep->internalAttemptSave( $result, $wgUser->isAllowed( 'bot' ) && $params['bot'] ); + $status = $ep->internalAttemptSave( $result, $user->isAllowed( 'bot' ) && $params['bot'] ); $wgRequest = $oldRequest; global $wgMaxArticleSize; @@ -333,19 +327,14 @@ class ApiEditPage extends ApiBase { $r['result'] = 'Success'; $r['pageid'] = intval( $titleObj->getArticleID() ); $r['title'] = $titleObj->getPrefixedText(); - // HACK: We create a new Article object here because getRevIdFetched() - // refuses to be run twice, and because Title::getLatestRevId() - // won't fetch from the master unless we select for update, which we - // don't want to do. - $newArticle = new Article( $titleObj ); - $newRevId = $newArticle->getRevIdFetched(); + $newRevId = $articleObj->getLatest(); if ( $newRevId == $oldRevId ) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval( $oldRevId ); $r['newrevid'] = intval( $newRevId ); $r['newtimestamp'] = wfTimestamp( TS_ISO_8601, - $newArticle->getTimestamp() ); + $articleObj->getTimestamp() ); } break; @@ -358,7 +347,11 @@ class ApiEditPage extends ApiBase { $this->dieUsageMsg( $errors[0] ); // TODO: Add new errors to message map break; default: - $this->dieUsageMsg( array( 'unknownerror', $status->value ) ); + if ( is_string( $status->value ) && strlen( $status->value ) ) { + $this->dieUsage( "An unknown return value was returned by Editpage. The code returned was \"{$status->value}\"" , $status->value ); + } else { + $this->dieUsageMsg( array( 'unknownerror', $status->value ) ); + } } $apiResult->addValue( null, $this->getModuleName(), $r ); } @@ -371,7 +364,7 @@ class ApiEditPage extends ApiBase { return true; } - protected function getDescription() { + public function getDescription() { return 'Create and edit pages.'; } @@ -412,13 +405,17 @@ class ApiEditPage extends ApiBase { ) ); } - protected function getAllowedParams() { + public function getAllowedParams() { return array( 'title' => array( ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true ), 'section' => null, + 'sectiontitle' => array( + ApiBase::PARAM_TYPE => 'string', + ApiBase::PARAM_REQUIRED => false, + ), 'text' => null, 'token' => null, 'summary' => null, @@ -430,8 +427,6 @@ class ApiEditPage extends ApiBase { 'recreate' => false, 'createonly' => false, 'nocreate' => false, - 'captchaword' => null, - 'captchaid' => null, 'watch' => array( ApiBase::PARAM_DFLT => false, ApiBase::PARAM_DEPRECATED => true, @@ -465,11 +460,12 @@ class ApiEditPage extends ApiBase { ); } - protected function getParamDescription() { + public function getParamDescription() { $p = $this->getModulePrefix(); return array( 'title' => 'Page title', 'section' => 'Section number. 0 for the top section, \'new\' for a new section', + 'sectiontitle' => 'The title for a new section', 'text' => 'Page content', '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' @@ -490,10 +486,8 @@ class ApiEditPage extends ApiBase { 'watch' => 'Add the page to your watchlist', 'unwatch' => 'Remove the page from your watchlist', 'watchlist' => 'Unconditionally add or remove the page from your watchlist, use preferences or do not change watch', - 'captchaid' => 'CAPTCHA ID from previous request', - 'captchaword' => 'Answer to the CAPTCHA', 'md5' => array( "The MD5 hash of the {$p}text parameter, or the {$p}prependtext and {$p}appendtext parameters concatenated.", - 'If set, the edit won\'t be done unless the hash is correct' ), + 'If set, the edit won\'t be done unless the hash is correct' ), 'prependtext' => "Add this text to the beginning of the page. Overrides {$p}text", 'appendtext' => "Add this text to the end of the page. Overrides {$p}text", 'undo' => "Undo this revision. Overrides {$p}text, {$p}prependtext and {$p}appendtext", @@ -510,14 +504,16 @@ class ApiEditPage extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( - 'Edit a page (anonymous user):', - ' api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\', - 'Prepend __NOTOC__ to a page (anonymous user):', - ' api.php?action=edit&title=Test&summary=NOTOC&minor=&prependtext=__NOTOC__%0A&basetimestamp=20070824123454&token=%2B\\', - 'Undo r13579 through r13585 with autosummary (anonymous user):', - ' api.php?action=edit&title=Test&undo=13585&undoafter=13579&basetimestamp=20070824123454&token=%2B\\', + + 'api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\' + => 'Edit a page (anonymous user)', + + 'api.php?action=edit&title=Test&summary=NOTOC&minor=&prependtext=__NOTOC__%0A&basetimestamp=20070824123454&token=%2B\\' + => 'Prepend __NOTOC__ to a page (anonymous user)', + 'api.php?action=edit&title=Test&undo=13585&undoafter=13579&basetimestamp=20070824123454&token=%2B\\' + => 'Undo r13579 through r13585 with autosummary (anonymous user)', ); } diff --git a/includes/api/ApiEmailUser.php b/includes/api/ApiEmailUser.php index 46e8d523..d9eed60c 100644 --- a/includes/api/ApiEmailUser.php +++ b/includes/api/ApiEmailUser.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API Module to facilitate sending of emails to users * @ingroup API @@ -40,8 +35,6 @@ class ApiEmailUser extends ApiBase { } public function execute() { - global $wgUser; - $params = $this->extractRequestParams(); // Validate target @@ -51,7 +44,7 @@ class ApiEmailUser extends ApiBase { } // Check permissions and errors - $error = SpecialEmailUser::getPermissionsError( $wgUser, $params['token'] ); + $error = SpecialEmailUser::getPermissionsError( $this->getUser(), $params['token'] ); if ( $error ) { $this->dieUsageMsg( array( $error ) ); } @@ -138,9 +131,9 @@ class ApiEmailUser extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( - 'api.php?action=emailuser&target=WikiSysop&text=Content' + 'api.php?action=emailuser&target=WikiSysop&text=Content' => 'Send an email to the User "WikiSysop" with the text "Content"', ); } diff --git a/includes/api/ApiExpandTemplates.php b/includes/api/ApiExpandTemplates.php index dfa520a2..d570534d 100644 --- a/includes/api/ApiExpandTemplates.php +++ b/includes/api/ApiExpandTemplates.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API module that functions as a shortcut to the wikitext preprocessor. Expands * any templates in a provided string, and returns the result of this expansion @@ -52,14 +47,14 @@ class ApiExpandTemplates extends ApiBase { // Create title for parser $title_obj = Title::newFromText( $params['title'] ); if ( !$title_obj ) { - $title_obj = Title::newFromText( 'API' ); // default + $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) ); } $result = $this->getResult(); // Parse text global $wgParser; - $options = new ParserOptions(); + $options = ParserOptions::newFromContext( $this->getContext() ); if ( $params['includecomments'] ) { $options->setRemoveComments( false ); @@ -112,7 +107,13 @@ class ApiExpandTemplates extends ApiBase { return 'Expands all templates in wikitext'; } - protected function getExamples() { + public function getPossibleErrors() { + return array_merge( parent::getPossibleErrors(), array( + array( 'invalidtitle', 'title' ), + ) ); + } + + public function getExamples() { return array( 'api.php?action=expandtemplates&text={{Project:Sandbox}}' ); diff --git a/includes/api/ApiFeedContributions.php b/includes/api/ApiFeedContributions.php index c1e6ff6e..4e70bde2 100644 --- a/includes/api/ApiFeedContributions.php +++ b/includes/api/ApiFeedContributions.php @@ -1,5 +1,4 @@ getMain() ); @@ -73,7 +74,7 @@ class ApiFeedContributions extends ApiBase { $feedUrl ); - $pager = new ContribsPager( array( + $pager = new ContribsPager( $this->getContext(), array( 'target' => $target, 'namespace' => $params['namespace'], 'year' => $params['year'], @@ -99,7 +100,7 @@ class ApiFeedContributions extends ApiBase { if( $title ) { $date = $row->rev_timestamp; $comments = $title->getTalkPage()->getFullURL(); - $revision = Revision::newFromRow( $row); + $revision = Revision::newFromRow( $row ); return new FeedItem( $title->getPrefixedText(), @@ -195,7 +196,7 @@ class ApiFeedContributions extends ApiBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=feedcontributions&user=Reedy', ); @@ -204,4 +205,4 @@ class ApiFeedContributions extends ApiBase { public function getVersion() { return __CLASS__ . ': $Id$'; } -} \ No newline at end of file +} diff --git a/includes/api/ApiFeedWatchlist.php b/includes/api/ApiFeedWatchlist.php index dd7e3d8f..eee8fa19 100644 --- a/includes/api/ApiFeedWatchlist.php +++ b/includes/api/ApiFeedWatchlist.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * This action allows users to get their watchlist items in RSS/Atom formats. * When executed, it performs a nested call to the API to get the needed data, @@ -44,6 +39,8 @@ class ApiFeedWatchlist extends ApiBase { /** * This module uses a custom feed wrapper printer. + * + * @return ApiFormatFeedWrapper */ public function getCustomPrinter() { return new ApiFormatFeedWrapper( $this->getMain() ); @@ -68,6 +65,9 @@ class ApiFeedWatchlist extends ApiBase { if( !isset( $wgFeedClasses[ $params['feedformat'] ] ) ) { $this->dieUsage( 'Invalid subscription feed type', 'feed-invalid' ); } + if ( !is_null( $params['wlexcludeuser'] ) ) { + $fauxReqArr['wlexcludeuser'] = $params['wlexcludeuser']; + } // limit to the number of hours going from now back $endTime = wfTimestamp( TS_MW, time() - intval( $params['hours'] * 60 * 60 ) ); @@ -150,6 +150,10 @@ class ApiFeedWatchlist extends ApiBase { } } + /** + * @param $info array + * @return FeedItem + */ private function createFeedItem( $info ) { $titleStr = $info['title']; $title = Title::newFromText( $titleStr ); @@ -188,6 +192,9 @@ class ApiFeedWatchlist extends ApiBase { 'wltoken' => array( ApiBase::PARAM_TYPE => 'string' ), + 'wlexcludeuser' => array( + ApiBase::PARAM_TYPE => 'user' + ), 'linktodiffs' => false, ); } @@ -197,9 +204,10 @@ class ApiFeedWatchlist extends ApiBase { 'feedformat' => 'The format of the feed', 'hours' => 'List pages modified within this many hours from now', '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)", + 'wlowner' => "The user whose watchlist you want (must be accompanied by {$this->getModulePrefix()}wltoken if it's not you)", 'wltoken' => 'Security token that requested user set in their preferences', - 'linktodiffs' => 'Link to change differences instead of article pages' + 'wlexcludeuser' => 'A user whose edits should not be shown in the watchlist', + 'linktodiffs' => 'Link to change differences instead of article pages', ); } @@ -214,7 +222,7 @@ class ApiFeedWatchlist extends ApiBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=feedwatchlist', 'api.php?action=feedwatchlist&allrev=&linktodiffs=&hours=6' diff --git a/includes/api/ApiFileRevert.php b/includes/api/ApiFileRevert.php index 5ff50512..7ef1da0a 100644 --- a/includes/api/ApiFileRevert.php +++ b/includes/api/ApiFileRevert.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -47,14 +42,12 @@ class ApiFileRevert extends ApiBase { } 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 ); + $this->checkPermissions( $this->getUser() ); $sourceUrl = $this->file->getArchiveVirtualUrl( $this->archiveName ); $status = $this->file->upload( $sourceUrl, $this->params['comment'], $this->params['comment'] ); @@ -176,10 +169,10 @@ class ApiFileRevert extends ApiBase { return ''; } - protected function getExamples() { + public 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=+\\', + 'api.php?action=filerevert&filename=Wiki.png&comment=Revert&archivename=20110305152740!Wiki.png&token=+\\' + => 'Revert Wiki.png to the version of 20110305152740', ); } diff --git a/includes/api/ApiFormatBase.php b/includes/api/ApiFormatBase.php index 8c8235b8..543c90ce 100644 --- a/includes/api/ApiFormatBase.php +++ b/includes/api/ApiFormatBase.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * This is the abstract base class for API formatters. * @@ -235,8 +230,10 @@ See complete documentation, or public function getBuffer() { return $this->mBuffer; } + /** * Set the flag to buffer the result instead of printing it. + * @param $value bool */ public function setBufferResult( $value ) { $this->mBufferResult = $value; @@ -267,7 +264,7 @@ See complete documentation, or // This regex hacks around bug 13218 (" included in the URL) $text = preg_replace( "#(($protos).*?)(")?([ \\'\"<>\n]|<|>|")#", '\\1\\3\\4', $text ); // identify requests to api.php - $text = preg_replace( "#api\\.php\\?[^ \\()<\n\t]+#", '\\0', $text ); + $text = preg_replace( "#api\\.php\\?[^ <\n\t]+#", '\\0', $text ); if ( $this->mHelp ) { // make strings inside * bold $text = preg_replace( "#\\*[^<>\n]+\\*#", '\\0', $text ); @@ -288,8 +285,11 @@ See complete documentation, or return $text; } - protected function getExamples() { - return 'api.php?action=query&meta=siteinfo&siprop=namespaces&format=' . $this->getModuleName(); + public function getExamples() { + return array( + 'api.php?action=query&meta=siteinfo&siprop=namespaces&format=' . $this->getModuleName() + => "Format the query result in the {$this->getModuleName()} format", + ); } public function getHelpUrls() { @@ -335,6 +335,8 @@ class ApiFormatFeedWrapper extends ApiFormatBase { /** * Feed does its own headers + * + * @return null */ public function getMimeType() { return null; @@ -342,6 +344,8 @@ class ApiFormatFeedWrapper extends ApiFormatBase { /** * Optimization - no need to sanitize data that will not be needed + * + * @return bool */ public function getNeedsRawData() { return true; diff --git a/includes/api/ApiFormatDbg.php b/includes/api/ApiFormatDbg.php index 32f223d7..92619f76 100644 --- a/includes/api/ApiFormatDbg.php +++ b/includes/api/ApiFormatDbg.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API PHP's var_export() output formatter * @ingroup API diff --git a/includes/api/ApiFormatDump.php b/includes/api/ApiFormatDump.php index bde3e56d..0f055e13 100644 --- a/includes/api/ApiFormatDump.php +++ b/includes/api/ApiFormatDump.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API PHP's var_dump() output formatter * @ingroup API diff --git a/includes/api/ApiFormatJson.php b/includes/api/ApiFormatJson.php index e3755d73..e728d057 100644 --- a/includes/api/ApiFormatJson.php +++ b/includes/api/ApiFormatJson.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API JSON output formatter * @ingroup API diff --git a/includes/api/ApiFormatPhp.php b/includes/api/ApiFormatPhp.php index cfcc2a03..60552c40 100644 --- a/includes/api/ApiFormatPhp.php +++ b/includes/api/ApiFormatPhp.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API Serialized PHP output formatter * @ingroup API diff --git a/includes/api/ApiFormatRaw.php b/includes/api/ApiFormatRaw.php index 75912871..db81aacd 100644 --- a/includes/api/ApiFormatRaw.php +++ b/includes/api/ApiFormatRaw.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * Formatter that spits out anything you like with any desired MIME type * @ingroup API diff --git a/includes/api/ApiFormatTxt.php b/includes/api/ApiFormatTxt.php index 54a620fc..e26b82b0 100644 --- a/includes/api/ApiFormatTxt.php +++ b/includes/api/ApiFormatTxt.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API Text output formatter * @ingroup API diff --git a/includes/api/ApiFormatWddx.php b/includes/api/ApiFormatWddx.php index f5cace21..1bc9d025 100644 --- a/includes/api/ApiFormatWddx.php +++ b/includes/api/ApiFormatWddx.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API WDDX output formatter * @ingroup API @@ -69,6 +64,8 @@ class ApiFormatWddx extends ApiFormatBase { /** * Recursively go through the object and output its data in WDDX format. + * @param $elemValue + * @param $indent int */ function slowWddxPrinter( $elemValue, $indent = 0 ) { $indstr = ( $this->getIsHtml() ? '' : str_repeat( ' ', $indent ) ); diff --git a/includes/api/ApiFormatXml.php b/includes/api/ApiFormatXml.php index 06bd9f33..8f4abc15 100644 --- a/includes/api/ApiFormatXml.php +++ b/includes/api/ApiFormatXml.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API XML output formatter * @ingroup API @@ -68,11 +63,15 @@ class ApiFormatXml extends ApiFormatBase { $this->addXslt(); } if ( $this->mIncludeNamespace ) { - $data = array( 'xmlns' => self::$namespace ) + $this->getResultData(); + // If the result data already contains an 'xmlns' namespace added + // for custom XML output types, it will override the one for the + // generic API results. + // This allows API output of other XML types like Atom, RSS, RSD. + $data = $this->getResultData() + array( 'xmlns' => self::$namespace ); } else { $data = $this->getResultData(); } - + $this->printText( self::recXmlPrint( $this->mRootElemName, $data, @@ -94,7 +93,7 @@ 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 @@ -202,7 +201,7 @@ class ApiFormatXml extends ApiFormatBase { $this->setWarning( 'Stylesheet should have .xsl extension.' ); return; } - $this->printText( 'escapeLocalURL( 'action=raw' ) . '" type="text/xsl" ?>' ); + $this->printText( 'getLocalURL( 'action=raw' ) ) . '" type="text/xsl" ?>' ); } public function getAllowedParams() { diff --git a/includes/api/ApiFormatYaml.php b/includes/api/ApiFormatYaml.php index ecf35900..dbcdb21c 100644 --- a/includes/api/ApiFormatYaml.php +++ b/includes/api/ApiFormatYaml.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiFormatBase.php' ); -} - /** * API YAML output formatter * @ingroup API diff --git a/includes/api/ApiHelp.php b/includes/api/ApiHelp.php index f2af822a..97da786b 100644 --- a/includes/api/ApiHelp.php +++ b/includes/api/ApiHelp.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * This is a simple class to handle action=help * @@ -139,18 +134,13 @@ class ApiHelp extends ApiBase { return 'Display this help screen. Or the help screen for the specified module'; } - protected function getExamples() { + public function getExamples() { return array( - 'Whole help page:', - ' api.php?action=help', - 'Module (action) help page:', - ' api.php?action=help&modules=protect', - 'Query (list) modules help page:', - ' api.php?action=help&querymodules=categorymembers', - 'Query (prop) modules help page:', - ' api.php?action=help&querymodules=info', - 'Query (meta) modules help page:', - ' api.php?action=help&querymodules=siteinfo', + 'api.php?action=help' => 'Whole help page', + 'api.php?action=help&modules=protect' => 'Module (action) help page', + 'api.php?action=help&querymodules=categorymembers' => 'Query (list) modules help page', + 'api.php?action=help&querymodules=info' => 'Query (prop) modules help page', + 'api.php?action=help&querymodules=siteinfo' => 'Query (meta) modules help page', ); } diff --git a/includes/api/ApiImport.php b/includes/api/ApiImport.php index ce740efc..ade9f1f3 100644 --- a/includes/api/ApiImport.php +++ b/includes/api/ApiImport.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * API module that imports an XML file like Special:Import does * @@ -41,13 +36,12 @@ class ApiImport extends ApiBase { } public function execute() { - global $wgUser; - + $user = $this->getUser(); $params = $this->extractRequestParams(); $isUpload = false; if ( isset( $params['interwikisource'] ) ) { - if ( !$wgUser->isAllowed( 'import' ) ) { + if ( !$user->isAllowed( 'import' ) ) { $this->dieUsageMsg( 'cantimport' ); } if ( !isset( $params['interwikipage'] ) ) { @@ -61,7 +55,7 @@ class ApiImport extends ApiBase { ); } else { $isUpload = true; - if ( !$wgUser->isAllowed( 'importupload' ) ) { + if ( !$user->isAllowed( 'importupload' ) ) { $this->dieUsageMsg( 'cantimport-upload' ); } $source = ImportStreamSource::newFromUpload( 'xml' ); @@ -158,10 +152,10 @@ class ApiImport extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( - 'Import [[meta:Help:Parserfunctions]] to namespace 100 with full history:', - ' api.php?action=import&interwikisource=meta&interwikipage=Help:ParserFunctions&namespace=100&fullhistory=&token=123ABC', + 'api.php?action=import&interwikisource=meta&interwikipage=Help:ParserFunctions&namespace=100&fullhistory=&token=123ABC' + => 'Import [[meta:Help:Parserfunctions]] to namespace 100 with full history', ); } diff --git a/includes/api/ApiLogin.php b/includes/api/ApiLogin.php index 1b17e43b..aa570cbc 100644 --- a/includes/api/ApiLogin.php +++ b/includes/api/ApiLogin.php @@ -25,11 +25,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * Unit to authenticate log-in attempts to the current wiki. * @@ -55,39 +50,45 @@ class ApiLogin extends ApiBase { $result = array(); - $req = new FauxRequest( array( - 'wpName' => $params['name'], - 'wpPassword' => $params['password'], - 'wpDomain' => $params['domain'], - 'wpLoginToken' => $params['token'], - 'wpRemember' => '' - ) ); - // Init session if necessary if ( session_id() == '' ) { wfSetupSession(); } - $loginForm = new LoginForm( $req ); + $context = new DerivativeContext( $this->getContext() ); + $context->setRequest( new DerivativeRequest( + $this->getContext()->getRequest(), + array( + 'wpName' => $params['name'], + 'wpPassword' => $params['password'], + 'wpDomain' => $params['domain'], + 'wpLoginToken' => $params['token'], + 'wpRemember' => '' + ) + ) ); + $loginForm = new LoginForm(); + $loginForm->setContext( $context ); - global $wgCookiePrefix, $wgUser, $wgPasswordAttemptThrottle; + global $wgCookiePrefix, $wgPasswordAttemptThrottle; $authRes = $loginForm->authenticateUserData(); switch ( $authRes ) { case LoginForm::SUCCESS: - $wgUser->setOption( 'rememberpassword', 1 ); - $wgUser->setCookies( $this->getMain()->getRequest() ); + $user = $context->getUser(); + $this->getContext()->setUser( $user ); + $user->setOption( 'rememberpassword', 1 ); + $user->setCookies( $this->getRequest() ); // 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 ) ); + wfRunHooks( 'UserLoginComplete', array( &$user, &$injected_html ) ); $result['result'] = 'Success'; - $result['lguserid'] = intval( $wgUser->getId() ); - $result['lgusername'] = $wgUser->getName(); - $result['lgtoken'] = $wgUser->getToken(); + $result['lguserid'] = intval( $user->getId() ); + $result['lgusername'] = $user->getName(); + $result['lgtoken'] = $user->getToken(); $result['cookieprefix'] = $wgCookiePrefix; $result['sessionid'] = session_id(); break; @@ -199,14 +200,14 @@ class ApiLogin extends ApiBase { array( 'code' => 'NotExists', 'info' => ' The username you provided doesn\'t exist' ), array( 'code' => 'EmptyPass', 'info' => ' You didn\'t set the lgpassword parameter or you left it empty' ), array( 'code' => 'WrongPass', 'info' => ' The password you provided is incorrect' ), - array( 'code' => 'WrongPluginPass', 'info' => 'Same as `WrongPass", returned when an authentication plugin rather than MediaWiki itself rejected the password' ), + array( 'code' => 'WrongPluginPass', 'info' => 'Same as "WrongPass", returned when an authentication plugin rather than MediaWiki itself rejected the password' ), array( 'code' => 'CreateBlocked', 'info' => 'The wiki tried to automatically create a new account for you, but your IP address has been blocked from account creation' ), array( 'code' => 'Throttled', 'info' => 'You\'ve logged in too many times in a short time' ), array( 'code' => 'Blocked', 'info' => 'User is blocked' ), ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=login&lgname=user&lgpassword=password' ); diff --git a/includes/api/ApiLogout.php b/includes/api/ApiLogout.php index b5dd7ac9..81a054a6 100644 --- a/includes/api/ApiLogout.php +++ b/includes/api/ApiLogout.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * API module to allow users to log out of the wiki. API equivalent of * Special:Userlogout. @@ -42,13 +37,13 @@ class ApiLogout extends ApiBase { } public function execute() { - global $wgUser; - $oldName = $wgUser->getName(); - $wgUser->logout(); + $user = $this->getUser(); + $oldName = $user->getName(); + $user->logout(); // Give extensions to do something after user logout $injected_html = ''; - wfRunHooks( 'UserLogoutComplete', array( &$wgUser, &$injected_html, $oldName ) ); + wfRunHooks( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) ); } public function isReadMode() { @@ -67,9 +62,9 @@ class ApiLogout extends ApiBase { return 'Log out and clear session data'; } - protected function getExamples() { + public function getExamples() { return array( - 'api.php?action=logout' + 'api.php?action=logout' => 'Log the current user out', ); } diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index b7e118cf..fa95cfca 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -25,11 +25,6 @@ * @defgroup API API */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * This is the main API class, used for both external and internal processing. * When executed, it will create the requested formatter object, @@ -132,7 +127,7 @@ class ApiMain extends ApiBase { private $mPrinter; private $mModules, $mModuleNames, $mFormats, $mFormatNames; - private $mResult, $mAction, $mShowVersions, $mEnableWrite, $mRequest; + private $mResult, $mAction, $mShowVersions, $mEnableWrite; private $mInternalMode, $mSquidMaxage, $mModule; private $mCacheMode = 'private'; @@ -141,11 +136,25 @@ class ApiMain extends ApiBase { /** * Constructs an instance of ApiMain that utilizes the module and format specified by $request. * - * @param $request WebRequest - if this is an instance of FauxRequest, errors are thrown and no printing occurs + * @param $context IContextSource|WebRequest - if this is an instance of FauxRequest, errors are thrown and no printing occurs * @param $enableWrite bool should be set to true if the api may modify data */ - public function __construct( $request, $enableWrite = false ) { - $this->mInternalMode = ( $request instanceof FauxRequest ); + public function __construct( $context = null, $enableWrite = false ) { + if ( $context === null ) { + $context = RequestContext::getMain(); + } elseif ( $context instanceof WebRequest ) { + // BC for pre-1.19 + $request = $context; + $context = RequestContext::getMain(); + } + // We set a derivative context so we can change stuff later + $this->setContext( new DerivativeContext( $context ) ); + + if ( isset( $request ) ) { + $this->getContext()->setRequest( $request ); + } + + $this->mInternalMode = ( $this->getRequest() instanceof FauxRequest ); // Special handling for the main module: $parent === $this parent::__construct( $this, $this->mInternalMode ? 'main_int' : 'main' ); @@ -156,11 +165,12 @@ class ApiMain extends ApiBase { // Remove all modules other than login global $wgUser; - if ( $request->getVal( 'callback' ) !== null ) { + if ( $this->getRequest()->getVal( 'callback' ) !== null ) { // JSON callback allows cross-site reads. // For safety, strip user credentials. wfDebug( "API: stripping user credentials for JSON callback\n" ); $wgUser = new User(); + $this->getContext()->setUser( $wgUser ); } } @@ -175,8 +185,6 @@ class ApiMain extends ApiBase { $this->mShowVersions = false; $this->mEnableWrite = $enableWrite; - $this->mRequest = &$request; - $this->mSquidMaxage = - 1; // flag for executeActionWithErrorHandling() $this->mCommit = false; } @@ -189,14 +197,6 @@ class ApiMain extends ApiBase { return $this->mInternalMode; } - /** - * Return the request object that contains client's request - * @return WebRequest - */ - public function getRequest() { - return $this->mRequest; - } - /** * Get the ApiResult object associated with current request * @@ -286,6 +286,7 @@ class ApiMain extends ApiBase { * $this->setCacheMode('private') */ public function setCachePrivate() { + wfDeprecated( __METHOD__, '1.17' ); $this->setCacheMode( 'private' ); } @@ -314,6 +315,7 @@ class ApiMain extends ApiBase { * @deprecated since 1.17 Use setCacheMode( 'anon-public-user-private' ) */ public function setVaryCookie() { + wfDeprecated( __METHOD__, '1.17' ); $this->setCacheMode( 'anon-public-user-private' ); } @@ -399,7 +401,7 @@ class ApiMain extends ApiBase { } protected function sendCacheHeaders() { - global $wgUseXVO, $wgOut, $wgVaryOnXFP; + global $wgUseXVO, $wgVaryOnXFP; $response = $this->getRequest()->response(); if ( $this->mCacheMode == 'private' ) { @@ -411,11 +413,12 @@ class ApiMain extends ApiBase { $xfp = $wgVaryOnXFP ? ', X-Forwarded-Proto' : ''; $response->header( 'Vary: Accept-Encoding, Cookie' . $xfp ); if ( $wgUseXVO ) { + $out = $this->getOutput(); if ( $wgVaryOnXFP ) { - $wgOut->addVaryHeader( 'X-Forwarded-Proto' ); + $out->addVaryHeader( 'X-Forwarded-Proto' ); } - $response->header( $wgOut->getXVO() ); - if ( $wgOut->haveCacheVaryCookies() ) { + $response->header( $out->getXVO() ); + if ( $out->haveCacheVaryCookies() ) { // Logged in, mark this request private $response->header( 'Cache-Control: private' ); return; @@ -428,7 +431,7 @@ class ApiMain extends ApiBase { return; } // else no XVO and anonymous, send public headers below } - + // Send public headers if ( $wgVaryOnXFP ) { $response->header( 'Vary: Accept-Encoding, X-Forwarded-Proto' ); @@ -486,6 +489,8 @@ class ApiMain extends ApiBase { * @return string */ protected function substituteResultWithError( $e ) { + global $wgShowHostnames; + $result = $this->getResult(); // Printer may not be initialized if the extractRequestParams() fails for the main module if ( !isset ( $this->mPrinter ) ) { @@ -533,8 +538,12 @@ class ApiMain extends ApiBase { if ( !is_null( $requestid ) ) { $result->addValue( null, 'requestid', $requestid ); } - // servedby is especially useful when debugging errors - $result->addValue( null, 'servedby', wfHostName() ); + + if ( $wgShowHostnames ) { + // servedby is especially useful when debugging errors + $result->addValue( null, 'servedby', wfHostName() ); + } + $result->addValue( null, 'error', $errMessage ); return $errMessage['code']; @@ -545,15 +554,20 @@ class ApiMain extends ApiBase { * @return array */ protected function setupExecuteAction() { + global $wgShowHostnames; + // First add the id to the top element $result = $this->getResult(); $requestid = $this->getParameter( 'requestid' ); if ( !is_null( $requestid ) ) { $result->addValue( null, 'requestid', $requestid ); } - $servedby = $this->getParameter( 'servedby' ); - if ( $servedby ) { - $result->addValue( null, 'servedby', wfHostName() ); + + if ( $wgShowHostnames ) { + $servedby = $this->getParameter( 'servedby' ); + if ( $servedby ) { + $result->addValue( null, 'servedby', wfHostName() ); + } } $params = $this->extractRequestParams(); @@ -591,8 +605,7 @@ class ApiMain extends ApiBase { if ( !isset( $moduleParams['token'] ) ) { $this->dieUsageMsg( array( 'missingparam', 'token' ) ); } else { - global $wgUser; - if ( !$wgUser->matchEditToken( $moduleParams['token'], $salt, $this->getRequest() ) ) { + if ( !$this->getUser()->matchEditToken( $moduleParams['token'], $salt, $this->getRequest() ) ) { $this->dieUsageMsg( 'sessionfailure' ); } } @@ -634,9 +647,9 @@ class ApiMain extends ApiBase { * @param $module ApiBase An Api module */ protected function checkExecutePermissions( $module ) { - global $wgUser; + $user = $this->getUser(); if ( $module->isReadMode() && !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) && - !$wgUser->isAllowed( 'read' ) ) + !$user->isAllowed( 'read' ) ) { $this->dieUsageMsg( 'readrequired' ); } @@ -644,7 +657,7 @@ class ApiMain extends ApiBase { if ( !$this->mEnableWrite ) { $this->dieUsageMsg( 'writedisabled' ); } - if ( !$wgUser->isAllowed( 'writeapi' ) ) { + if ( !$user->isAllowed( 'writeapi' ) ) { $this->dieUsageMsg( 'writerequired' ); } if ( wfReadOnly() ) { @@ -660,7 +673,7 @@ class ApiMain extends ApiBase { */ protected function setupExternalResponse( $module, $params ) { // Ignore mustBePosted() for internal calls - if ( $module->mustBePosted() && !$this->mRequest->wasPosted() ) { + if ( $module->mustBePosted() && !$this->getRequest()->wasPosted() ) { $this->dieUsageMsg( array( 'mustbeposted', $this->mAction ) ); } @@ -807,8 +820,8 @@ class ApiMain extends ApiBase { '** **', '** This is an auto-generated MediaWiki API documentation page **', '** **', - '** Documentation and Examples: **', - '** https://www.mediawiki.org/wiki/API **', + '** Documentation and Examples: **', + '** https://www.mediawiki.org/wiki/API **', '** **', '**********************************************************************************************************', '', @@ -970,8 +983,7 @@ class ApiMain extends ApiBase { */ public function canApiHighLimits() { if ( !isset( $this->mCanApiHighLimits ) ) { - global $wgUser; - $this->mCanApiHighLimits = $wgUser->isAllowed( 'apihighlimits' ); + $this->mCanApiHighLimits = $this->getUser()->isAllowed( 'apihighlimits' ); } return $this->mCanApiHighLimits; diff --git a/includes/api/ApiMove.php b/includes/api/ApiMove.php index a0b7bcbe..f0a25e4a 100644 --- a/includes/api/ApiMove.php +++ b/includes/api/ApiMove.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API Module to move pages * @ingroup API @@ -40,7 +35,7 @@ class ApiMove extends ApiBase { } public function execute() { - global $wgUser; + $user = $this->getUser(); $params = $this->extractRequestParams(); if ( is_null( $params['reason'] ) ) { $params['reason'] = ''; @@ -75,9 +70,9 @@ class ApiMove extends ApiBase { && !RepoGroup::singleton()->getLocalRepo()->findFile( $toTitle ) && wfFindFile( $toTitle ) ) { - if ( !$params['ignorewarnings'] && $wgUser->isAllowed( 'reupload-shared' ) ) { + if ( !$params['ignorewarnings'] && $user->isAllowed( 'reupload-shared' ) ) { $this->dieUsageMsg( 'sharedfile-exists' ); - } elseif ( !$wgUser->isAllowed( 'reupload-shared' ) ) { + } elseif ( !$user->isAllowed( 'reupload-shared' ) ) { $this->dieUsageMsg( 'cantoverwrite-sharedfile' ); } } @@ -89,7 +84,7 @@ class ApiMove extends ApiBase { } $r = array( 'from' => $fromTitle->getPrefixedText(), 'to' => $toTitle->getPrefixedText(), 'reason' => $params['reason'] ); - if ( !$params['noredirect'] || !$wgUser->isAllowed( 'suppressredirect' ) ) { + if ( !$params['noredirect'] || !$user->isAllowed( 'suppressredirect' ) ) { $r['redirectcreated'] = ''; } @@ -254,7 +249,7 @@ class ApiMove extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=move&from=Exampel&to=Example&token=123ABC&reason=Misspelled%20title&movetalk=&noredirect=' ); diff --git a/includes/api/ApiOpenSearch.php b/includes/api/ApiOpenSearch.php index 65ee0db9..0727cffd 100644 --- a/includes/api/ApiOpenSearch.php +++ b/includes/api/ApiOpenSearch.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -116,10 +111,10 @@ class ApiOpenSearch extends ApiBase { } public function getDescription() { - return 'Searches the wiki using the OpenSearch protocol'; + return 'Search the wiki using the OpenSearch protocol'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=opensearch&search=Te' ); diff --git a/includes/api/ApiPageSet.php b/includes/api/ApiPageSet.php index 4718221d..7b84c473 100644 --- a/includes/api/ApiPageSet.php +++ b/includes/api/ApiPageSet.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * This class contains a list of pages that the client has requested. * Initially, when the client passes in titles=, pageids=, or revisions= @@ -57,7 +52,7 @@ class ApiPageSet extends ApiQueryBase { /** * Constructor - * @param $query ApiQuery + * @param $query ApiQueryBase * @param $resolveRedirects bool Whether redirects should be resolved * @param $convertTitles bool */ @@ -464,7 +459,7 @@ class ApiPageSet extends ApiQueryBase { __METHOD__ ); $this->profileDBOut(); } - + $this->initFromQueryResult( $res, $remaining, false ); // process PageIDs // Resolve any found redirects @@ -645,8 +640,8 @@ class ApiPageSet extends ApiQueryBase { // We found pages that aren't in the redirect table // Add them foreach ( $this->mPendingRedirectIDs as $id => $title ) { - $article = new Article( $title ); - $rt = $article->insertRedirect(); + $page = WikiPage::factory( $title ); + $rt = $page->insertRedirect(); if ( !$rt ) { // What the hell. Let's just ignore this continue; @@ -743,7 +738,7 @@ class ApiPageSet extends ApiQueryBase { return $array; } - protected function getAllowedParams() { + public function getAllowedParams() { return array( 'titles' => array( ApiBase::PARAM_ISMULTI => true @@ -759,7 +754,7 @@ class ApiPageSet extends ApiQueryBase { ); } - protected function getParamDescription() { + public function getParamDescription() { return array( 'titles' => 'A list of titles to work on', 'pageids' => 'A list of page IDs to work on', diff --git a/includes/api/ApiParamInfo.php b/includes/api/ApiParamInfo.php index ad098920..f2263476 100644 --- a/includes/api/ApiParamInfo.php +++ b/includes/api/ApiParamInfo.php @@ -24,65 +24,86 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ class ApiParamInfo extends ApiBase { + /** + * @var ApiQuery + */ + protected $queryObj; + public function __construct( $main, $action ) { parent::__construct( $main, $action ); + $this->queryObj = new ApiQuery( $this->getMain(), 'query' ); } public function execute() { // Get parameters $params = $this->extractRequestParams(); $result = $this->getResult(); - $queryObj = new ApiQuery( $this->getMain(), 'query' ); - $r = array(); + + $res = array(); if ( is_array( $params['modules'] ) ) { - $modArr = $this->getMain()->getModules(); - $r['modules'] = array(); - foreach ( $params['modules'] as $m ) { - if ( !isset( $modArr[$m] ) ) { - $r['modules'][] = array( 'name' => $m, 'missing' => '' ); + $modules = $this->getMain()->getModules(); + $res['modules'] = array(); + foreach ( $params['modules'] as $mod ) { + if ( !isset( $modules[$mod] ) ) { + $res['modules'][] = array( 'name' => $mod, 'missing' => '' ); continue; } - $obj = new $modArr[$m]( $this->getMain(), $m ); - $a = $this->getClassInfo( $obj ); - $a['name'] = $m; - $r['modules'][] = $a; + $obj = new $modules[$mod]( $this->getMain(), $mod ); + + $item = $this->getClassInfo( $obj ); + $item['name'] = $mod; + $res['modules'][] = $item; } - $result->setIndexedTagName( $r['modules'], 'module' ); + $result->setIndexedTagName( $res['modules'], 'module' ); } + if ( is_array( $params['querymodules'] ) ) { - $qmodArr = $queryObj->getModules(); - $r['querymodules'] = array(); + $queryModules = $this->queryObj->getModules(); + $res['querymodules'] = array(); foreach ( $params['querymodules'] as $qm ) { - if ( !isset( $qmodArr[$qm] ) ) { - $r['querymodules'][] = array( 'name' => $qm, 'missing' => '' ); + if ( !isset( $queryModules[$qm] ) ) { + $res['querymodules'][] = array( 'name' => $qm, 'missing' => '' ); continue; } - $obj = new $qmodArr[$qm]( $this, $qm ); - $a = $this->getClassInfo( $obj ); - $a['name'] = $qm; - $a['querytype'] = $queryObj->getModuleType( $qm ); - $r['querymodules'][] = $a; + $obj = new $queryModules[$qm]( $this, $qm ); + $item = $this->getClassInfo( $obj ); + $item['name'] = $qm; + $item['querytype'] = $this->queryObj->getModuleType( $qm ); + $res['querymodules'][] = $item; } - $result->setIndexedTagName( $r['querymodules'], 'module' ); + $result->setIndexedTagName( $res['querymodules'], 'module' ); } + if ( $params['mainmodule'] ) { - $r['mainmodule'] = $this->getClassInfo( $this->getMain() ); + $res['mainmodule'] = $this->getClassInfo( $this->getMain() ); } + if ( $params['pagesetmodule'] ) { - $pageSet = new ApiPageSet( $queryObj ); - $r['pagesetmodule'] = $this->getClassInfo( $pageSet ); + $pageSet = new ApiPageSet( $this->queryObj ); + $res['pagesetmodule'] = $this->getClassInfo( $pageSet ); + } + + if ( is_array( $params['formatmodules'] ) ) { + $formats = $this->getMain()->getFormats(); + $res['formatmodules'] = array(); + foreach ( $params['formatmodules'] as $f ) { + if ( !isset( $formats[$f] ) ) { + $res['formatmodules'][] = array( 'name' => $f, 'missing' => '' ); + continue; + } + $obj = new $formats[$f]( $this, $f ); + $item = $this->getClassInfo( $obj ); + $item['name'] = $f; + $res['formatmodules'][] = $item; + } + $result->setIndexedTagName( $res['formatmodules'], 'module' ); } - $result->addValue( null, $this->getModuleName(), $r ); + $result->addValue( null, $this->getModuleName(), $res ); } /** @@ -92,9 +113,10 @@ class ApiParamInfo extends ApiBase { function getClassInfo( $obj ) { $result = $this->getResult(); $retval['classname'] = get_class( $obj ); - $retval['description'] = implode( "\n", (array)$obj->getDescription() ); - $examples = (array)$obj->getExamples(); - $retval['examples'] = implode( "\n", $examples ); + $retval['description'] = implode( "\n", (array)$obj->getFinalDescription() ); + + $retval['examples'] = ''; + $retval['version'] = implode( "\n", (array)$obj->getVersion() ); $retval['prefix'] = $obj->getModulePrefix(); @@ -122,9 +144,31 @@ class ApiParamInfo extends ApiBase { } $result->setIndexedTagName( $retval['helpurls'], 'helpurl' ); - $retval['allexamples'] = $examples; - if ( isset( $retval['allexamples'][0] ) && $retval['allexamples'][0] === false ) { - $retval['allexamples'] = array(); + $examples = $obj->getExamples(); + $retval['allexamples'] = array(); + if ( $examples !== false ) { + if ( is_string( $examples ) ) { + $examples = array( $examples ); + } + foreach( $examples as $k => $v ) { + if ( strlen( $retval['examples'] ) ) { + $retval['examples'] .= ' '; + } + $item = array(); + if ( is_numeric( $k ) ) { + $retval['examples'] .= $v; + $result->setContent( $item, $v ); + } else { + if ( !is_array( $v ) ) { + $item['description'] = $v; + } else { + $item['description'] = implode( $v, "\n" ); + } + $retval['examples'] .= $item['description'] . ' ' . $k; + $result->setContent( $item, $k ); + } + $retval['allexamples'][] = $item; + } } $result->setIndexedTagName( $retval['allexamples'], 'example' ); @@ -219,15 +263,27 @@ class ApiParamInfo extends ApiBase { } public function getAllowedParams() { + $modules = array_keys( $this->getMain()->getModules() ); + sort( $modules ); + $querymodules = array_keys( $this->queryObj->getModules() ); + sort( $querymodules ); + $formatmodules = array_keys( $this->getMain()->getFormats() ); + sort( $formatmodules ); return array( 'modules' => array( - ApiBase::PARAM_ISMULTI => true + ApiBase::PARAM_ISMULTI => true, + ApiBase::PARAM_TYPE => $modules, ), 'querymodules' => array( - ApiBase::PARAM_ISMULTI => true + ApiBase::PARAM_ISMULTI => true, + ApiBase::PARAM_TYPE => $querymodules, ), 'mainmodule' => false, 'pagesetmodule' => false, + 'formatmodules' => array( + ApiBase::PARAM_ISMULTI => true, + ApiBase::PARAM_TYPE => $formatmodules, + ) ); } @@ -237,6 +293,7 @@ class ApiParamInfo extends ApiBase { 'querymodules' => 'List of query module names (value of prop=, meta= or list= parameter)', 'mainmodule' => 'Get information about the main (top-level) module as well', 'pagesetmodule' => 'Get information about the pageset module (providing titles= and friends) as well', + 'formatmodules' => 'List of format module names (value of format= parameter)', ); } @@ -244,7 +301,7 @@ class ApiParamInfo extends ApiBase { return 'Obtain information about certain API parameters and errors'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=paraminfo&modules=parse&querymodules=allpages|siteinfo' ); diff --git a/includes/api/ApiParse.php b/includes/api/ApiParse.php index a3159186..893491b9 100644 --- a/includes/api/ApiParse.php +++ b/includes/api/ApiParse.php @@ -22,11 +22,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -63,7 +58,8 @@ class ApiParse extends ApiBase { // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* - global $wgParser, $wgUser, $wgTitle, $wgLang; + // TODO: Does this still need $wgTitle? + global $wgParser, $wgTitle, $wgLang; // Currently unnecessary, code to act as a safeguard against any change in current behaviour of uselang breaks $oldLang = null; @@ -72,7 +68,7 @@ class ApiParse extends ApiBase { $wgLang = Language::factory( $params['uselang'] ); } - $popts = new ParserOptions(); + $popts = ParserOptions::newFromContext( $this->getContext() ); $popts->setTidy( true ); $popts->enableLimitReport( !$params['disablepp'] ); @@ -88,7 +84,7 @@ class ApiParse extends ApiBase { if ( !$rev ) { $this->dieUsage( "There is no revision ID $oldid", 'missingrev' ); } - if ( !$rev->userCan( Revision::DELETED_TEXT ) ) { + if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) { $this->dieUsage( "You don't have permission to view deleted revisions", 'permissiondenied' ); } @@ -98,22 +94,20 @@ class ApiParse extends ApiBase { // 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, + // May get from/save to parser cache + $p_result = $this->getParsedSectionOrText( $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 ); - - $wgTitle = $titleObj; + $this->text = $rev->getText( Revision::FOR_THIS_USER, $this->getUser() ); if ( $this->section !== false ) { $this->text = $this->getSectionText( $this->text, 'r' . $rev->getId() ); } + // Should we save old revision parses to the parser cache? $p_result = $wgParser->parse( $this->text, $titleObj, $popts ); } - } else { // Not $oldid + } else { // Not $oldid, but $pageid or $page if ( $params['redirects'] ) { $reqParams = array( 'action' => 'query', @@ -155,12 +149,12 @@ class ApiParse extends ApiBase { } $wgTitle = $titleObj; - $articleObj = new Article( $titleObj, 0 ); if ( isset( $prop['revid'] ) ) { - $oldid = $articleObj->getRevIdFetched(); + $oldid = $titleObj->getLatestRevID(); } - $p_result = $this->getParsedSectionOrText( $articleObj, $titleObj, $popts, $pageid, + // Potentially cached + $p_result = $this->getParsedSectionOrText( $titleObj, $popts, $pageid, isset( $prop['wikitext'] ) ) ; } } else { // Not $oldid, $pageid, $page. Hence based on $text @@ -180,10 +174,11 @@ class ApiParse extends ApiBase { } if ( $params['pst'] || $params['onlypst'] ) { - $this->pstText = $wgParser->preSaveTransform( $this->text, $titleObj, $wgUser, $popts ); + $this->pstText = $wgParser->preSaveTransform( $this->text, $titleObj, $this->getUser(), $popts ); } if ( $params['onlypst'] ) { // Build a result and bail out + $result_array = array(); $result_array['text'] = array(); $result->setContent( $result_array['text'], $this->pstText ); if ( isset( $prop['wikitext'] ) ) { @@ -193,6 +188,7 @@ class ApiParse extends ApiBase { $result->addValue( null, $this->getModuleName(), $result_array ); return; } + // Not cached (save or load) $p_result = $wgParser->parse( $params['pst'] ? $this->pstText : $this->text, $titleObj, $popts ); } @@ -215,7 +211,7 @@ class ApiParse extends ApiBase { if ( !is_null( $params['summary'] ) ) { $result_array['parsedsummary'] = array(); - $result->setContent( $result_array['parsedsummary'], $wgUser->getSkin()->formatComment( $params['summary'], $titleObj ) ); + $result->setContent( $result_array['parsedsummary'], Linker::formatComment( $params['summary'], $titleObj ) ); } if ( isset( $prop['langlinks'] ) ) { @@ -257,16 +253,16 @@ class ApiParse extends ApiBase { } if ( isset( $prop['headitems'] ) || isset( $prop['headhtml'] ) ) { - $context = new RequestContext; + $context = $this->getContext(); + $context->setTitle( $titleObj ); $context->getOutput()->addParserOutputNoText( $p_result ); if ( isset( $prop['headitems'] ) ) { $headItems = $this->formatHeadItems( $p_result->getHeadItems() ); - $context->getSkin()->setupUserCss( $context->getOutput() ); $css = $this->formatCss( $context->getOutput()->buildCssLinksArray() ); - $scripts = array( $context->getOutput()->getHeadScripts( $context->getSkin() ) ); + $scripts = array( $context->getOutput()->getHeadScripts() ); $result_array['headitems'] = array_merge( $headItems, $css, $scripts ); } @@ -311,29 +307,29 @@ class ApiParse extends ApiBase { } /** - * @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 ) { - if ( $this->section !== false ) { - global $wgParser; + private function getParsedSectionOrText( $titleObj, $popts, $pageId = null, $getWikitext = false ) { + global $wgParser; + + $page = WikiPage::factory( $titleObj ); - $this->text = $this->getSectionText( $articleObj->getRawText(), !is_null ( $pageId ) + if ( $this->section !== false ) { + $this->text = $this->getSectionText( $page->getRawText(), !is_null( $pageId ) ? 'page id ' . $pageId : $titleObj->getText() ); + // Not cached (save or load) return $wgParser->parse( $this->text, $titleObj, $popts ); } else { // Try the parser cache first - $pout = $articleObj->getParserOutput(); + // getParserOutput will save to Parser cache if able + $pout = $page->getParserOutput( $popts ); if ( $getWikitext ) { - $rev = Revision::newFromTitle( $titleObj ); - if ( $rev ) { - $this->text = $rev->getText(); - } + $this->text = $page->getRawText(); } return $pout; } @@ -341,6 +337,7 @@ class ApiParse extends ApiBase { private function getSectionText( $text, $what ) { global $wgParser; + // Not cached (save or load) $text = $wgParser->getSection( $text, $this->section, false ); if ( $text === false ) { $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' ); @@ -377,7 +374,7 @@ class ApiParse extends ApiBase { } private function categoriesHtml( $categories ) { - $context = $this->createContext(); + $context = $this->getContext(); $context->getOutput()->addCategoryLinks( $categories ); return $context->getSkin()->getCategories(); } @@ -385,8 +382,12 @@ class ApiParse extends ApiBase { /** * @deprecated since 1.18 No modern skin generates language links this way, please use language links * data to generate your own HTML. + * @param $languages array + * @return string */ private function languagesHtml( $languages ) { + wfDeprecated( __METHOD__, '1.18' ); + global $wgContLang, $wgHideInterlanguageLinks; if ( $wgHideInterlanguageLinks || count( $languages ) == 0 ) { @@ -584,7 +585,7 @@ class ApiParse extends ApiBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=parse&text={{Project:Sandbox}}' ); diff --git a/includes/api/ApiPatrol.php b/includes/api/ApiPatrol.php index 8e6e8738..1332f263 100644 --- a/includes/api/ApiPatrol.php +++ b/includes/api/ApiPatrol.php @@ -24,10 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - require_once ( 'ApiBase.php' ); -} - /** * Allows user to patrol pages * @ingroup API @@ -42,15 +38,13 @@ 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 = $rc->doMarkPatrolled( $wgUser ); + $retval = $rc->doMarkPatrolled( $this->getUser() ); if ( $retval ) { $this->dieUsageMsg( reset( $retval ) ); @@ -104,7 +98,7 @@ class ApiPatrol extends ApiBase { return 'patrol'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=patrol&token=123abc&rcid=230672766' ); diff --git a/includes/api/ApiProtect.php b/includes/api/ApiProtect.php index ac1e0736..fb225d86 100644 --- a/includes/api/ApiProtect.php +++ b/includes/api/ApiProtect.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -39,7 +34,7 @@ class ApiProtect extends ApiBase { } public function execute() { - global $wgUser, $wgRestrictionLevels; + global $wgRestrictionLevels; $params = $this->extractRequestParams(); $titleObj = Title::newFromText( $params['title'] ); @@ -47,7 +42,7 @@ class ApiProtect extends ApiBase { $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) ); } - $errors = $titleObj->getUserPermissionsErrors( 'protect', $wgUser ); + $errors = $titleObj->getUserPermissionsErrors( 'protect', $this->getUser() ); if ( $errors ) { // We don't care about multiple errors, just report one of them $this->dieUsageMsg( reset( $errors ) ); @@ -107,20 +102,16 @@ class ApiProtect extends ApiBase { } $cascade = $params['cascade']; - $articleObj = new Article( $titleObj ); $watch = $params['watch'] ? 'watch' : $params['watchlist']; $this->setWatch( $watch, $titleObj ); - if ( $titleObj->exists() ) { - $ok = $articleObj->updateRestrictions( $protections, $params['reason'], $cascade, $expiryarray ); - } else { - $ok = $titleObj->updateTitleProtection( $protections['create'], $params['reason'], $expiryarray['create'] ); - } - if ( !$ok ) { - // This is very weird. Maybe the article was deleted or the user was blocked/desysopped in the meantime? - // Just throw an unknown error in this case, as it's very likely to be a race condition - $this->dieUsageMsg( array() ); + $pageObj = WikiPage::factory( $titleObj ); + $status = $pageObj->doUpdateRestrictions( $protections, $expiryarray, $cascade, $params['reason'], $this->getUser() ); + + if ( !$status->isOK() ) { + $errors = $status->getErrorsArray(); + $this->dieUsageMsg( $errors[0] ); } $res = array( 'title' => $titleObj->getPrefixedText(), @@ -217,7 +208,7 @@ class ApiProtect extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=protect&title=Main%20Page&token=123ABC&protections=edit=sysop|move=sysop&cascade=&expiry=20070901163000|never', 'api.php?action=protect&title=Main%20Page&token=123ABC&protections=edit=all|move=all&reason=Lifting%20restrictions' diff --git a/includes/api/ApiPurge.php b/includes/api/ApiPurge.php index ac5f0207..9e9320fb 100644 --- a/includes/api/ApiPurge.php +++ b/includes/api/ApiPurge.php @@ -25,10 +25,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - require_once( 'ApiBase.php' ); -} - /** * API interface for page purging * @ingroup API @@ -43,42 +39,58 @@ class ApiPurge extends ApiBase { * Purges the cache of a page */ public function execute() { - global $wgUser; + $user = $this->getUser(); $params = $this->extractRequestParams(); - if ( !$wgUser->isAllowed( 'purge' ) && !$this->getMain()->isInternalMode() && - !$this->getMain()->getRequest()->wasPosted() ) { + if ( !$user->isAllowed( 'purge' ) && !$this->getMain()->isInternalMode() && + !$this->getRequest()->wasPosted() ) { $this->dieUsageMsg( array( 'mustbeposted', $this->getModuleName() ) ); } $forceLinkUpdate = $params['forcelinkupdate']; + $pageSet = new ApiPageSet( $this ); + $pageSet->execute(); $result = array(); - foreach ( $params['titles'] as $t ) { + foreach( $pageSet->getInvalidTitles() as $title ) { $r = array(); - $title = Title::newFromText( $t ); - if ( !$title instanceof Title ) { - $r['title'] = $t; - $r['invalid'] = ''; - $result[] = $r; - continue; - } + $r['title'] = $title; + $r['invalid'] = ''; + $result[] = $r; + } + foreach( $pageSet->getMissingPageIDs() as $p ) { + $page = array(); + $page['pageid'] = $p; + $page['missing'] = ''; + $result[] = $page; + } + foreach( $pageSet->getMissingRevisionIDs() as $r ) { + $rev = array(); + $rev['revid'] = $r; + $rev['missing'] = ''; + $result[] = $rev; + } + + foreach ( $pageSet->getTitles() as $title ) { + $r = array(); + ApiQueryBase::addTitleInfo( $r, $title ); if ( !$title->exists() ) { $r['missing'] = ''; $result[] = $r; continue; } - $context = $this->createContext(); - $context->setTitle( $title ); - $article = Article::newFromTitle( $title, $context ); - $article->doPurge(); // Directly purge and skip the UI part of purge(). + + $page = WikiPage::factory( $title ); + $page->doPurge(); // Directly purge and skip the UI part of purge(). $r['purged'] = ''; if( $forceLinkUpdate ) { - if ( !$wgUser->pingLimiter() ) { + if ( !$user->pingLimiter() ) { global $wgParser, $wgEnableParserCache; - $popts = new ParserOptions(); - $p_result = $wgParser->parse( $article->getContent(), $title, $popts ); + + $popts = ParserOptions::newFromContext( $this->getContext() ); + $p_result = $wgParser->parse( $page->getRawText(), $title, $popts, + true, true, $page->getLatest() ); # Update the links tables $u = new LinksUpdate( $title, $p_result ); @@ -88,7 +100,7 @@ class ApiPurge extends ApiBase { if ( $wgEnableParserCache ) { $pcache = ParserCache::singleton(); - $pcache->save( $p_result, $article, $popts ); + $pcache->save( $p_result, $page, $popts ); } } else { $this->setWarning( $this->parseMsg( array( 'actionthrottledtext' ) ) ); @@ -108,18 +120,15 @@ class ApiPurge extends ApiBase { } public function getAllowedParams() { - return array( - 'titles' => array( - ApiBase::PARAM_ISMULTI => true, - ApiBase::PARAM_REQUIRED => true - ), + $psModule = new ApiPageSet( $this ); + return $psModule->getAllowedParams() + array( 'forcelinkupdate' => false, ); } public function getParamDescription() { - return array( - 'titles' => 'A list of titles', + $psModule = new ApiPageSet( $this ); + return $psModule->getParamDescription() + array( 'forcelinkupdate' => 'Update the links tables', ); } @@ -131,14 +140,17 @@ class ApiPurge extends ApiBase { } public function getPossibleErrors() { - return array_merge( parent::getPossibleErrors(), array( - array( 'cantpurge' ), - ) ); + $psModule = new ApiPageSet( $this ); + return array_merge( + parent::getPossibleErrors(), + array( array( 'cantpurge' ), ), + $psModule->getPossibleErrors() + ); } - protected function getExamples() { + public function getExamples() { return array( - 'api.php?action=purge&titles=Main_Page|API' + 'api.php?action=purge&titles=Main_Page|API' => 'Purge the "Main Page" and the "API" page', ); } diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php index 717b43b4..cd54a7da 100644 --- a/includes/api/ApiQuery.php +++ b/includes/api/ApiQuery.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * This is the main query class. It behaves similar to ApiMain: based on the * parameters given, it will create a list of titles to work on (an ApiPageSet @@ -106,6 +101,8 @@ class ApiQuery extends ApiBase { private $mSlaveDB = null; private $mNamedDB = array(); + protected $mAllowedGenerators = array(); + public function __construct( $main, $action ) { parent::__construct( $main, $action ); @@ -119,9 +116,8 @@ class ApiQuery extends ApiBase { $this->mListModuleNames = array_keys( $this->mQueryListModules ); $this->mMetaModuleNames = array_keys( $this->mQueryMetaModules ); - // Allow the entire list of modules at first, - // but during module instantiation check if it can be used as a generator. - $this->mAllowedGenerators = array_merge( $this->mListModuleNames, $this->mPropModuleNames ); + $this->makeHelpMsgHelper( $this->mQueryPropModules, 'prop' ); + $this->makeHelpMsgHelper( $this->mQueryListModules, 'list' ); } /** @@ -179,7 +175,7 @@ class ApiQuery extends ApiBase { /** * Get the array mapping module names to class names - * @return array(modulename => classname) + * @return array array(modulename => classname) */ function getModules() { return array_merge( $this->mQueryPropModules, $this->mQueryListModules, $this->mQueryMetaModules ); @@ -281,6 +277,8 @@ class ApiQuery extends ApiBase { * The cache mode may increase in the level of privacy, but public modules * added to private data do not decrease the level of privacy. * + * @param $cacheMode string + * @param $modCacheMode string * @return string */ protected function mergeCacheMode( $cacheMode, $modCacheMode ) { @@ -441,7 +439,7 @@ class ApiQuery extends ApiBase { $vals = array(); ApiQueryBase::addTitleInfo( $vals, $title ); $vals['special'] = ''; - if ( $title->getNamespace() == NS_SPECIAL && + if ( $title->isSpecialPage() && !SpecialPageFactory::exists( $title->getDbKey() ) ) { $vals['missing'] = ''; } elseif ( $title->getNamespace() == NS_MEDIA && @@ -485,7 +483,7 @@ class ApiQuery extends ApiBase { $titles = $pageSet->getGoodTitles(); if ( count( $titles ) ) { foreach ( $titles as $title ) { - if ( $title->userCanRead() ) { + if ( $title->userCan( 'read' ) ) { $exportTitles[] = $title; } } @@ -634,6 +632,9 @@ class ApiQuery extends ApiBase { $moduleDescriptions = array(); foreach ( $moduleList as $moduleName => $moduleClass ) { + /** + * @var $module ApiQueryBase + */ $module = new $moduleClass( $this, $moduleName, null ); $msg = ApiMain::makeHelpMsgHeader( $module, $paramName ); @@ -673,7 +674,7 @@ class ApiQuery extends ApiBase { 'NOTE: generator parameter names must be prefixed with a \'g\', see examples' ), 'redirects' => 'Automatically resolve redirects', 'converttitles' => array( "Convert titles to other variants if necessary. Only works if the wiki's content language supports variant conversion.", - 'Languages that support variant conversion include kk, ku, gan, tg, sr, zh' ), + 'Languages that support variant conversion include gan, iu, kk, ku, shi, sr, tg, zh' ), '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', @@ -695,7 +696,7 @@ class ApiQuery extends ApiBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&prop=revisions&meta=siteinfo&titles=Main%20Page&rvprop=user|comment', 'api.php?action=query&generator=allpages&gapprefix=API/&prop=revisions', diff --git a/includes/api/ApiQueryAllCategories.php b/includes/api/ApiQueryAllCategories.php index fc56965e..78367a45 100644 --- a/includes/api/ApiQueryAllCategories.php +++ b/includes/api/ApiQueryAllCategories.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all categories, even the ones that don't have * category pages. @@ -55,7 +50,6 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase { /** * @param $resultPageSet ApiPageSet - * @return void */ private function run( $resultPageSet = null ) { $db = $this->getDB(); @@ -196,7 +190,7 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase { return 'Enumerate all categories'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=allcategories&acprop=size', 'api.php?action=query&generator=allcategories&gacprefix=List&prop=info', diff --git a/includes/api/ApiQueryAllLinks.php b/includes/api/ApiQueryAllLinks.php index 822d0136..903f144f 100644 --- a/includes/api/ApiQueryAllLinks.php +++ b/includes/api/ApiQueryAllLinks.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate links from all pages together. * @@ -221,7 +216,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=alllinks&alunique=&alfrom=B', ); diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php index 0443269e..ac112ef9 100644 --- a/includes/api/ApiQueryAllUsers.php +++ b/includes/api/ApiQueryAllUsers.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all registered users. * @@ -65,10 +60,15 @@ class ApiQueryAllUsers extends ApiQueryBase { $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 ); + # MySQL doesn't seem to use 'equality propagation' here, so like the + # ActiveUsers special page, we have to use rc_user_text for some cases. + $userFieldToSort = $params['activeusers'] ? 'rc_user_text' : 'user_name'; + + $this->addWhereRange( $userFieldToSort, $dir, $from, $to ); if ( !is_null( $params['prefix'] ) ) { - $this->addWhere( 'user_name' . $db->buildLike( $this->keyToTitle( $params['prefix'] ), $db->anyString() ) ); + $this->addWhere( $userFieldToSort . + $db->buildLike( $this->keyToTitle( $params['prefix'] ), $db->anyString() ) ); } if ( !is_null( $params['rights'] ) ) { @@ -148,7 +148,7 @@ class ApiQueryAllUsers extends ApiQueryBase { $timestamp = $db->timestamp( wfTimestamp( TS_UNIX ) - $wgActiveUserDays*24*3600 ); $this->addWhere( "rc_timestamp >= {$db->addQuotes( $timestamp )}" ); - $this->addOption( 'GROUP BY', 'user_name' ); + $this->addOption( 'GROUP BY', $userFieldToSort ); } $this->addOption( 'LIMIT', $sqlLimit ); @@ -235,10 +235,12 @@ class ApiQueryAllUsers extends ApiQueryBase { 'MediaWiki configuration error: the database contains more user groups than known to User::getAllGroups() function' ); } + $lastUserObj = User::newFromName( $lastUser ); + // Add user's group info if ( $fld_groups ) { - if ( !isset( $lastUserData['groups'] ) ) { - $lastUserData['groups'] = ApiQueryUsers::getAutoGroups( User::newFromName( $lastUser ) ); + if ( !isset( $lastUserData['groups'] ) && $lastUserObj ) { + $lastUserData['groups'] = ApiQueryUsers::getAutoGroups( $lastUserObj ); } if ( !is_null( $row->ug_group2 ) ) { @@ -247,13 +249,13 @@ class ApiQueryAllUsers extends ApiQueryBase { $result->setIndexedTagName( $lastUserData['groups'], 'g' ); } - if ( $fld_implicitgroups && !isset( $lastUserData['implicitgroups'] ) ) { - $lastUserData['implicitgroups'] = ApiQueryUsers::getAutoGroups( User::newFromName( $lastUser ) ); + if ( $fld_implicitgroups && !isset( $lastUserData['implicitgroups'] ) && $lastUserObj ) { + $lastUserData['implicitgroups'] = ApiQueryUsers::getAutoGroups( $lastUserObj ); $result->setIndexedTagName( $lastUserData['implicitgroups'], 'g' ); } if ( $fld_rights ) { - if ( !isset( $lastUserData['rights'] ) ) { - $lastUserData['rights'] = User::getGroupPermissions( User::newFromName( $lastUser )->getAutomaticGroups() ); + if ( !isset( $lastUserData['rights'] ) && $lastUserObj ) { + $lastUserData['rights'] = User::getGroupPermissions( $lastUserObj->getAutomaticGroups() ); } if ( !is_null( $row->ug_group2 ) ) { $lastUserData['rights'] = array_unique( array_merge( $lastUserData['rights'], @@ -362,7 +364,7 @@ class ApiQueryAllUsers extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=allusers&aufrom=Y', ); diff --git a/includes/api/ApiQueryAllimages.php b/includes/api/ApiQueryAllimages.php index f0fc39e3..ca344f73 100644 --- a/includes/api/ApiQueryAllimages.php +++ b/includes/api/ApiQueryAllimages.php @@ -26,11 +26,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all available pages. * @@ -249,14 +244,16 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Simple Use', - ' Show a list of images starting at the letter "B"', - ' api.php?action=query&list=allimages&aifrom=B', - 'Using as Generator', - ' Show info about 4 images starting at the letter "T"', - ' api.php?action=query&generator=allimages&gailimit=4&gaifrom=T&prop=imageinfo', + 'api.php?action=query&list=allimages&aifrom=B' => array( + 'Simple Use', + 'Show a list of images starting at the letter "B"', + ), + 'api.php?action=query&generator=allimages&gailimit=4&gaifrom=T&prop=imageinfo' => array( + 'Using as Generator', + 'Show info about 4 images starting at the letter "T"', + ), ); } diff --git a/includes/api/ApiQueryAllmessages.php b/includes/api/ApiQueryAllmessages.php index d636c613..44774927 100644 --- a/includes/api/ApiQueryAllmessages.php +++ b/includes/api/ApiQueryAllmessages.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * A query action to return messages from site message cache * @@ -65,7 +60,18 @@ class ApiQueryAllmessages extends ApiQueryBase { // Determine which messages should we print if ( in_array( '*', $params['messages'] ) ) { - $message_names = array_keys( Language::getMessagesFor( 'en' ) ); + $message_names = Language::getMessageKeysFor( $langObj->getCode() ); + if ( $params['includelocal'] ) { + global $wgLanguageCode; + $message_names = array_unique( array_merge( + $message_names, + // Pass in the content language code so we get local messages that have a + // MediaWiki:msgkey page. We might theoretically miss messages that have no + // MediaWiki:msgkey page but do have a MediaWiki:msgkey/lang page, but that's + // just a stupid case. + MessageCache::singleton()->getAllMessageKeys( $wgLanguageCode ) + ) ); + } sort( $message_names ); $messages_target = $message_names; } else { @@ -158,7 +164,9 @@ class ApiQueryAllmessages extends ApiQueryBase { } else { $msgString = $msg->plain(); } - ApiResult::setContent( $a, $msgString ); + if ( !$params['nocontent'] ) { + ApiResult::setContent( $a, $msgString ); + } if ( isset( $prop['default'] ) ) { $default = wfMessage( $message )->inLanguage( $langObj )->useDatabase( false ); if ( !$default->exists() ) { @@ -204,6 +212,8 @@ class ApiQueryAllmessages extends ApiQueryBase { ) ), 'enableparser' => false, + 'nocontent' => false, + 'includelocal' => false, 'args' => array( ApiBase::PARAM_ISMULTI => true, ApiBase::PARAM_ALLOW_DUPLICATES => true, @@ -230,7 +240,11 @@ class ApiQueryAllmessages extends ApiQueryBase { '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.' ), + 'Will substitute magic words, handle templates etc.' ), + 'nocontent' => 'If set, do not include the content of the messages in the output.', + 'includelocal' => array( "Also include local messages, i.e. messages that don't exist in the software but do exist as a MediaWiki: page.", + "This lists all MediaWiki: pages, so it will also list those that aren't 'really' messages such as Common.js", + ), 'title' => 'Page name to use as context when parsing message (for enableparser option)', 'args' => 'Arguments to be substituted into message', 'prefix' => 'Return messages with this prefix', @@ -246,7 +260,7 @@ class ApiQueryAllmessages extends ApiQueryBase { return 'Return messages from this site'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&meta=allmessages&refix=ipb-', 'api.php?action=query&meta=allmessages&ammessages=august|mainpage&amlang=de', diff --git a/includes/api/ApiQueryAllpages.php b/includes/api/ApiQueryAllpages.php index 4a216670..e003ee91 100644 --- a/includes/api/ApiQueryAllpages.php +++ b/includes/api/ApiQueryAllpages.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all available pages. * @@ -312,16 +307,19 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Simple Use', - ' Show a list of pages starting at the letter "B"', - ' api.php?action=query&list=allpages&apfrom=B', - 'Using as Generator', - ' Show info about 4 pages starting at the letter "T"', - ' api.php?action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info', - ' Show content of first 2 non-redirect pages begining at "Re"', - ' api.php?action=query&generator=allpages&gaplimit=2&gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content' + 'api.php?action=query&list=allpages&apfrom=B' => array( + 'Simple Use', + 'Show a list of pages starting at the letter "B"', + ), + 'api.php?action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info' => array( + 'Using as Generator', + 'Show info about 4 pages starting at the letter "T"', + ), + 'api.php?action=query&generator=allpages&gaplimit=2&gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content' => array( + 'Show content of first 2 non-redirect pages begining at "Re"', + ) ); } diff --git a/includes/api/ApiQueryBacklinks.php b/includes/api/ApiQueryBacklinks.php index 8e2639f3..381ef550 100644 --- a/includes/api/ApiQueryBacklinks.php +++ b/includes/api/ApiQueryBacklinks.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * This is a three-in-one module to query: * * backlinks - links pointing to the given page, @@ -511,7 +506,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { static $examples = array( 'backlinks' => array( 'api.php?action=query&list=backlinks&bltitle=Main%20Page', diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php index 130d0403..4fe82de0 100644 --- a/includes/api/ApiQueryBase.php +++ b/includes/api/ApiQueryBase.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * This is a base class for all Query modules. * It provides some common functionality such as constructing various SQL @@ -40,6 +35,11 @@ abstract class ApiQueryBase extends ApiBase { private $mQueryModule, $mDb, $tables, $where, $fields, $options, $join_conds; + /** + * @param $query ApiBase + * @param $moduleName string + * @param $paramPrefix string + */ public function __construct( ApiBase $query, $moduleName, $paramPrefix = '' ) { parent::__construct( $query->getMain(), $moduleName, $paramPrefix ); $this->mQueryModule = $query; @@ -55,6 +55,7 @@ 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. * + * @param $params * @return string */ public function getCacheMode( $params ) { @@ -213,21 +214,26 @@ abstract class ApiQueryBase extends ApiBase { if ( $sort ) { $order = $field . ( $isDirNewer ? '' : ' DESC' ); - if ( !isset( $this->options['ORDER BY'] ) ) { - $this->addOption( 'ORDER BY', $order ); - } else { - $this->addOption( 'ORDER BY', $this->options['ORDER BY'] . ', ' . $order ); - } + // Append ORDER BY + $optionOrderBy = isset( $this->options['ORDER BY'] ) ? (array)$this->options['ORDER BY'] : array(); + $optionOrderBy[] = $order; + $this->addOption( 'ORDER BY', $optionOrderBy ); } } + /** * Add a WHERE clause corresponding to a range, similar to addWhereRange, * but converts $start and $end to database timestamps. * @see addWhereRange + * @param $field + * @param $dir + * @param $start + * @param $end + * @param $sort bool */ protected function addTimestampWhereRange( $field, $dir, $start, $end, $sort = true ) { $db = $this->getDb(); - return $this->addWhereRange( $field, $dir, + return $this->addWhereRange( $field, $dir, $db->timestampOrNull( $start ), $db->timestampOrNull( $end ), $sort ); } @@ -502,8 +508,7 @@ abstract class ApiQueryBase extends ApiBase { * @return void */ public function showHiddenUsersAddBlockInfo( $showBlockInfo ) { - global $wgUser; - $userCanViewHiddenUsers = $wgUser->isAllowed( 'hideuser' ); + $userCanViewHiddenUsers = $this->getUser()->isAllowed( 'hideuser' ); if ( $showBlockInfo || !$userCanViewHiddenUsers ) { $this->addTables( 'ipblocks' ); diff --git a/includes/api/ApiQueryBlocks.php b/includes/api/ApiQueryBlocks.php index cfcaf0b3..bebb5a7d 100644 --- a/includes/api/ApiQueryBlocks.php +++ b/includes/api/ApiQueryBlocks.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all user blocks * @@ -46,7 +41,7 @@ class ApiQueryBlocks extends ApiQueryBase { } public function execute() { - global $wgUser, $wgContLang; + global $wgContLang; $params = $this->extractRequestParams(); $this->requireMaxOneParameter( $params, 'users', 'ip' ); @@ -92,6 +87,7 @@ class ApiQueryBlocks extends ApiQueryBase { $this->addWhereFld( 'ipb_address', $this->usernames ); $this->addWhereFld( 'ipb_auto', 0 ); } + $db = $this->getDB(); if ( isset( $params['ip'] ) ) { list( $ip, $range ) = IP::parseCIDR( $params['ip'] ); if ( $ip && $range ) { @@ -105,7 +101,6 @@ class ApiQueryBlocks extends ApiQueryBase { } $prefix = substr( $lower, 0, 4 ); - $db = $this->getDB(); $this->addWhere( array( 'ipb_range_start' . $db->buildLike( $prefix, $db->anyString() ), "ipb_range_start <= '$lower'", @@ -114,7 +109,29 @@ class ApiQueryBlocks extends ApiQueryBase { ) ); } - if ( !$wgUser->isAllowed( 'hideuser' ) ) { + if ( !is_null( $params['show'] ) ) { + $show = array_flip( $params['show'] ); + + /* Check for conflicting parameters. */ + if ( ( isset ( $show['account'] ) && isset ( $show['!account'] ) ) + || ( isset ( $show['ip'] ) && isset ( $show['!ip'] ) ) + || ( isset ( $show['range'] ) && isset ( $show['!range'] ) ) + || ( isset ( $show['temp'] ) && isset ( $show['!temp'] ) ) + ) { + $this->dieUsageMsg( 'show' ); + } + + $this->addWhereIf( 'ipb_user = 0', isset( $show['!account'] ) ); + $this->addWhereIf( 'ipb_user != 0', isset( $show['account'] ) ); + $this->addWhereIf( 'ipb_user != 0 OR ipb_range_end > ipb_range_start', isset( $show['!ip'] ) ); + $this->addWhereIf( 'ipb_user = 0 AND ipb_range_end = ipb_range_start', isset( $show['ip'] ) ); + $this->addWhereIf( 'ipb_expiry = '.$db->addQuotes($db->getInfinity()), isset( $show['!temp'] ) ); + $this->addWhereIf( 'ipb_expiry != '.$db->addQuotes($db->getInfinity()), isset( $show['temp'] ) ); + $this->addWhereIf( "ipb_range_end = ipb_range_start", isset( $show['!range'] ) ); + $this->addWhereIf( "ipb_range_end > ipb_range_start", isset( $show['range'] ) ); + } + + if ( !$this->getUser()->isAllowed( 'hideuser' ) ) { $this->addWhereFld( 'ipb_deleted', 0 ); } @@ -252,15 +269,29 @@ class ApiQueryBlocks extends ApiQueryBase { 'flags' ), ApiBase::PARAM_ISMULTI => true - ) + ), + 'show' => array( + ApiBase::PARAM_TYPE => array( + 'account', + '!account', + 'temp', + '!temp', + 'ip', + '!ip', + 'range', + '!range', + ), + ApiBase::PARAM_ISMULTI => true + ), ); } public function getParamDescription() { + $p = $this->getModulePrefix(); return array( 'start' => 'The timestamp to start enumerating from', 'end' => 'The timestamp to stop enumerating at', - 'dir' => $this->getDirectionDescription( $this->getModulePrefix() ), + 'dir' => $this->getDirectionDescription( $p ), '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.', @@ -279,6 +310,10 @@ class ApiQueryBlocks extends ApiQueryBase { ' range - Adds the range of IPs affected by the block', ' flags - Tags the ban with (autoblock, anononly, etc)', ), + 'show' => array( + 'Show only items that meet this criteria.', + "For example, to see only indefinite blocks on IPs, set {$p}show=ip|!temp" + ), ); } @@ -292,10 +327,11 @@ class ApiQueryBlocks extends ApiQueryBase { 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' ), + array( 'show' ), ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=blocks', 'api.php?action=query&list=blocks&bkusers=Alice|Bob' diff --git a/includes/api/ApiQueryCategories.php b/includes/api/ApiQueryCategories.php index a6bca698..1c1f1550 100644 --- a/includes/api/ApiQueryCategories.php +++ b/includes/api/ApiQueryCategories.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * A query module to enumerate categories the set of pages belong to. * @@ -80,7 +75,7 @@ class ApiQueryCategories extends ApiQueryGeneratorBase { foreach ( $params['categories'] as $cat ) { $title = Title::newFromText( $cat ); if ( !$title || $title->getNamespace() != NS_CATEGORY ) { - $this->setWarning( "``$cat'' is not a category" ); + $this->setWarning( "\"$cat\" is not a category" ); } else { $cats[] = $title->getDBkey(); } @@ -127,11 +122,16 @@ class ApiQueryCategories extends ApiQueryGeneratorBase { } $this->addOption( 'USE INDEX', array( 'categorylinks' => 'cl_from' ) ); + + $dir = ( $params['dir'] == 'descending' ? ' DESC' : '' ); // Don't order by cl_from if it's constant in the WHERE clause if ( count( $this->getPageSet()->getGoodTitles() ) == 1 ) { - $this->addOption( 'ORDER BY', 'cl_to' ); + $this->addOption( 'ORDER BY', 'cl_to' . $dir ); } else { - $this->addOption( 'ORDER BY', "cl_from, cl_to" ); + $this->addOption( 'ORDER BY', array( + 'cl_from' . $dir, + 'cl_to' . $dir + )); } $res = $this->select( __METHOD__ ); @@ -213,6 +213,13 @@ class ApiQueryCategories extends ApiQueryGeneratorBase { 'categories' => array( ApiBase::PARAM_ISMULTI => true, ), + 'dir' => array( + ApiBase::PARAM_DFLT => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), ); } @@ -228,6 +235,7 @@ class ApiQueryCategories extends ApiQueryGeneratorBase { 'show' => 'Which kind of categories to show', 'continue' => 'When more results are available, use this to continue', 'categories' => 'Only list these categories. Useful for checking whether a certain page is in a certain category', + 'dir' => 'The direction in which to list', ); } @@ -241,12 +249,10 @@ class ApiQueryCategories extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Get a list of categories [[Albert Einstein]] belongs to:', - ' api.php?action=query&prop=categories&titles=Albert%20Einstein', - 'Get information about all categories used in the [[Albert Einstein]]:', - ' api.php?action=query&generator=categories&titles=Albert%20Einstein&prop=info' + 'api.php?action=query&prop=categories&titles=Albert%20Einstein' => 'Get a list of categories [[Albert Einstein]] belongs to', + 'api.php?action=query&generator=categories&titles=Albert%20Einstein&prop=info' => 'Get information about all categories used in the [[Albert Einstein]]', ); } diff --git a/includes/api/ApiQueryCategoryInfo.php b/includes/api/ApiQueryCategoryInfo.php index 3130140f..c5070e87 100644 --- a/includes/api/ApiQueryCategoryInfo.php +++ b/includes/api/ApiQueryCategoryInfo.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * This query adds the subelement to all pages with the list of categories the page is in * @@ -115,7 +110,7 @@ class ApiQueryCategoryInfo extends ApiQueryBase { return 'Returns information about the given categories'; } - protected function getExamples() { + public function getExamples() { return 'api.php?action=query&prop=categoryinfo&titles=Category:Foo|Category:Bar'; } diff --git a/includes/api/ApiQueryCategoryMembers.php b/includes/api/ApiQueryCategoryMembers.php index c916f5c1..4b19b7e8 100644 --- a/includes/api/ApiQueryCategoryMembers.php +++ b/includes/api/ApiQueryCategoryMembers.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * A query module to enumerate pages that belong to a category. * @@ -153,7 +148,7 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase { $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, @@ -392,12 +387,10 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase { ); } - protected function getExamples() { + public function getExamples() { return array( - 'Get first 10 pages in [[Category:Physics]]:', - ' api.php?action=query&list=categorymembers&cmtitle=Category:Physics', - 'Get page info about first 10 pages in [[Category:Physics]]:', - ' api.php?action=query&generator=categorymembers&gcmtitle=Category:Physics&prop=info', + 'api.php?action=query&list=categorymembers&cmtitle=Category:Physics' => 'Get first 10 pages in [[Category:Physics]]', + 'api.php?action=query&generator=categorymembers&gcmtitle=Category:Physics&prop=info' => 'Get page info about first 10 pages in [[Category:Physics]]', ); } diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php index e226070c..0a0cc93d 100644 --- a/includes/api/ApiQueryDeletedrevs.php +++ b/includes/api/ApiQueryDeletedrevs.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all deleted revisions. * @@ -41,9 +36,9 @@ class ApiQueryDeletedrevs extends ApiQueryBase { } public function execute() { - global $wgUser; + $user = $this->getUser(); // Before doing anything at all, let's check permissions - if ( !$wgUser->isAllowed( 'deletedhistory' ) ) { + if ( !$user->isAllowed( 'deletedhistory' ) ) { $this->dieUsage( 'You don\'t have permission to view deleted revision information', 'permissiondenied' ); } @@ -58,6 +53,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $fld_parsedcomment = isset ( $prop['parsedcomment'] ); $fld_minor = isset( $prop['minor'] ); $fld_len = isset( $prop['len'] ); + $fld_sha1 = isset( $prop['sha1'] ); $fld_content = isset( $prop['content'] ); $fld_token = isset( $prop['token'] ); @@ -106,6 +102,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $this->addFieldsIf( 'ar_comment', $fld_comment || $fld_parsedcomment ); $this->addFieldsIf( 'ar_minor_edit', $fld_minor ); $this->addFieldsIf( 'ar_len', $fld_len ); + $this->addFieldsIf( 'ar_sha1', $fld_sha1 ); if ( $fld_content ) { $this->addTables( 'text' ); @@ -113,7 +110,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $this->addWhere( 'ar_text_id = old_id' ); // This also means stricter restrictions - if ( !$wgUser->isAllowed( 'undelete' ) ) { + if ( !$user->isAllowed( 'undelete' ) ) { $this->dieUsage( 'You don\'t have permission to view deleted revision content', 'permissiondenied' ); } } @@ -132,7 +129,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { if ( $fld_token ) { // Undelete tokens are identical for all pages, so we cache one here - $token = $wgUser->editToken( '', $this->getMain()->getRequest() ); + $token = $user->getEditToken( '', $this->getMain()->getRequest() ); } $dir = $params['dir']; @@ -214,7 +211,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { if ( $fld_revid ) { $rev['revid'] = intval( $row->ar_rev_id ); } - if ( $fld_parentid ) { + if ( $fld_parentid && !is_null( $row->ar_parent_id ) ) { $rev['parentid'] = intval( $row->ar_parent_id ); } if ( $fld_user ) { @@ -230,7 +227,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { $title = Title::makeTitle( $row->ar_namespace, $row->ar_title ); if ( $fld_parsedcomment ) { - $rev['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->ar_comment, $title ); + $rev['parsedcomment'] = Linker::formatComment( $row->ar_comment, $title ); } if ( $fld_minor && $row->ar_minor_edit == 1 ) { $rev['minor'] = ''; @@ -238,6 +235,13 @@ class ApiQueryDeletedrevs extends ApiQueryBase { if ( $fld_len ) { $rev['len'] = $row->ar_len; } + if ( $fld_sha1 ) { + if ( $row->ar_sha1 != '' ) { + $rev['sha1'] = wfBaseConvert( $row->ar_sha1, 36, 16, 40 ); + } else { + $rev['sha1'] = ''; + } + } if ( $fld_content ) { ApiResult::setContent( $rev, Revision::getRevisionText( $row ) ); } @@ -319,6 +323,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase { 'parsedcomment', 'minor', 'len', + 'sha1', 'content', 'token' ), @@ -345,7 +350,8 @@ class ApiQueryDeletedrevs extends ApiQueryBase { ' comment - Adds the comment of the revision', ' parsedcomment - Adds the parsed comment of the revision', ' minor - Tags if the revision is minor', - ' len - Adds the length of the revision', + ' len - Adds the length (bytes) of the revision', + ' sha1 - Adds the SHA-1 (base 16) of the revision', ' content - Adds the content of the revision', ' token - Gives the edit token', ), @@ -385,16 +391,16 @@ class ApiQueryDeletedrevs extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'List the last deleted revisions of Main Page and Talk:Main Page, with content (mode 1):', - ' api.php?action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&drprop=user|comment|content', - 'List the last 50 deleted contributions by Bob (mode 2):', - ' api.php?action=query&list=deletedrevs&druser=Bob&drlimit=50', - 'List the first 50 deleted revisions in the main namespace (mode 3):', - ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50', - 'List the first 50 deleted pages in the Talk namespace (mode 3):', - ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=1&drunique=', + 'api.php?action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&drprop=user|comment|content' + => 'List the last deleted revisions of Main Page and Talk:Main Page, with content (mode 1)', + 'api.php?action=query&list=deletedrevs&druser=Bob&drlimit=50' + => 'List the last 50 deleted contributions by Bob (mode 2)', + 'api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50' + => 'List the first 50 deleted revisions in the main namespace (mode 3)', + 'api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=1&drunique=' + => 'List the first 50 deleted pages in the Talk namespace (mode 3):', ); } diff --git a/includes/api/ApiQueryDisabled.php b/includes/api/ApiQueryDisabled.php index ab08042a..d68480c3 100644 --- a/includes/api/ApiQueryDisabled.php +++ b/includes/api/ApiQueryDisabled.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API module that does nothing * @@ -46,7 +41,7 @@ class ApiQueryDisabled extends ApiQueryBase { } public function execute() { - $this->setWarning( "The ``{$this->getModuleName()}'' module has been disabled." ); + $this->setWarning( "The \"{$this->getModuleName()}\" module has been disabled." ); } public function getAllowedParams() { @@ -63,7 +58,7 @@ class ApiQueryDisabled extends ApiQueryBase { ); } - protected function getExamples() { + public function getExamples() { return array(); } diff --git a/includes/api/ApiQueryDuplicateFiles.php b/includes/api/ApiQueryDuplicateFiles.php index a68e178d..beca5879 100644 --- a/includes/api/ApiQueryDuplicateFiles.php +++ b/includes/api/ApiQueryDuplicateFiles.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * A query module to list duplicates of the given file(s) * @@ -94,7 +89,8 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase { ); } - $this->addOption( 'ORDER BY', 'i1.img_name' ); + $dir = ( $params['dir'] == 'descending' ? ' DESC' : '' ); + $this->addOption( 'ORDER BY', 'i1.img_name' . $dir ); $this->addOption( 'LIMIT', $params['limit'] + 1 ); $res = $this->select( __METHOD__ ); @@ -141,6 +137,13 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase { ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2 ), 'continue' => null, + 'dir' => array( + ApiBase::PARAM_DFLT => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), ); } @@ -148,6 +151,7 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase { return array( 'limit' => 'How many files to return', 'continue' => 'When more results are available, use this to continue', + 'dir' => 'The direction in which to list', ); } @@ -161,7 +165,7 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&titles=File:Albert_Einstein_Head.jpg&prop=duplicatefiles', 'api.php?action=query&generator=allimages&prop=duplicatefiles', diff --git a/includes/api/ApiQueryExtLinksUsage.php b/includes/api/ApiQueryExtLinksUsage.php index a2b2e318..93c71e2f 100644 --- a/includes/api/ApiQueryExtLinksUsage.php +++ b/includes/api/ApiQueryExtLinksUsage.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * @ingroup API */ @@ -247,7 +242,7 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=exturlusage&euquery=www.mediawiki.org' ); diff --git a/includes/api/ApiQueryExternalLinks.php b/includes/api/ApiQueryExternalLinks.php index 95297628..a9fbc839 100644 --- a/includes/api/ApiQueryExternalLinks.php +++ b/includes/api/ApiQueryExternalLinks.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * A query module to list all external URLs found on a given set of pages. * @@ -148,10 +143,9 @@ class ApiQueryExternalLinks extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Get a list of external links on the [[Main Page]]:', - ' api.php?action=query&prop=extlinks&titles=Main%20Page', + 'api.php?action=query&prop=extlinks&titles=Main%20Page' => 'Get a list of external links on the [[Main Page]]', ); } diff --git a/includes/api/ApiQueryFilearchive.php b/includes/api/ApiQueryFilearchive.php index e746a6c4..be995f30 100644 --- a/includes/api/ApiQueryFilearchive.php +++ b/includes/api/ApiQueryFilearchive.php @@ -26,11 +26,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all deleted files. * @@ -43,9 +38,9 @@ class ApiQueryFilearchive extends ApiQueryBase { } public function execute() { - global $wgUser; + $user = $this->getUser(); // Before doing anything at all, let's check permissions - if ( !$wgUser->isAllowed( 'deletedhistory' ) ) { + if ( !$user->isAllowed( 'deletedhistory' ) ) { $this->dieUsage( 'You don\'t have permission to view deleted file information', 'permissiondenied' ); } @@ -110,7 +105,7 @@ class ApiQueryFilearchive extends ApiQueryBase { } } - if ( !$wgUser->isAllowed( 'suppressrevision' ) ) { + if ( !$user->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 @@ -166,7 +161,7 @@ class ApiQueryFilearchive extends ApiQueryBase { if ( $fld_description ) { $file['description'] = $row->fa_description; if ( isset( $prop['parseddescription'] ) ) { - $file['parseddescription'] = $wgUser->getSkin()->formatComment( + $file['parseddescription'] = Linker::formatComment( $row->fa_description, $title ); } } @@ -285,11 +280,12 @@ class ApiQueryFilearchive extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Simple Use', - ' Show a list of all deleted files', - ' api.php?action=query&list=filearchive', + 'api.php?action=query&list=filearchive' => array( + 'Simple Use', + 'Show a list of all deleted files', + ), ); } diff --git a/includes/api/ApiQueryIWBacklinks.php b/includes/api/ApiQueryIWBacklinks.php index 8b3c8af1..feda1779 100644 --- a/includes/api/ApiQueryIWBacklinks.php +++ b/includes/api/ApiQueryIWBacklinks.php @@ -25,11 +25,6 @@ * @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 @@ -207,7 +202,7 @@ class ApiQueryIWBacklinks extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=iwbacklinks&iwbltitle=Test&iwblprefix=wikibooks', 'api.php?action=query&generator=iwbacklinks&giwbltitle=Test&iwblprefix=wikibooks&prop=info' diff --git a/includes/api/ApiQueryIWLinks.php b/includes/api/ApiQueryIWLinks.php index 30e44ae4..13256ad8 100644 --- a/includes/api/ApiQueryIWLinks.php +++ b/includes/api/ApiQueryIWLinks.php @@ -25,11 +25,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * A query module to list all interwiki links on a page * @@ -79,20 +74,27 @@ class ApiQueryIWLinks extends ApiQueryBase { ); } + $dir = ( $params['dir'] == 'descending' ? ' DESC' : '' ); 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' ); + $this->addOption( 'ORDER BY', 'iwl_from' . $dir ); } else { - $this->addOption( 'ORDER BY', 'iwl_title, iwl_from' ); + $this->addOption( 'ORDER BY', array( + 'iwl_title' . $dir, + 'iwl_from' . $dir + )); } } else { // 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' ); + $this->addOption( 'ORDER BY', 'iwl_prefix' . $dir ); } else { - $this->addOption( 'ORDER BY', 'iwl_from, iwl_prefix' ); + $this->addOption( 'ORDER BY', array ( + 'iwl_from' . $dir, + 'iwl_prefix' . $dir + )); } } @@ -109,7 +111,7 @@ class ApiQueryIWLinks extends ApiQueryBase { } $entry = array( 'prefix' => $row->iwl_prefix ); - if ( !is_null( $params['url'] ) ) { + if ( $params['url'] ) { $title = Title::newFromText( "{$row->iwl_prefix}:{$row->iwl_title}" ); if ( $title ) { $entry['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ); @@ -131,7 +133,7 @@ class ApiQueryIWLinks extends ApiQueryBase { public function getAllowedParams() { return array( - 'url' => null, + 'url' => false, 'limit' => array( ApiBase::PARAM_DFLT => 10, ApiBase::PARAM_TYPE => 'limit', @@ -142,6 +144,13 @@ class ApiQueryIWLinks extends ApiQueryBase { 'continue' => null, 'prefix' => null, 'title' => null, + 'dir' => array( + ApiBase::PARAM_DFLT => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), ); } @@ -152,6 +161,7 @@ class ApiQueryIWLinks extends ApiQueryBase { '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", + 'dir' => 'The direction in which to list', ); } @@ -166,10 +176,9 @@ class ApiQueryIWLinks extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Get interwiki links from the [[Main Page]]:', - ' api.php?action=query&prop=iwlinks&titles=Main%20Page', + 'api.php?action=query&prop=iwlinks&titles=Main%20Page' => 'Get interwiki links from the [[Main Page]]', ); } diff --git a/includes/api/ApiQueryImageInfo.php b/includes/api/ApiQueryImageInfo.php index ab179b9f..03a24821 100644 --- a/includes/api/ApiQueryImageInfo.php +++ b/includes/api/ApiQueryImageInfo.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * A query action to get image information and upload history. * @@ -318,8 +313,7 @@ class ApiQueryImageInfo extends ApiQueryBase { $vals['commenthidden'] = ''; } else { if ( $pcomment ) { - global $wgUser; - $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( + $vals['parsedcomment'] = Linker::formatComment( $file->getDescription(), $file->getTitle() ); } if ( $comment ) { @@ -568,7 +562,7 @@ class ApiQueryImageInfo extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&titles=File:Albert%20Einstein%20Head.jpg&prop=imageinfo', 'api.php?action=query&titles=File:Test.jpg&prop=imageinfo&iilimit=50&iiend=20071231235959&iiprop=timestamp|user|url', diff --git a/includes/api/ApiQueryImages.php b/includes/api/ApiQueryImages.php index 5fbdc895..f03b2874 100644 --- a/includes/api/ApiQueryImages.php +++ b/includes/api/ApiQueryImages.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * This query adds an subelement to all pages with the list of images embedded into those pages. * @@ -79,11 +74,15 @@ class ApiQueryImages extends ApiQueryGeneratorBase { ); } + $dir = ( $params['dir'] == 'descending' ? ' DESC' : '' ); // Don't order by il_from if it's constant in the WHERE clause if ( count( $this->getPageSet()->getGoodTitles() ) == 1 ) { - $this->addOption( 'ORDER BY', 'il_to' ); + $this->addOption( 'ORDER BY', 'il_to' . $dir ); } else { - $this->addOption( 'ORDER BY', 'il_from, il_to' ); + $this->addOption( 'ORDER BY', array( + 'il_from' . $dir, + 'il_to' . $dir + )); } $this->addOption( 'LIMIT', $params['limit'] + 1 ); @@ -92,7 +91,7 @@ class ApiQueryImages extends ApiQueryGeneratorBase { foreach ( $params['images'] as $img ) { $title = Title::newFromText( $img ); if ( !$title || $title->getNamespace() != NS_FILE ) { - $this->setWarning( "``$img'' is not a file" ); + $this->setWarning( "\"$img\" is not a file" ); } else { $images[] = $title->getDBkey(); } @@ -154,7 +153,14 @@ class ApiQueryImages extends ApiQueryGeneratorBase { 'continue' => null, 'images' => array( ApiBase::PARAM_ISMULTI => true, - ) + ), + 'dir' => array( + ApiBase::PARAM_DFLT => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), ); } @@ -163,6 +169,7 @@ class ApiQueryImages extends ApiQueryGeneratorBase { '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.', + 'dir' => 'The direction in which to list', ); } @@ -176,12 +183,10 @@ class ApiQueryImages extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Get a list of images used in the [[Main Page]]:', - ' api.php?action=query&prop=images&titles=Main%20Page', - 'Get information about all images used in the [[Main Page]]:', - ' api.php?action=query&generator=images&titles=Main%20Page&prop=info' + 'api.php?action=query&prop=images&titles=Main%20Page' => 'Get a list of images used in the [[Main Page]]', + 'api.php?action=query&generator=images&titles=Main%20Page&prop=info' => 'Get information about all images used in the [[Main Page]]', ); } diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php index c2f4dc92..f0d0faa3 100644 --- a/includes/api/ApiQueryInfo.php +++ b/includes/api/ApiQueryInfo.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * A query module to show basic page information. * @@ -76,7 +71,7 @@ class ApiQueryInfo extends ApiQueryBase { * Get an array mapping token names to their handler functions. * The prototype for a token function is func($pageid, $title) * it should return a token or false (permission denied) - * @return array(tokenname => function) + * @return array array(tokenname => function) */ protected function getTokenFunctions() { // Don't call the hooks twice @@ -119,7 +114,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedEditToken; } - $cachedEditToken = $wgUser->editToken(); + $cachedEditToken = $wgUser->getEditToken(); return $cachedEditToken; } @@ -134,7 +129,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedDeleteToken; } - $cachedDeleteToken = $wgUser->editToken(); + $cachedDeleteToken = $wgUser->getEditToken(); return $cachedDeleteToken; } @@ -149,7 +144,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedProtectToken; } - $cachedProtectToken = $wgUser->editToken(); + $cachedProtectToken = $wgUser->getEditToken(); return $cachedProtectToken; } @@ -164,7 +159,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedMoveToken; } - $cachedMoveToken = $wgUser->editToken(); + $cachedMoveToken = $wgUser->getEditToken(); return $cachedMoveToken; } @@ -179,7 +174,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedBlockToken; } - $cachedBlockToken = $wgUser->editToken(); + $cachedBlockToken = $wgUser->getEditToken(); return $cachedBlockToken; } @@ -199,7 +194,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedEmailToken; } - $cachedEmailToken = $wgUser->editToken(); + $cachedEmailToken = $wgUser->getEditToken(); return $cachedEmailToken; } @@ -214,7 +209,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedImportToken; } - $cachedImportToken = $wgUser->editToken(); + $cachedImportToken = $wgUser->getEditToken(); return $cachedImportToken; } @@ -229,7 +224,7 @@ class ApiQueryInfo extends ApiQueryBase { return $cachedWatchToken; } - $cachedWatchToken = $wgUser->editToken( 'watch' ); + $cachedWatchToken = $wgUser->getEditToken( 'watch' ); return $cachedWatchToken; } @@ -383,7 +378,7 @@ class ApiQueryInfo extends ApiQueryBase { $pageInfo['fullurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ); $pageInfo['editurl'] = wfExpandUrl( $title->getFullURL( 'action=edit' ), PROTO_CURRENT ); } - if ( $this->fld_readable && $title->userCanRead() ) { + if ( $this->fld_readable && $title->userCan( 'read' ) ) { $pageInfo['readable'] = ''; } @@ -619,9 +614,9 @@ class ApiQueryInfo extends ApiQueryBase { * Get information about watched status and put it in $this->watched */ private function getWatchedInfo() { - global $wgUser; + $user = $this->getUser(); - if ( $wgUser->isAnon() || count( $this->everything ) == 0 ) { + if ( $user->isAnon() || count( $this->everything ) == 0 ) { return; } @@ -635,7 +630,7 @@ class ApiQueryInfo extends ApiQueryBase { $this->addFields( array( 'wl_title', 'wl_namespace' ) ); $this->addWhere( array( $lb->constructSet( 'wl', $db ), - 'wl_user' => $wgUser->getID() + 'wl_user' => $user->getID() ) ); $res = $this->select( __METHOD__ ); @@ -721,7 +716,7 @@ class ApiQueryInfo extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&prop=info&titles=Main%20Page', 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page' diff --git a/includes/api/ApiQueryLangBacklinks.php b/includes/api/ApiQueryLangBacklinks.php index 959ee789..15734944 100644 --- a/includes/api/ApiQueryLangBacklinks.php +++ b/includes/api/ApiQueryLangBacklinks.php @@ -25,11 +25,6 @@ * @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 @@ -207,7 +202,7 @@ class ApiQueryLangBacklinks extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public 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' diff --git a/includes/api/ApiQueryLangLinks.php b/includes/api/ApiQueryLangLinks.php index 942655f4..fdba8465 100644 --- a/includes/api/ApiQueryLangLinks.php +++ b/includes/api/ApiQueryLangLinks.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * A query module to list all langlinks (links to correspanding foreign language pages). * @@ -74,20 +69,27 @@ class ApiQueryLangLinks extends ApiQueryBase { ); } + $dir = ( $params['dir'] == 'descending' ? ' DESC' : '' ); 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' ); + $this->addOption( 'ORDER BY', 'll_from' . $dir ); } else { - $this->addOption( 'ORDER BY', 'll_title, ll_from' ); + $this->addOption( 'ORDER BY', array( + 'll_title' . $dir, + 'll_from' . $dir + )); } } else { // 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' ); + $this->addOption( 'ORDER BY', 'll_lang' . $dir ); } else { - $this->addOption( 'ORDER BY', 'll_from, ll_lang' ); + $this->addOption( 'ORDER BY', array( + 'll_from' . $dir, + 'll_lang' . $dir + )); } } @@ -135,6 +137,13 @@ class ApiQueryLangLinks extends ApiQueryBase { 'url' => false, 'lang' => null, 'title' => null, + 'dir' => array( + ApiBase::PARAM_DFLT => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), ); } @@ -145,6 +154,7 @@ class ApiQueryLangLinks extends ApiQueryBase { 'url' => 'Whether to get the full URL', 'lang' => 'Language code', 'title' => "Link to search for. Must be used with {$this->getModulePrefix()}lang", + 'dir' => 'The direction in which to list', ); } @@ -159,10 +169,9 @@ class ApiQueryLangLinks extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Get interlanguage links from the [[Main Page]]:', - ' api.php?action=query&prop=langlinks&titles=Main%20Page&redirects=', + 'api.php?action=query&prop=langlinks&titles=Main%20Page&redirects=' => 'Get interlanguage links from the [[Main Page]]', ); } diff --git a/includes/api/ApiQueryLinks.php b/includes/api/ApiQueryLinks.php index 55217e2f..0377eddb 100644 --- a/includes/api/ApiQueryLinks.php +++ b/includes/api/ApiQueryLinks.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiQueryBase.php" ); -} - /** * A query module to list all wiki links on a given set of pages. * @@ -48,6 +43,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase { $this->prefix = 'pl'; $this->description = 'link'; $this->titlesParam = 'titles'; + $this->titlesParamDescription = 'Only list links to these titles. Useful for checking whether a certain page links to a certain title.'; $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#links_.2F_pl'; break; case self::TEMPLATES: @@ -55,6 +51,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase { $this->prefix = 'tl'; $this->description = 'template'; $this->titlesParam = 'templates'; + $this->titlesParamDescription = 'Only list these templates. Useful for checking whether a certain page uses a certain template.'; $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#templates_.2F_tl'; break; default: @@ -102,7 +99,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase { foreach ( $params[$this->titlesParam] as $t ) { $title = Title::newFromText( $t ); if ( !$title ) { - $this->setWarning( "``$t'' is not a valid title" ); + $this->setWarning( "\"$t\" is not a valid title" ); } else { $lb->addObj( $title ); } @@ -131,6 +128,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase { ); } + $dir = ( $params['dir'] == 'descending' ? ' DESC' : '' ); // Here's some MySQL craziness going on: if you use WHERE foo='bar' // and later ORDER BY foo MySQL doesn't notice the ORDER BY is pointless // but instead goes and filesorts, because the index for foo was used @@ -138,15 +136,15 @@ class ApiQueryLinks extends ApiQueryGeneratorBase { // clause from the ORDER BY clause $order = array(); if ( count( $this->getPageSet()->getGoodTitles() ) != 1 ) { - $order[] = "{$this->prefix}_from"; + $order[] = $this->prefix . '_from' . $dir; } if ( count( $params['namespace'] ) != 1 ) { - $order[] = "{$this->prefix}_namespace"; + $order[] = $this->prefix . '_namespace' . $dir; } - $order[] = "{$this->prefix}_title"; - $this->addOption( 'ORDER BY', implode( ', ', $order ) ); - $this->addOption( 'USE INDEX', "{$this->prefix}_from" ); + $order[] = $this->prefix . "_title" . $dir; + $this->addOption( 'ORDER BY', $order ); + $this->addOption( 'USE INDEX', $this->prefix . '_from' ); $this->addOption( 'LIMIT', $params['limit'] + 1 ); $res = $this->select( __METHOD__ ); @@ -207,36 +205,38 @@ class ApiQueryLinks extends ApiQueryGeneratorBase { $this->titlesParam => array( ApiBase::PARAM_ISMULTI => true, ), + 'dir' => array( + ApiBase::PARAM_DFLT => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), ); } public function getParamDescription() { $desc = $this->description; - $arr = array( + return array( 'namespace' => "Show {$desc}s in this namespace(s) only", 'limit' => "How many {$desc}s to return", 'continue' => 'When more results are available, use this to continue', + $this->titlesParam => $this->titlesParamDescription, + 'dir' => 'The direction in which to list', ); - 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.'; - } 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; } public function getDescription() { return "Returns all {$this->description}s from the given page(s)"; } - protected function getExamples() { + public function getExamples() { + $desc = $this->description; + $name = $this->getModuleName(); return array( - "Get {$this->description}s from the [[Main Page]]:", - " api.php?action=query&prop={$this->getModuleName()}&titles=Main%20Page", - "Get information about the {$this->description} pages in the [[Main Page]]:", - " api.php?action=query&generator={$this->getModuleName()}&titles=Main%20Page&prop=info", - "Get {$this->description}s from the Main Page in the User and Template namespaces:", - " api.php?action=query&prop={$this->getModuleName()}&titles=Main%20Page&{$this->prefix}namespace=2|10" + "api.php?action=query&prop={$name}&titles=Main%20Page" => "Get {$desc}s from the [[Main Page]]:", + "api.php?action=query&generator={$name}&titles=Main%20Page&prop=info" => "Get information about the {$desc} pages in the [[Main Page]]:", + "api.php?action=query&prop={$name}&titles=Main%20Page&{$this->prefix}namespace=2|10" => "Get {$desc}s from the Main Page in the User and Template namespaces:", ); } diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php index 669ab71f..0d07a254 100644 --- a/includes/api/ApiQueryLogEvents.php +++ b/includes/api/ApiQueryLogEvents.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query action to List the log events, with optional filtering by various parameters. * @@ -202,26 +197,44 @@ class ApiQueryLogEvents extends ApiQueryBase { * @param $ts * @return array */ - public static function addLogParams( $result, &$vals, $params, $type, $action, $ts ) { - $params = explode( "\n", $params ); + public static function addLogParams( $result, &$vals, $params, $type, $action, $ts, $legacy = false ) { switch ( $type ) { case 'move': - if ( isset( $params[0] ) ) { - $title = Title::newFromText( $params[0] ); + if ( $legacy ){ + $targetKey = 0; + $noredirKey = 1; + } else { + $targetKey = '4::target'; + $noredirKey = '5::noredir'; + } + + if ( isset( $params[ $targetKey ] ) ) { + $title = Title::newFromText( $params[ $targetKey ] ); if ( $title ) { $vals2 = array(); ApiQueryBase::addTitleInfo( $vals2, $title, 'new_' ); $vals[$type] = $vals2; } } - if ( isset( $params[1] ) && $params[1] ) { + if ( isset( $params[ $noredirKey ] ) && $params[ $noredirKey ] ) { $vals[$type]['suppressedredirect'] = ''; } $params = null; break; case 'patrol': + if ( $legacy ){ + $cur = 0; + $prev = 1; + $auto = 2; + } else { + $cur = '4::curid'; + $prev = '5::previd'; + $auto = '6::auto'; + } $vals2 = array(); - list( $vals2['cur'], $vals2['prev'], $vals2['auto'] ) = $params; + $vals2['cur'] = $params[$cur]; + $vals2['prev'] = $params[$prev]; + $vals2['auto'] = $params[$auto]; $vals[$type] = $vals2; $params = null; break; @@ -255,6 +268,7 @@ class ApiQueryLogEvents extends ApiQueryBase { } private function extractRowInfo( $row ) { + $logEntry = DatabaseLogEntry::newFromRow( $row ); $vals = array(); if ( $this->fld_ids ) { @@ -286,10 +300,11 @@ class ApiQueryLogEvents extends ApiQueryBase { self::addLogParams( $this->getResult(), $vals, - $row->log_params, - $row->log_type, - $row->log_action, - $row->log_timestamp + $logEntry->getParameters(), + $logEntry->getType(), + $logEntry->getSubtype(), + $logEntry->getTimestamp(), + $logEntry->isLegacy() ); } } @@ -323,8 +338,7 @@ class ApiQueryLogEvents extends ApiQueryBase { } if ( $this->fld_parsedcomment ) { - global $wgUser; - $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->log_comment, $title ); + $vals['parsedcomment'] = Linker::formatComment( $row->log_comment, $title ); } } } @@ -445,7 +459,7 @@ class ApiQueryLogEvents extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=logevents' ); diff --git a/includes/api/ApiQueryPageProps.php b/includes/api/ApiQueryPageProps.php index 56213fa3..1eef67e6 100644 --- a/includes/api/ApiQueryPageProps.php +++ b/includes/api/ApiQueryPageProps.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * A query module to show basic page information. * @@ -142,7 +137,7 @@ class ApiQueryPageProps extends ApiQueryBase { return 'Get various properties defined in the page content'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&prop=pageprops&titles=Category:Foo', ); diff --git a/includes/api/ApiQueryProtectedTitles.php b/includes/api/ApiQueryProtectedTitles.php index ff703cda..44cc1d32 100644 --- a/includes/api/ApiQueryProtectedTitles.php +++ b/includes/api/ApiQueryProtectedTitles.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate all create-protected pages. * @@ -112,8 +107,7 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase { } if ( isset( $prop['parsedcomment'] ) ) { - global $wgUser; - $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->pt_reason, $title ); + $vals['parsedcomment'] = Linker::formatComment( $row->pt_reason, $title ); } if ( isset( $prop['expiry'] ) ) { @@ -224,7 +218,7 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase { return 'List all titles protected from creation'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=protectedtitles', ); diff --git a/includes/api/ApiQueryQueryPage.php b/includes/api/ApiQueryQueryPage.php index b38df6b6..5eba0de6 100644 --- a/includes/api/ApiQueryQueryPage.php +++ b/includes/api/ApiQueryQueryPage.php @@ -24,11 +24,6 @@ * @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 * @@ -73,15 +68,13 @@ class ApiQueryQueryPage extends ApiQueryGeneratorBase { /** * @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 ) ) { + if ( !$qp->userCanExecute( $this->getUser() ) ) { $this->dieUsageMsg( 'specialpage-cantexecute' ); } @@ -98,7 +91,7 @@ class ApiQueryQueryPage extends ApiQueryGeneratorBase { } } $result->addValue( array( 'query' ), $this->getModuleName(), $r ); - + if ( $qp->isCached() && !$qp->isCacheable() ) { // Disabled query page, don't run the query return; @@ -183,10 +176,11 @@ class ApiQueryQueryPage extends ApiQueryGeneratorBase { public function getPossibleErrors() { return array_merge( parent::getPossibleErrors(), array( + array( 'specialpage-cantexecute' ) ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=querypage&qppage=Ancientpages' ); diff --git a/includes/api/ApiQueryRandom.php b/includes/api/ApiQueryRandom.php index dea0b0f5..2e9e2dd5 100644 --- a/includes/api/ApiQueryRandom.php +++ b/includes/api/ApiQueryRandom.php @@ -25,11 +25,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to get list of random pages * @@ -175,7 +170,7 @@ class ApiQueryRandom extends ApiQueryGeneratorBase { ); } - protected function getExamples() { + public function getExamples() { return 'api.php?action=query&list=random&rnnamespace=0&rnlimit=2'; } diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php index 9ce6688e..bf5bbd9b 100644 --- a/includes/api/ApiQueryRecentChanges.php +++ b/includes/api/ApiQueryRecentChanges.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * A query action to enumerate the recent changes that were done to the wiki. * Various filters are supported. @@ -52,7 +47,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { * Get an array mapping token names to their handler functions. * The prototype for a token function is func($pageid, $title, $rc) * it should return a token or false (permission denied) - * @return array(tokenname => function) + * @return array array(tokenname => function) */ protected function getTokenFunctions() { // Don't call the hooks twice @@ -89,7 +84,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { // The patrol token is always the same, let's exploit that static $cachedPatrolToken = null; if ( is_null( $cachedPatrolToken ) ) { - $cachedPatrolToken = $wgUser->editToken( 'patrol' ); + $cachedPatrolToken = $wgUser->getEditToken( 'patrol' ); } return $cachedPatrolToken; @@ -129,7 +124,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { * @param $resultPageSet ApiPageSet */ public function run( $resultPageSet = null ) { - global $wgUser; + $user = $this->getUser(); /* Get the parameters of the request. */ $params = $this->extractRequestParams(); @@ -163,7 +158,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { // Check permissions if ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) { - if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) { + if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) { $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' ); } } @@ -219,7 +214,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { /* Set up internal members based upon params. */ $this->initProperties( $prop ); - if ( $this->fld_patrolled && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) { + if ( $this->fld_patrolled && !$user->useRCPatrol() && !$user->useNPPatrol() ) { $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' ); } @@ -410,8 +405,7 @@ class ApiQueryRecentChanges 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_redirect ) { @@ -633,7 +627,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=recentchanges' ); diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php index 401406bb..fa58bdf0 100644 --- a/includes/api/ApiQueryRevisions.php +++ b/includes/api/ApiQueryRevisions.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * A query action to enumerate revisions of a given page, or show top revisions of multiple pages. * Various pieces of information may be shown - flags, comments, and the actual wiki markup of the rev. @@ -84,8 +79,8 @@ class ApiQueryRevisions extends ApiQueryBase { if ( !$wgUser->isAllowed( 'rollback' ) ) { return false; } - return $wgUser->editToken( array( $title->getPrefixedText(), - $rev->getUserText() ) ); + return $wgUser->getEditToken( + array( $title->getPrefixedText(), $rev->getUserText() ) ); } public function execute() { @@ -159,6 +154,7 @@ class ApiQueryRevisions extends ApiQueryBase { $this->fld_comment = isset ( $prop['comment'] ); $this->fld_parsedcomment = isset ( $prop['parsedcomment'] ); $this->fld_size = isset ( $prop['size'] ); + $this->fld_sha1 = isset ( $prop['sha1'] ); $this->fld_userid = isset( $prop['userid'] ); $this->fld_user = isset ( $prop['user'] ); $this->token = $params['token']; @@ -196,7 +192,7 @@ class ApiQueryRevisions extends ApiQueryBase { if ( isset( $prop['content'] ) || !is_null( $this->difftotext ) ) { // For each page we will request, the user must have read rights for that page foreach ( $pageSet->getGoodTitles() as $title ) { - if ( !$title->userCanRead() ) { + if ( !$title->userCan( 'read' ) ) { $this->dieUsage( 'The current user is not allowed to read ' . $title->getPrefixedText(), 'accessdenied' ); @@ -409,8 +405,20 @@ class ApiQueryRevisions extends ApiQueryBase { $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $revision->getTimestamp() ); } - if ( $this->fld_size && !is_null( $revision->getSize() ) ) { - $vals['size'] = intval( $revision->getSize() ); + if ( $this->fld_size ) { + if ( !is_null( $revision->getSize() ) ) { + $vals['size'] = intval( $revision->getSize() ); + } else { + $vals['size'] = 0; + } + } + + if ( $this->fld_sha1 ) { + if ( $revision->getSha1() != '' ) { + $vals['sha1'] = wfBaseConvert( $revision->getSha1(), 36, 16, 40 ); + } else { + $vals['sha1'] = ''; + } } if ( $this->fld_comment || $this->fld_parsedcomment ) { @@ -424,8 +432,7 @@ class ApiQueryRevisions extends ApiQueryBase { } if ( $this->fld_parsedcomment ) { - global $wgUser; - $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $comment, $title ); + $vals['parsedcomment'] = Linker::formatComment( $comment, $title ); } } } @@ -468,7 +475,7 @@ class ApiQueryRevisions extends ApiQueryBase { } if ( $this->fld_content && !$revision->isDeleted( Revision::DELETED_TEXT ) ) { if ( $this->generateXML ) { - $wgParser->startExternalParse( $title, new ParserOptions(), OT_PREPROCESS ); + $wgParser->startExternalParse( $title, ParserOptions::newFromContext( $this->getContext() ), OT_PREPROCESS ); $dom = $wgParser->preprocessToDom( $text ); if ( is_callable( array( $dom, 'saveXML' ) ) ) { $xml = $dom->saveXML(); @@ -479,10 +486,10 @@ class ApiQueryRevisions extends ApiQueryBase { } if ( $this->expandTemplates && !$this->parseContent ) { - $text = $wgParser->preprocess( $text, $title, new ParserOptions() ); + $text = $wgParser->preprocess( $text, $title, ParserOptions::newFromContext( $this->getContext() ) ); } if ( $this->parseContent ) { - $text = $wgParser->parse( $text, $title, new ParserOptions() )->getText(); + $text = $wgParser->parse( $text, $title, ParserOptions::newFromContext( $this->getContext() ) )->getText(); } ApiResult::setContent( $vals, $text ); } elseif ( $this->fld_content ) { @@ -494,11 +501,13 @@ class ApiQueryRevisions extends ApiQueryBase { static $n = 0; // Number of uncached diffs we've had if ( $n < $wgAPIMaxUncachedDiffs ) { $vals['diff'] = array(); + $context = new DerivativeContext( $this->getContext() ); + $context->setTitle( $title ); if ( !is_null( $this->difftotext ) ) { - $engine = new DifferenceEngine( $title ); + $engine = new DifferenceEngine( $context ); $engine->setText( $text, $this->difftotext ); } else { - $engine = new DifferenceEngine( $title, $revision->getID(), $this->diffto ); + $engine = new DifferenceEngine( $context, $revision->getID(), $this->diffto ); $vals['diff']['from'] = $engine->getOldid(); $vals['diff']['to'] = $engine->getNewid(); } @@ -537,6 +546,7 @@ class ApiQueryRevisions extends ApiQueryBase { 'user', 'userid', 'size', + 'sha1', 'comment', 'parsedcomment', 'content', @@ -599,7 +609,8 @@ class ApiQueryRevisions extends ApiQueryBase { ' timestamp - The timestamp of the revision', ' user - User that made the revision', ' userid - User id of revision creator', - ' size - Length of the revision', + ' size - Length (bytes) of the revision', + ' sha1 - SHA-1 (base 16) of the revision', ' comment - Comment by the user for revision', ' parsedcomment - Parsed comment by the user for the revision', ' content - Text of the revision', @@ -651,15 +662,15 @@ class ApiQueryRevisions extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'Get data with content for the last revision of titles "API" and "Main Page":', + 'Get data with content for the last revision of titles "API" and "Main Page"', ' api.php?action=query&prop=revisions&titles=API|Main%20Page&rvprop=timestamp|user|comment|content', - 'Get last 5 revisions of the "Main Page":', + 'Get last 5 revisions of the "Main Page"', ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment', - 'Get first 5 revisions of the "Main Page":', + 'Get first 5 revisions of the "Main Page"', ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer', - 'Get first 5 revisions of the "Main Page" made after 2006-05-01:', + 'Get first 5 revisions of the "Main Page" made after 2006-05-01', ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer&rvstart=20060501000000', 'Get first 5 revisions of the "Main Page" that were not made made by anonymous user "127.0.0.1"', ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvexcludeuser=127.0.0.1', diff --git a/includes/api/ApiQuerySearch.php b/includes/api/ApiQuerySearch.php index 5c133b7d..40aac050 100644 --- a/includes/api/ApiQuerySearch.php +++ b/includes/api/ApiQuerySearch.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to perform full text search within wiki titles and content * @@ -69,6 +64,9 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { $search->setNamespaces( $params['namespace'] ); $search->showRedirects = $params['redirects']; + $query = $search->transformSearchTerm( $query ); + $query = $search->replacePrefixes( $query ); + // Perform the actual search if ( $what == 'text' ) { $matches = $search->searchText( $query ); @@ -293,7 +291,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=search&srsearch=meaning', 'api.php?action=query&list=search&srwhat=text&srsearch=meaning', diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php index 56743189..e2580ac6 100644 --- a/includes/api/ApiQuerySiteinfo.php +++ b/includes/api/ApiQuerySiteinfo.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * A query action to return meta information about the wiki site. * @@ -43,6 +38,7 @@ class ApiQuerySiteinfo extends ApiQueryBase { public function execute() { $params = $this->extractRequestParams(); $done = array(); + $fit = false; foreach ( $params['prop'] as $p ) { switch ( $p ) { case 'general': @@ -138,6 +134,14 @@ class ApiQuerySiteinfo extends ApiQueryBase { } $data['rights'] = $GLOBALS['wgRightsText']; $data['lang'] = $GLOBALS['wgLanguageCode']; + + $fallbacks = array(); + foreach( $wgContLang->getFallbackLanguages() as $code ) { + $fallbacks[] = array( 'code' => $code ); + } + $data['fallback'] = $fallbacks; + $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' ); + if ( $wgContLang->isRTL() ) { $data['rtl'] = ''; } @@ -256,40 +260,44 @@ class ApiQuerySiteinfo extends ApiQueryBase { } protected function appendInterwikiMap( $property, $filter ) { - $this->resetQueryParams(); - $this->addTables( 'interwiki' ); - $this->addFields( array( 'iw_prefix', 'iw_local', 'iw_url', 'iw_wikiid', 'iw_api' ) ); - + $local = null; if ( $filter === 'local' ) { - $this->addWhere( 'iw_local = 1' ); + $local = 1; } elseif ( $filter === '!local' ) { - $this->addWhere( 'iw_local = 0' ); + $local = 0; } elseif ( $filter ) { ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" ); } - $this->addOption( 'ORDER BY', 'iw_prefix' ); + $params = $this->extractRequestParams(); + $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : ''; - $res = $this->select( __METHOD__ ); + if( $langCode ) { + $langNames = Language::getTranslatedLanguageNames( $langCode ); + } else { + $langNames = Language::getLanguageNames(); + } + $getPrefixes = Interwiki::getAllPrefixes( $local ); $data = array(); - $langNames = Language::getLanguageNames(); - foreach ( $res as $row ) { + + foreach ( $getPrefixes as $row ) { + $prefix = $row['iw_prefix']; $val = array(); - $val['prefix'] = $row->iw_prefix; - if ( $row->iw_local == '1' ) { + $val['prefix'] = $prefix; + if ( $row['iw_local'] == '1' ) { $val['local'] = ''; } - // $val['trans'] = intval( $row->iw_trans ); // should this be exposed? - if ( isset( $langNames[$row->iw_prefix] ) ) { - $val['language'] = $langNames[$row->iw_prefix]; + // $val['trans'] = intval( $row['iw_trans'] ); // should this be exposed? + if ( isset( $langNames[$prefix] ) ) { + $val['language'] = $langNames[$prefix]; } - $val['url'] = wfExpandUrl( $row->iw_url, PROTO_CURRENT ); - if( isset( $row->iw_wikiid ) ) { - $val['wikiid'] = $row->iw_wikiid; + $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; + if( isset( $row['iw_api'] ) ) { + $val['api'] = $row['iw_api']; } $data[] = $val; @@ -467,8 +475,18 @@ class ApiQuerySiteinfo extends ApiQueryBase { } public function appendLanguages( $property ) { + $params = $this->extractRequestParams(); + $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : ''; + + if( $langCode ) { + $langNames = Language::getTranslatedLanguageNames( $langCode ); + } else { + $langNames = Language::getLanguageNames(); + } + $data = array(); - foreach ( Language::getLanguageNames() as $code => $name ) { + + foreach ( $langNames as $code => $name ) { $lang = array( 'code' => $code ); ApiResult::setContent( $lang, $name ); $data[] = $lang; @@ -565,10 +583,12 @@ class ApiQuerySiteinfo extends ApiQueryBase { ), 'showalldb' => false, 'numberingroup' => false, + 'inlanguagecode' => null, ); } public function getParamDescription() { + $p = $this->getModulePrefix(); return array( 'prop' => array( 'Which sysinfo properties to get:', @@ -578,13 +598,13 @@ class ApiQuerySiteinfo extends ApiQueryBase { ' specialpagealiases - List of special page aliases', ' magicwords - List of magic words and their aliases', ' statistics - Returns site statistics', - ' interwikimap - Returns interwiki map (optionally filtered)', + " interwikimap - Returns interwiki map (optionally filtered, (optionally localised by using {$p}inlanguagecode))", ' dbrepllag - Returns database server with the highest replication lag', ' usergroups - Returns user groups and the associated permissions', ' extensions - Returns extensions installed on the wiki', ' 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', + " languages - Returns a list of languages MediaWiki supports (optionally localised by using {$p}inlanguagecode)", ' skins - Returns a list of all enabled skins', ' extensiontags - Returns a list of parser extension tags', ' functionhooks - Returns a list of parser function hooks', @@ -593,6 +613,7 @@ class ApiQuerySiteinfo extends ApiQueryBase { 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map', 'showalldb' => 'List all database servers, not just the one lagging the most', 'numberingroup' => 'Lists the number of users in user groups', + 'inlanguagecode' => 'Language code for localised language names (best effort, use CLDR extension)', ); } @@ -606,7 +627,7 @@ class ApiQuerySiteinfo extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics', 'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local', diff --git a/includes/api/ApiQueryStashImageInfo.php b/includes/api/ApiQueryStashImageInfo.php index b1903025..4501ec58 100644 --- a/includes/api/ApiQueryStashImageInfo.php +++ b/includes/api/ApiQueryStashImageInfo.php @@ -45,6 +45,11 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo { $this->dieUsage( "One of filekey or sessionkey must be supplied", 'nofilekey'); } + // Alias sessionkey to filekey, but give an existing filekey precedence. + if ( !$params['filekey'] && $params['sessionkey'] ) { + $params['filekey'] = $params['sessionkey']; + } + try { $stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash(); @@ -122,7 +127,7 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo { return 'Returns image information for stashed images'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&prop=stashimageinfo&siifilekey=124sd34rsdf567', 'api.php?action=query&prop=stashimageinfo&siifilekey=b34edoe3|bceffd4&siiurlwidth=120&siiprop=url', diff --git a/includes/api/ApiQueryTags.php b/includes/api/ApiQueryTags.php index 4ab0c3d1..12cea1d7 100644 --- a/includes/api/ApiQueryTags.php +++ b/includes/api/ApiQueryTags.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to enumerate change tags. * @@ -178,7 +173,7 @@ class ApiQueryTags extends ApiQueryBase { return 'List change tags'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=tags&tgprop=displayname|description|hitcount' ); diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php index f6a9fe46..8e2f20db 100644 --- a/includes/api/ApiQueryUserContributions.php +++ b/includes/api/ApiQueryUserContributions.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * This query action adds a list of a specified user's contributions to the output. * @@ -146,7 +141,7 @@ class ApiQueryContributions extends ApiQueryBase { // We're after the revision table, and the corresponding page // row for anything we retrieve. We may also need the // recentchanges row and/or tag summary row. - global $wgUser; + $user = $this->getUser(); $tables = array( 'page', 'revision' ); // Order may change $this->addWhere( 'page_id=rev_page' ); @@ -167,7 +162,7 @@ class ApiQueryContributions extends ApiQueryBase { ); } - if ( !$wgUser->isAllowed( 'hideuser' ) ) { + if ( !$user->isAllowed( 'hideuser' ) ) { $this->addWhere( $this->getDB()->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ); } // We only want pages by the specified users. @@ -216,7 +211,7 @@ class ApiQueryContributions extends ApiQueryBase { if ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) || $this->fld_patrolled ) { - if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) { + if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) { $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' ); } @@ -275,6 +270,9 @@ class ApiQueryContributions extends ApiQueryBase { /** * Extract fields from the database row and append them to a result array + * + * @param $row + * @return array */ private function extractRowInfo( $row ) { $vals = array(); @@ -321,8 +319,7 @@ class ApiQueryContributions extends ApiQueryBase { } if ( $this->fld_parsedcomment ) { - global $wgUser; - $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->rev_comment, $title ); + $vals['parsedcomment'] = Linker::formatComment( $row->rev_comment, $title ); } } } @@ -444,7 +441,7 @@ class ApiQueryContributions extends ApiQueryBase { ' tags - Lists tags for the edit', ), '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", ), + "NOTE: if {$p}show=patrolled or {$p}show=!patrolled is set, revisions older than \$wgRCMaxAge ($wgRCMaxAge) won't be shown", ), 'tag' => 'Only list revisions tagged with this tag', 'toponly' => 'Only list changes which are the latest revision', ); @@ -463,7 +460,7 @@ class ApiQueryContributions extends ApiQueryBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=usercontribs&ucuser=YurikBot', 'api.php?action=query&list=usercontribs&ucuserprefix=217.121.114.', diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php index 2411bee9..a0ee227f 100644 --- a/includes/api/ApiQueryUserInfo.php +++ b/includes/api/ApiQueryUserInfo.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to get information about the currently logged-in user * @@ -55,47 +50,48 @@ class ApiQueryUserInfo extends ApiQueryBase { } protected function getCurrentUserInfo() { - global $wgUser, $wgRequest, $wgHiddenPrefs; + global $wgRequest, $wgHiddenPrefs; + $user = $this->getUser(); $result = $this->getResult(); $vals = array(); - $vals['id'] = intval( $wgUser->getId() ); - $vals['name'] = $wgUser->getName(); + $vals['id'] = intval( $user->getId() ); + $vals['name'] = $user->getName(); - if ( $wgUser->isAnon() ) { + if ( $user->isAnon() ) { $vals['anon'] = ''; } if ( isset( $this->prop['blockinfo'] ) ) { - if ( $wgUser->isBlocked() ) { - $vals['blockedby'] = User::whoIs( $wgUser->blockedBy() ); - $vals['blockreason'] = $wgUser->blockedFor(); + if ( $user->isBlocked() ) { + $vals['blockedby'] = User::whoIs( $user->blockedBy() ); + $vals['blockreason'] = $user->blockedFor(); } } - if ( isset( $this->prop['hasmsg'] ) && $wgUser->getNewtalk() ) { + if ( isset( $this->prop['hasmsg'] ) && $user->getNewtalk() ) { $vals['messages'] = ''; } if ( isset( $this->prop['groups'] ) ) { - $autolist = ApiQueryUsers::getAutoGroups( $wgUser ); + $autolist = ApiQueryUsers::getAutoGroups( $user ); - $vals['groups'] = array_merge( $autolist, $wgUser->getGroups() ); + $vals['groups'] = array_merge( $autolist, $user->getGroups() ); $result->setIndexedTagName( $vals['groups'], 'g' ); // even if empty } if ( isset( $this->prop['implicitgroups'] ) ) { - $vals['implicitgroups'] = ApiQueryUsers::getAutoGroups( $wgUser ); + $vals['implicitgroups'] = ApiQueryUsers::getAutoGroups( $user ); $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() ) ); + $vals['rights'] = array_values( array_unique( $user->getRights() ) ); $result->setIndexedTagName( $vals['rights'], 'r' ); // even if empty } if ( isset( $this->prop['changeablegroups'] ) ) { - $vals['changeablegroups'] = $wgUser->changeableGroups(); + $vals['changeablegroups'] = $user->changeableGroups(); $result->setIndexedTagName( $vals['changeablegroups']['add'], 'g' ); $result->setIndexedTagName( $vals['changeablegroups']['remove'], 'g' ); $result->setIndexedTagName( $vals['changeablegroups']['add-self'], 'g' ); @@ -103,17 +99,17 @@ class ApiQueryUserInfo extends ApiQueryBase { } if ( isset( $this->prop['options'] ) ) { - $vals['options'] = $wgUser->getOptions(); + $vals['options'] = $user->getOptions(); } if ( isset( $this->prop['preferencestoken'] ) && is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { - $vals['preferencestoken'] = $wgUser->editToken( '', $this->getMain()->getRequest() ); + $vals['preferencestoken'] = $user->getEditToken( '', $this->getMain()->getRequest() ); } if ( isset( $this->prop['editcount'] ) ) { - $vals['editcount'] = intval( $wgUser->getEditCount() ); + $vals['editcount'] = intval( $user->getEditCount() ); } if ( isset( $this->prop['ratelimits'] ) ) { @@ -121,19 +117,19 @@ class ApiQueryUserInfo extends ApiQueryBase { } if ( isset( $this->prop['realname'] ) && !in_array( 'realname', $wgHiddenPrefs ) ) { - $vals['realname'] = $wgUser->getRealName(); + $vals['realname'] = $user->getRealName(); } if ( isset( $this->prop['email'] ) ) { - $vals['email'] = $wgUser->getEmail(); - $auth = $wgUser->getEmailAuthenticationTimestamp(); + $vals['email'] = $user->getEmail(); + $auth = $user->getEmailAuthenticationTimestamp(); if ( !is_null( $auth ) ) { $vals['emailauthenticated'] = wfTimestamp( TS_ISO_8601, $auth ); } } if ( isset( $this->prop['registrationdate'] ) ) { - $regDate = $wgUser->getRegistration(); + $regDate = $user->getRegistration(); if ( $regDate !== false ) { $vals['registrationdate'] = wfTimestamp( TS_ISO_8601, $regDate ); } @@ -154,25 +150,26 @@ class ApiQueryUserInfo extends ApiQueryBase { } protected function getRateLimits() { - global $wgUser, $wgRateLimits; - if ( !$wgUser->isPingLimitable() ) { + global $wgRateLimits; + $user = $this->getUser(); + if ( !$user->isPingLimitable() ) { return array(); // No limits } // Find out which categories we belong to $categories = array(); - if ( $wgUser->isAnon() ) { + if ( $user->isAnon() ) { $categories[] = 'anon'; } else { $categories[] = 'user'; } - if ( $wgUser->isNewbie() ) { + if ( $user->isNewbie() ) { $categories[] = 'ip'; $categories[] = 'subnet'; - if ( !$wgUser->isAnon() ) + if ( !$user->isAnon() ) $categories[] = 'newbie'; } - $categories = array_merge( $categories, $wgUser->getGroups() ); + $categories = array_merge( $categories, $user->getGroups() ); // Now get the actual limits $retval = array(); @@ -238,7 +235,7 @@ class ApiQueryUserInfo extends ApiQueryBase { return 'Get information about the current user'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&meta=userinfo', 'api.php?action=query&meta=userinfo&uiprop=blockinfo|groups|rights|hasmsg', diff --git a/includes/api/ApiQueryUsers.php b/includes/api/ApiQueryUsers.php index 31437827..31624bdf 100644 --- a/includes/api/ApiQueryUsers.php +++ b/includes/api/ApiQueryUsers.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * Query module to get information about a list of users * @@ -74,7 +69,7 @@ class ApiQueryUsers extends ApiQueryBase { global $wgUser; // Since the permissions check for userrights is non-trivial, // don't bother with it here - return $wgUser->editToken( $user->getName() ); + return $wgUser->getEditToken( $user->getName() ); } public function execute() { @@ -322,7 +317,7 @@ class ApiQueryUsers extends ApiQueryBase { return 'Get information about a list of users'; } - protected function getExamples() { + public function getExamples() { return 'api.php?action=query&list=users&ususers=brion|TimStarling&usprop=groups|editcount|gender'; } diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php index 77ecb90a..ea56fcd9 100644 --- a/includes/api/ApiQueryWatchlist.php +++ b/includes/api/ApiQueryWatchlist.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * This query action allows clients to retrieve a list of recently modified pages * that are part of the logged-in user's watchlist. @@ -159,8 +154,8 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase { // Check permissions. if ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) { - global $wgUser; - if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) { + $user = $this->getUser(); + if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) { $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' ); } } @@ -438,7 +433,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=watchlist', 'api.php?action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment', diff --git a/includes/api/ApiQueryWatchlistRaw.php b/includes/api/ApiQueryWatchlistRaw.php index 126f6d89..506944f0 100644 --- a/includes/api/ApiQueryWatchlistRaw.php +++ b/includes/api/ApiQueryWatchlistRaw.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiQueryBase.php' ); -} - /** * This query action allows clients to retrieve a list of pages * on the logged-in user's watchlist. @@ -197,7 +192,7 @@ class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=query&list=watchlistraw', 'api.php?action=query&generator=watchlistraw&gwrshow=changed&prop=revisions', diff --git a/includes/api/ApiResult.php b/includes/api/ApiResult.php index a8ca6046..798b2275 100644 --- a/includes/api/ApiResult.php +++ b/includes/api/ApiResult.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * This class represents the result of the API operations. * It simply wraps a nested array() structure, adding some functions to simplify array's modifications. @@ -246,11 +241,12 @@ class ApiResult extends ApiBase { /** * Add value to the output data at the given path. - * 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 + * Path can be 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 $path is null, the value will be inserted at the data root. + * If $name is empty, the $value is added as a next list element data[] = $value. * - * @param $path + * @param $path array|string|null * @param $name string * @param $value mixed * @param $overwrite bool @@ -259,6 +255,7 @@ class ApiResult extends ApiBase { */ public function addValue( $path, $name, $value, $overwrite = false ) { global $wgAPIMaxResultSize; + $data = &$this->mData; if ( $this->mCheckingSize ) { $newsize = $this->mSize + self::size( $value ); diff --git a/includes/api/ApiRollback.php b/includes/api/ApiRollback.php index 154e5dfb..436c392b 100644 --- a/includes/api/ApiRollback.php +++ b/includes/api/ApiRollback.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -52,11 +47,11 @@ class ApiRollback extends ApiBase { $params = $this->extractRequestParams(); // User and title already validated in call to getTokenSalt from Main - $titleObj = $this->getTitle(); - $articleObj = new Article( $titleObj ); + $titleObj = $this->getRbTitle(); + $pageObj = WikiPage::factory( $titleObj ); $summary = ( isset( $params['summary'] ) ? $params['summary'] : '' ); $details = array(); - $retval = $articleObj->doRollback( $this->getUser(), $summary, $params['token'], $params['markbot'], $details ); + $retval = $pageObj->doRollback( $this->getRbUser(), $summary, $params['token'], $params['markbot'], $details, $this->getUser() ); if ( $retval ) { // We don't care about multiple errors, just report one of them @@ -141,10 +136,10 @@ class ApiRollback extends ApiBase { } public function getTokenSalt() { - return array( $this->getTitle()->getPrefixedText(), $this->getUser() ); + return array( $this->getRbTitle()->getPrefixedText(), $this->getRbUser() ); } - private function getUser() { + private function getRbUser() { if ( $this->mUser !== null ) { return $this->mUser; } @@ -165,7 +160,7 @@ class ApiRollback extends ApiBase { /** * @return Title */ - private function getTitle() { + private function getRbTitle() { if ( $this->mTitleObj !== null ) { return $this->mTitleObj; } @@ -184,7 +179,7 @@ class ApiRollback extends ApiBase { return $this->mTitleObj; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=rollback&title=Main%20Page&user=Catrope&token=123ABC', 'api.php?action=rollback&title=Main%20Page&user=217.121.114.116&token=123ABC&summary=Reverting%20vandalism&markbot=1' diff --git a/includes/api/ApiRsd.php b/includes/api/ApiRsd.php index e4410379..f0e1fad6 100644 --- a/includes/api/ApiRsd.php +++ b/includes/api/ApiRsd.php @@ -25,10 +25,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - require_once( 'ApiBase.php' ); -} - /** * API module for sending out RSD information * @ingroup API @@ -71,7 +67,7 @@ class ApiRsd extends ApiBase { return 'Export an RSD (Really Simple Discovery) schema'; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=rsd' ); diff --git a/includes/api/ApiUnblock.php b/includes/api/ApiUnblock.php index 9c3bcf69..db94fd5b 100644 --- a/includes/api/ApiUnblock.php +++ b/includes/api/ApiUnblock.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * API module that facilitates the unblocking of users. Requires API write mode * to be enabled. @@ -45,11 +40,11 @@ class ApiUnblock extends ApiBase { * Unblocks the specified user or provides the reason the unblock failed. */ public function execute() { - global $wgUser; + $user = $this->getUser(); $params = $this->extractRequestParams(); if ( $params['gettoken'] ) { - $res['unblocktoken'] = $wgUser->editToken( '', $this->getMain()->getRequest() ); + $res['unblocktoken'] = $user->getEditToken( '', $this->getMain()->getRequest() ); $this->getResult()->addValue( null, $this->getModuleName(), $res ); return; } @@ -61,12 +56,12 @@ class ApiUnblock extends ApiBase { $this->dieUsageMsg( 'unblock-idanduser' ); } - if ( !$wgUser->isAllowed( 'block' ) ) { + if ( !$user->isAllowed( 'block' ) ) { $this->dieUsageMsg( 'cantunblock' ); } # bug 15810: blocked admins should have limited access here - if ( $wgUser->isBlocked() ) { - $status = SpecialBlock::checkUnblockSelf( $params['user'] ); + if ( $user->isBlocked() ) { + $status = SpecialBlock::checkUnblockSelf( $params['user'], $user ); if ( $status !== true ) { $this->dieUsageMsg( $status ); } @@ -77,7 +72,7 @@ class ApiUnblock extends ApiBase { 'Reason' => is_null( $params['reason'] ) ? '' : $params['reason'] ); $block = Block::newFromTarget( $data['Target'] ); - $retval = SpecialUnblock::processUnblock( $data ); + $retval = SpecialUnblock::processUnblock( $data, $this->getContext() ); if ( $retval !== true ) { $this->dieUsageMsg( $retval[0] ); } @@ -141,7 +136,7 @@ class ApiUnblock extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=unblock&id=105', 'api.php?action=unblock&user=Bob&reason=Sorry%20Bob' diff --git a/includes/api/ApiUndelete.php b/includes/api/ApiUndelete.php index 2be70108..d3429972 100644 --- a/includes/api/ApiUndelete.php +++ b/includes/api/ApiUndelete.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -39,14 +34,13 @@ class ApiUndelete extends ApiBase { } public function execute() { - global $wgUser; $params = $this->extractRequestParams(); - if ( !$wgUser->isAllowed( 'undelete' ) ) { + if ( !$this->getUser()->isAllowed( 'undelete' ) ) { $this->dieUsageMsg( 'permdenied-undelete' ); } - if ( $wgUser->isBlocked() ) { + if ( $this->getUser()->isBlocked() ) { $this->dieUsageMsg( 'blockedtext' ); } @@ -74,7 +68,7 @@ class ApiUndelete extends ApiBase { if ( $retval[1] ) { wfRunHooks( 'FileUndeleteComplete', - array( $titleObj, array(), $wgUser, $params['reason'] ) ); + array( $titleObj, array(), $this->getUser(), $params['reason'] ) ); } $this->setWatch( $params['watchlist'], $titleObj ); @@ -152,7 +146,7 @@ class ApiUndelete extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=undelete&title=Main%20Page&token=123ABC&reason=Restoring%20main%20page', 'api.php?action=undelete&title=Main%20Page&token=123ABC×tamps=20070703220045|20070702194856' diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php index e9598378..fdc1eff0 100644 --- a/includes/api/ApiUpload.php +++ b/includes/api/ApiUpload.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -46,18 +41,19 @@ class ApiUpload extends ApiBase { } public function execute() { - global $wgUser; - // Check whether upload is enabled if ( !UploadBase::isEnabled() ) { $this->dieUsageMsg( 'uploaddisabled' ); } + $user = $this->getUser(); + // Parameter handling $this->mParams = $this->extractRequestParams(); $request = $this->getMain()->getRequest(); // Add the uploaded file to the params array $this->mParams['file'] = $request->getFileName( 'file' ); + $this->mParams['chunk'] = $request->getFileName( 'chunk' ); // Copy the session key to the file key, for backward compatibility. if( !$this->mParams['filekey'] && $this->mParams['sessionkey'] ) { @@ -74,7 +70,7 @@ class ApiUpload extends ApiBase { } // First check permission to upload - $this->checkPermissions( $wgUser ); + $this->checkPermissions( $user ); // Fetch the file $status = $this->mUpload->fetchFile(); @@ -85,49 +81,26 @@ class ApiUpload extends ApiBase { } // Check if the uploaded file is sane - $this->verifyUpload(); - - + if ( $this->mParams['chunk'] ) { + $maxSize = $this->mUpload->getMaxUploadSize( ); + if( $this->mParams['filesize'] > $maxSize ) { + $this->dieUsage( 'The file you submitted was too large', 'file-too-large' ); + } + } else { + $this->verifyUpload(); + } + // 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 ); + $permErrors = $this->mUpload->verifyTitlePermissions( $user ); if ( $permErrors !== true ) { $this->dieRecoverableError( $permErrors[0], 'filename' ); } } - - // Prepare the API result - $result = array(); - - $warnings = $this->getApiWarnings(); - 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['filekey'] = $this->performStash(); - $result['sessionkey'] = $result['filekey']; // backwards compatibility - } catch ( MWException $e ) { - $result['warnings']['stashfailed'] = $e->getMessage(); - } - } 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['filekey'] = $this->performStash(); - $result['sessionkey'] = $result['filekey']; // backwards compatibility - } catch ( MWException $e ) { - $this->dieUsage( $e->getMessage(), 'stashfailed' ); - } - } else { - // This is the most common case -- a normal upload with no warnings - // $result will be formatted properly for the API already, with a status - $result = $this->performUpload(); - } + // Get the result based on the current upload context: + $result = $this->getContextResult(); if ( $result['result'] === 'Success' ) { $result['imageinfo'] = $this->mUpload->getImageInfo( $this->getResult() ); @@ -138,7 +111,93 @@ class ApiUpload extends ApiBase { // Cleanup any temporary mess $this->mUpload->cleanupTempFile(); } - + /** + * Get an uplaod result based on upload context + */ + private function getContextResult(){ + $warnings = $this->getApiWarnings(); + if ( $warnings ) { + // Get warnings formated in result array format + return $this->getWarningsResult( $warnings ); + } elseif ( $this->mParams['chunk'] ) { + // Add chunk, and get result + return $this->getChunkResult(); + } elseif ( $this->mParams['stash'] ) { + // Stash the file and get stash result + return $this->getStashResult(); + } + // This is the most common case -- a normal upload with no warnings + // performUpload will return a formatted properly for the API with status + return $this->performUpload(); + } + /** + * Get Stash Result, throws an expetion if the file could not be stashed. + */ + private function getStashResult(){ + $result = array (); + // 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['filekey'] = $this->performStash(); + $result['sessionkey'] = $result['filekey']; // backwards compatibility + } catch ( MWException $e ) { + $this->dieUsage( $e->getMessage(), 'stashfailed' ); + } + return $result; + } + /** + * Get Warnings Result + * @param $warnings Array of Api upload warnings + */ + private function getWarningsResult( $warnings ){ + $result = array(); + $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['filekey'] = $this->performStash(); + $result['sessionkey'] = $result['filekey']; // backwards compatibility + } catch ( MWException $e ) { + $result['warnings']['stashfailed'] = $e->getMessage(); + } + return $result; + } + /** + * Get the result of a chunk upload. + */ + private function getChunkResult(){ + $result = array(); + + $result['result'] = 'Continue'; + $request = $this->getMain()->getRequest(); + $chunkPath = $request->getFileTempname( 'chunk' ); + $chunkSize = $request->getUpload( 'chunk' )->getSize(); + if ($this->mParams['offset'] == 0) { + $result['filekey'] = $this->performStash(); + } else { + $status = $this->mUpload->addChunk($chunkPath, $chunkSize, + $this->mParams['offset']); + if ( !$status->isGood() ) { + $this->dieUsage( $status->getWikiText(), 'stashfailed' ); + return ; + } + $result['filekey'] = $this->mParams['filekey']; + // Check we added the last chunk: + if( $this->mParams['offset'] + $chunkSize == $this->mParams['filesize'] ) { + $status = $this->mUpload->concatenateChunks(); + if ( !$status->isGood() ) { + $this->dieUsage( $status->getWikiText(), 'stashfailed' ); + return ; + } + $result['result'] = 'Success'; + } + } + $result['offset'] = $this->mParams['offset'] + $chunkSize; + return $result; + } + /** * Stash the file and return the file key * Also re-raises exceptions with slightly more informative message strings (useful for API) @@ -147,7 +206,12 @@ class ApiUpload extends ApiBase { */ function performStash() { try { - $fileKey = $this->mUpload->stashFile()->getFileKey(); + $stashFile = $this->mUpload->stashFile(); + + if ( !$stashFile ) { + throw new MWException( 'Invalid stashed file' ); + } + $fileKey = $stashFile->getFileKey(); } catch ( MWException $e ) { $message = 'Stashing temporary file failed: ' . get_class( $e ) . ' ' . $e->getMessage(); wfDebug( __METHOD__ . ' ' . $message . "\n"); @@ -188,9 +252,11 @@ class ApiUpload extends ApiBase { protected function selectUploadModule() { $request = $this->getMain()->getRequest(); - // One and only one of the following parameters is needed - $this->requireOnlyOneParameter( $this->mParams, - 'filekey', 'file', 'url', 'statuskey' ); + // chunk or one and only one of the following parameters is needed + if( !$this->mParams['chunk'] ) { + $this->requireOnlyOneParameter( $this->mParams, + 'filekey', 'file', 'url', 'statuskey' ); + } if ( $this->mParams['statuskey'] ) { $this->checkAsyncDownloadEnabled(); @@ -214,17 +280,32 @@ class ApiUpload extends ApiBase { $this->dieUsageMsg( array( 'missingparam', 'filename' ) ); } - if ( $this->mParams['filekey'] ) { + if ( $this->mParams['chunk'] ) { + // Chunk upload + $this->mUpload = new UploadFromChunks(); + if( isset( $this->mParams['filekey'] ) ){ + // handle new chunk + $this->mUpload->continueChunks( + $this->mParams['filename'], + $this->mParams['filekey'], + $request->getUpload( 'chunk' ) + ); + } else { + // handle first chunk + $this->mUpload->initialize( + $this->mParams['filename'], + $request->getUpload( 'chunk' ) + ); + } + } elseif ( isset( $this->mParams['filekey'] ) ) { // Upload stashed in a previous request if ( !UploadFromStash::isValidKey( $this->mParams['filekey'] ) ) { $this->dieUsageMsg( 'invalid-file-key' ); } - // 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'] ); + $this->mUpload = new UploadFromStash( $this->getUser() ); + $this->mUpload->initialize( $this->mParams['filekey'], $this->mParams['filename'] ); } elseif ( isset( $this->mParams['file'] ) ) { $this->mUpload = new UploadFromFile(); $this->mUpload->initialize( @@ -255,7 +336,6 @@ class ApiUpload extends ApiBase { $this->mUpload = new UploadFromUrl; $this->mUpload->initialize( $this->mParams['filename'], $this->mParams['url'], $async ); - } return true; @@ -300,6 +380,9 @@ class ApiUpload extends ApiBase { $this->dieRecoverableError( 'illegal-filename', 'filename', array( 'filename' => $verification['filtered'] ) ); break; + case UploadBase::FILENAME_TOO_LONG: + $this->dieRecoverableError( 'filename-toolong', 'filename' ); + break; case UploadBase::FILETYPE_MISSING: $this->dieRecoverableError( 'filetype-missing', 'filename' ); break; @@ -383,10 +466,10 @@ class ApiUpload extends ApiBase { /** * Perform the actual upload. Returns a suitable result array on success; * dies on failure. + * + * @return array */ protected function performUpload() { - global $wgUser; - // Use comment as initial page text by default if ( is_null( $this->mParams['text'] ) ) { $this->mParams['text'] = $this->mParams['comment']; @@ -402,7 +485,7 @@ class ApiUpload extends ApiBase { // No errors, no warnings: do the upload $status = $this->mUpload->performUpload( $this->mParams['comment'], - $this->mParams['text'], $watch, $wgUser ); + $this->mParams['text'], $watch, $this->getUser() ); if ( !$status->isGood() ) { $error = $status->getErrorsArray(); @@ -479,6 +562,10 @@ class ApiUpload extends ApiBase { ), 'stash' => false, + 'filesize' => null, + 'offset' => null, + 'chunk' => null, + 'asyncdownload' => false, 'leavemessage' => false, 'statuskey' => null, @@ -497,11 +584,15 @@ class ApiUpload extends ApiBase { 'watchlist' => 'Unconditionally add or remove the page from your watchlist, use preferences or do not change watch', 'ignorewarnings' => 'Ignore any warnings', 'file' => 'File contents', - 'url' => 'Url to fetch the file from', + 'url' => 'URL to fetch the file from', '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.', + 'chunk' => 'Chunk contents', + 'offset' => 'Offset of chunk in bytes', + 'filesize' => 'Filesize of entire upload', + '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', @@ -552,12 +643,12 @@ class ApiUpload extends ApiBase { return ''; } - protected function getExamples() { + public function getExamples() { return array( - '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&filekey=filekey&ignorewarnings=1', + 'api.php?action=upload&filename=Wiki.png&url=http%3A//upload.wikimedia.org/wikipedia/en/b/bc/Wiki.png' + => 'Upload from a URL', + 'api.php?action=upload&filename=Wiki.png&filekey=filekey&ignorewarnings=1' + => 'Complete an upload that failed due to warnings', ); } diff --git a/includes/api/ApiUserrights.php b/includes/api/ApiUserrights.php index 74948ce0..191dd3ec 100644 --- a/includes/api/ApiUserrights.php +++ b/includes/api/ApiUserrights.php @@ -25,11 +25,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( "ApiBase.php" ); -} - /** * @ingroup API */ @@ -44,7 +39,7 @@ class ApiUserrights extends ApiBase { public function execute() { $params = $this->extractRequestParams(); - $user = $this->getUser(); + $user = $this->getUrUser(); $form = new UserrightsPage; $r['user'] = $user->getName(); @@ -62,7 +57,7 @@ class ApiUserrights extends ApiBase { /** * @return User */ - private function getUser() { + private function getUrUser() { if ( $this->mUser !== null ) { return $this->mUser; } @@ -130,10 +125,10 @@ class ApiUserrights extends ApiBase { } public function getTokenSalt() { - return $this->getUser()->getName(); + return $this->getUrUser()->getName(); } - protected function getExamples() { + public function getExamples() { return array( 'api.php?action=userrights&user=FooBot&add=bot&remove=sysop|bureaucrat&token=123ABC' ); diff --git a/includes/api/ApiWatch.php b/includes/api/ApiWatch.php index 27846ab7..fa382b3b 100644 --- a/includes/api/ApiWatch.php +++ b/includes/api/ApiWatch.php @@ -24,11 +24,6 @@ * @file */ -if ( !defined( 'MEDIAWIKI' ) ) { - // Eclipse helper - will be ignored in production - require_once( 'ApiBase.php' ); -} - /** * API module to allow users to watch a page * @@ -41,8 +36,8 @@ class ApiWatch extends ApiBase { } public function execute() { - global $wgUser; - if ( !$wgUser->isLoggedIn() ) { + $user = $this->getUser(); + if ( !$user->isLoggedIn() ) { $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' ); } @@ -53,17 +48,16 @@ class ApiWatch extends ApiBase { $this->dieUsageMsg( array( 'invalidtitle', $params['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 = WatchAction::doUnwatch( $title, $wgUser ); + $res['message'] = $this->msg( 'removedwatchtext', $title->getPrefixedText() )->title( $title )->parseAsBlock(); + $success = UnwatchAction::doUnwatch( $title, $user ); } else { $res['watched'] = ''; - $res['message'] = wfMsgExt( 'addedwatchtext', array( 'parse' ), $title->getPrefixedText() ); - $success = UnwatchAction::doWatch( $title, $wgUser ); + $res['message'] = $this->msg( 'addedwatchtext', $title->getPrefixedText() )->title( $title )->parseAsBlock(); + $success = WatchAction::doWatch( $title, $user ); } if ( !$success ) { $this->dieUsageMsg( 'hookaborted' ); @@ -118,10 +112,10 @@ class ApiWatch extends ApiBase { ) ); } - protected function getExamples() { + public function getExamples() { return array( - 'api.php?action=watch&title=Main_Page', - 'api.php?action=watch&title=Main_Page&unwatch=', + 'api.php?action=watch&title=Main_Page' => 'Watch the page "Main Page"', + 'api.php?action=watch&title=Main_Page&unwatch=' => 'Unwatch the page "Main Page"', ); } -- cgit v1.2.2