summaryrefslogtreecommitdiff
path: root/includes/api
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2008-03-21 11:49:34 +0100
committerPierre Schmitz <pierre@archlinux.de>2008-03-21 11:49:34 +0100
commit086ae52d12011746a75f5588e877347bc0457352 (patch)
treee73263c7a29d0f94fafb874562610e16eb292ba8 /includes/api
parent749e7fb2bae7bbda855de3c9e319435b9f698ff7 (diff)
Update auf MediaWiki 1.12.0
Diffstat (limited to 'includes/api')
-rw-r--r--includes/api/ApiBase.php186
-rw-r--r--includes/api/ApiBlock.php164
-rw-r--r--includes/api/ApiChangeRights.php155
-rw-r--r--includes/api/ApiDelete.php155
-rw-r--r--includes/api/ApiExpandTemplates.php97
-rw-r--r--includes/api/ApiFeedWatchlist.php29
-rw-r--r--includes/api/ApiFormatBase.php52
-rw-r--r--includes/api/ApiFormatDbg.php59
-rw-r--r--includes/api/ApiFormatJson.php8
-rw-r--r--includes/api/ApiFormatPhp.php4
-rw-r--r--includes/api/ApiFormatTxt.php59
-rw-r--r--includes/api/ApiFormatWddx.php4
-rw-r--r--includes/api/ApiFormatXml.php4
-rw-r--r--includes/api/ApiFormatYaml.php4
-rw-r--r--includes/api/ApiFormatYaml_spyc.php14
-rw-r--r--includes/api/ApiHelp.php8
-rw-r--r--includes/api/ApiLogin.php22
-rw-r--r--includes/api/ApiLogout.php71
-rw-r--r--includes/api/ApiMain.php112
-rw-r--r--includes/api/ApiMove.php152
-rw-r--r--includes/api/ApiOpenSearch.php51
-rw-r--r--includes/api/ApiParamInfo.php167
-rw-r--r--includes/api/ApiParse.php202
-rw-r--r--includes/api/ApiProtect.php154
-rw-r--r--includes/api/ApiQuery.php26
-rw-r--r--includes/api/ApiQueryAllCategories.php142
-rw-r--r--includes/api/ApiQueryAllLinks.php8
-rw-r--r--includes/api/ApiQueryAllUsers.php17
-rw-r--r--includes/api/ApiQueryAllmessages.php129
-rw-r--r--includes/api/ApiQueryAllpages.php48
-rw-r--r--includes/api/ApiQueryBacklinks.php10
-rw-r--r--includes/api/ApiQueryBase.php7
-rw-r--r--includes/api/ApiQueryBlocks.php239
-rw-r--r--includes/api/ApiQueryCategories.php8
-rw-r--r--includes/api/ApiQueryCategoryMembers.php61
-rw-r--r--includes/api/ApiQueryDeletedrevs.php235
-rw-r--r--includes/api/ApiQueryExtLinksUsage.php8
-rw-r--r--includes/api/ApiQueryExternalLinks.php4
-rw-r--r--includes/api/ApiQueryImageInfo.php170
-rw-r--r--includes/api/ApiQueryImages.php4
-rw-r--r--includes/api/ApiQueryInfo.php113
-rw-r--r--includes/api/ApiQueryLangLinks.php4
-rw-r--r--includes/api/ApiQueryLinks.php8
-rw-r--r--includes/api/ApiQueryLogEvents.php9
-rw-r--r--includes/api/ApiQueryRandom.php157
-rw-r--r--includes/api/ApiQueryRecentChanges.php110
-rw-r--r--includes/api/ApiQueryRevisions.php77
-rw-r--r--includes/api/ApiQuerySearch.php8
-rw-r--r--includes/api/ApiQuerySiteinfo.php39
-rw-r--r--includes/api/ApiQueryUserContributions.php36
-rw-r--r--includes/api/ApiQueryUserInfo.php138
-rw-r--r--includes/api/ApiQueryUsers.php162
-rw-r--r--includes/api/ApiQueryWatchlist.php50
-rw-r--r--includes/api/ApiResult.php45
-rw-r--r--includes/api/ApiRollback.php128
-rw-r--r--includes/api/ApiUnblock.php124
-rw-r--r--includes/api/ApiUndelete.php123
57 files changed, 4013 insertions, 367 deletions
diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php
index b324c52f..3a7b5099 100644
--- a/includes/api/ApiBase.php
+++ b/includes/api/ApiBase.php
@@ -63,12 +63,36 @@ abstract class ApiBase {
$this->mModulePrefix = $modulePrefix;
}
- /**
- * Executes this module
+ /*****************************************************************************
+ * ABSTRACT METHODS *
+ *****************************************************************************/
+
+ /**
+ * Evaluates the parameters, performs the requested query, and sets up the
+ * result. Concrete implementations of ApiBase must override this method to
+ * provide whatever functionality their module offers. Implementations must
+ * not produce any output on their own and are not expected to handle any
+ * errors.
+ *
+ * The execute method will be invoked directly by ApiMain immediately before
+ * the result of the module is output. Aside from the constructor, implementations
+ * should assume that no other methods will be called externally on the module
+ * before the result is processed.
+ *
+ * The result data should be stored in the result object referred to by
+ * "getResult()". Refer to ApiResult.php for details on populating a result
+ * object.
*/
public abstract function execute();
/**
+ * Returns a String that identifies the version of the extending class. Typically
+ * includes the class name, the svn revision, timestamp, and last author. May
+ * be severely incorrect in many implementations!
+ */
+ public abstract function getVersion();
+
+ /**
* Get the name of the module being executed by this instance
*/
public function getModuleName() {
@@ -100,14 +124,16 @@ abstract class ApiBase {
}
/**
- * If this module's $this is the same as $this->mMainModule, its the root, otherwise no
+ * Returns true if this module is the main module ($this === $this->mMainModule),
+ * false otherwise.
*/
public function isMain() {
return $this === $this->mMainModule;
}
/**
- * Get result object
+ * Get the result object. Please refer to the documentation in ApiResult.php
+ * for details on populating and accessing data in a result object.
*/
public function getResult() {
// Main module has getResult() method overriden
@@ -125,7 +151,8 @@ abstract class ApiBase {
}
/**
- * Set warning section for this module. Users should monitor this section to notice any changes in API.
+ * Set warning section for this module. Users should monitor this section to
+ * notice any changes in API.
*/
public function setWarning($warning) {
$msg = array();
@@ -196,6 +223,10 @@ abstract class ApiBase {
return $msg;
}
+ /**
+ * Generates the parameter descriptions for this module, to be displayed in the
+ * module's help.
+ */
public function makeHelpMsgParameters() {
$params = $this->getAllowedParams();
if ($params !== false) {
@@ -208,7 +239,7 @@ abstract class ApiBase {
if (is_array($desc))
$desc = implode($paramPrefix, $desc);
- @ $type = $paramSettings[self :: PARAM_TYPE];
+ $type = $paramSettings[self :: PARAM_TYPE];
if (isset ($type)) {
if (isset ($paramSettings[self :: PARAM_ISMULTI]))
$prompt = 'Values (separate with \'|\'): ';
@@ -303,13 +334,15 @@ abstract class ApiBase {
* Using getAllowedParams(), makes an array of the values provided by the user,
* with key being the name of the variable, and value - validated value from user or default.
* This method can be used to generate local variables using extract().
+ * limit=max will not be parsed if $parseMaxLimit is set to false; use this
+ * when the max limit is not definite, e.g. when getting revisions.
*/
- public function extractRequestParams() {
+ public function extractRequestParams($parseMaxLimit = true) {
$params = $this->getAllowedParams();
$results = array ();
foreach ($params as $paramName => $paramSettings)
- $results[$paramName] = $this->getParameterFromSettings($paramName, $paramSettings);
+ $results[$paramName] = $this->getParameterFromSettings($paramName, $paramSettings, $parseMaxLimit);
return $results;
}
@@ -323,6 +356,10 @@ abstract class ApiBase {
return $this->getParameterFromSettings($paramName, $paramSettings);
}
+ /**
+ * Returns an array of the namespaces (by integer id) that exist on the
+ * wiki. Used primarily in help documentation.
+ */
public static function getValidNamespaces() {
static $mValidNamespaces = null;
if (is_null($mValidNamespaces)) {
@@ -339,10 +376,12 @@ abstract class ApiBase {
/**
* Using the settings determine the value for the given parameter
+ *
* @param $paramName String: parameter name
* @param $paramSettings Mixed: default value or an array of settings using PARAM_* constants.
+ * @param $parseMaxLimit Boolean: parse limit when max is given?
*/
- protected function getParameterFromSettings($paramName, $paramSettings) {
+ protected function getParameterFromSettings($paramName, $paramSettings, $parseMaxLimit) {
// Some classes may decide to change parameter names
$encParamName = $this->encodeParamName($paramName);
@@ -410,8 +449,17 @@ abstract class ApiBase {
if ($multi)
ApiBase :: dieDebug(__METHOD__, "Multi-values not supported for $encParamName");
$min = isset ($paramSettings[self :: PARAM_MIN]) ? $paramSettings[self :: PARAM_MIN] : 0;
- $value = intval($value);
- $this->validateLimit($paramName, $value, $min, $paramSettings[self :: PARAM_MAX], $paramSettings[self :: PARAM_MAX2]);
+ if( $value == 'max' ) {
+ if( $parseMaxLimit ) {
+ $value = $this->getMain()->canApiHighLimits() ? $paramSettings[self :: PARAM_MAX2] : $paramSettings[self :: PARAM_MAX];
+ $this->getResult()->addValue( 'limits', $this->getModuleName(), $value );
+ $this->validateLimit($paramName, $value, $min, $paramSettings[self :: PARAM_MAX], $paramSettings[self :: PARAM_MAX2]);
+ }
+ }
+ else {
+ $value = intval($value);
+ $this->validateLimit($paramName, $value, $min, $paramSettings[self :: PARAM_MAX], $paramSettings[self :: PARAM_MAX2]);
+ }
break;
case 'boolean' :
if ($multi)
@@ -485,7 +533,7 @@ abstract class ApiBase {
// Optimization: do not check user's bot status unless really needed -- skips db query
// assumes $botMax >= $max
if (!is_null($max) && $value > $max) {
- if (!is_null($botMax) && ($this->getMain()->isBot() || $this->getMain()->isSysop())) {
+ if (!is_null($botMax) && $this->getMain()->canApiHighLimits()) {
if ($value > $botMax) {
$this->dieUsage($this->encodeParamName($paramName) . " may not be over $botMax (set to $value) for bots or sysops", $paramName);
}
@@ -501,6 +549,90 @@ abstract class ApiBase {
public function dieUsage($description, $errorCode, $httpRespCode = 0) {
throw new UsageException($description, $this->encodeParamName($errorCode), $httpRespCode);
}
+
+ /**
+ * Array that maps message keys to error messages. $1 and friends are replaced.
+ */
+ public static $messageMap = array(
+ // This one MUST be present, or dieUsageMsg() will recurse infinitely
+ '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"),
+ 'customcssjsprotected' => array('code' => 'customcssjsprotected', 'info' => "You're not allowed to edit custom CSS and JavaScript pages"),
+ 'cascadeprotected' => array('code' => 'cascadeprotected', 'info' =>"The page you're trying to edit is protected because it's included in a cascade-protected page"),
+ 'protectedpagetext' => array('code' => 'protectedpage', 'info' => "The ``\$1'' right is required to edit this page"),
+ 'protect-cantedit' => array('code' => 'cantedit', 'info' => "You can't protect this page because you can't edit it"),
+ 'badaccess-group0' => array('code' => 'permissiondenied', 'info' => "Permission denied"), // Generic permission denied message
+ 'badaccess-group1' => array('code' => 'permissiondenied', 'info' => "Permission denied"), // Can't use the parameter 'cause it's wikilinked
+ 'badaccess-group2' => array('code' => 'permissiondenied', 'info' => "Permission denied"),
+ 'badaccess-groups' => array('code' => 'permissiondenied', 'info' => "Permission denied"),
+ 'titleprotected' => array('code' => 'protectedtitle', 'info' => "This title has been protected from creation"),
+ 'nocreate-loggedin' => array('code' => 'cantcreate', 'info' => "You don't have permission to create new pages"),
+ 'nocreatetext' => array('code' => 'cantcreate-anon', 'info' => "Anonymous users can't create new pages"),
+ 'movenologintext' => array('code' => 'cantmove-anon', 'info' => "Anonymous users can't move pages"),
+ 'movenotallowed' => array('code' => 'cantmove', 'info' => "You don't have permission to move pages"),
+ 'confirmedittext' => array('code' => 'confirmemail', 'info' => "You must confirm your e-mail address before you can edit"),
+ 'blockedtext' => array('code' => 'blocked', 'info' => "You have been blocked from editing"),
+ 'autoblockedtext' => array('code' => 'autoblocked', 'info' => "Your IP address has been blocked automatically, because it was used by a blocked user"),
+
+ // Miscellaneous interface messages
+ 'actionthrottledtext' => array('code' => 'ratelimited', 'info' => "You've exceeded your rate limit. Please wait some time and try again"),
+ 'alreadyrolled' => array('code' => 'alreadyrolled', 'info' => "The page you tried to rollback was already rolled back"),
+ '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"),
+ '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"),
+ 'articleexists' => array('code' => 'articleexists', 'info' => "The destination article already exists and is not a redirect to the source article"),
+ 'protectedpage' => array('code' => 'protectedpage', 'info' => "You don't have permission to perform this move"),
+ 'hookaborted' => array('code' => 'hookaborted', 'info' => "The modification you tried to make was aborted by an extension hook"),
+ 'cantmove-titleprotected' => array('code' => 'protectedtitle', 'info' => "The destination article has been protected from creation"),
+ // 'badarticleerror' => shouldn't happen
+ // 'badtitletext' => shouldn't happen
+ 'ip_range_invalid' => array('code' => 'invalidrange', 'info' => "Invalid IP range"),
+ 'range_block_disabled' => array('code' => 'rangedisabled', 'info' => "Blocking IP ranges has been disabled"),
+ 'nosuchusershort' => array('code' => 'nosuchuser', 'info' => "The user you specified doesn't exist"),
+ '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_cant_unblock' => array('code' => 'cantunblock', 'info' => "The block you specified was not found. It may have been unblocked already"),
+
+ // API-specific messages
+ 'missingparam' => array('code' => 'no$1', 'info' => "The \$1 parameter must be set"),
+ 'invalidtitle' => array('code' => 'invalidtitle', 'info' => "Bad title ``\$1''"),
+ 'invaliduser' => array('code' => 'invaliduser', 'info' => "Invalid username ``\$1''"),
+ 'invalidexpiry' => array('code' => 'invalidexpiry', 'info' => "Invalid expiry time"),
+ 'pastexpiry' => array('code' => 'pastexpiry', 'info' => "Expiry time 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"),
+ 'canthide' => array('code' => 'canthide', 'info' => "You don't have permission to hide user names from the block log"),
+ 'cantblock-email' => array('code' => 'cantblock-email', 'info' => "You don't have permission to block users from sending e-mail through the wiki"),
+ 'unblock-notarget' => array('code' => 'notarget', 'info' => "Either the id or the user parameter must be set"),
+ 'unblock-idanduser' => array('code' => 'idanduser', 'info' => "The id and user parameters can\'t be used together"),
+ 'cantunblock' => array('code' => 'permissiondenied', 'info' => "You don't have permission to unblock users"),
+ 'cannotundelete' => array('code' => 'cantundelete', 'info' => "Couldn't undelete: the requested revisions may not exist, or may have been undeleted already"),
+ 'permdenied-undelete' => array('code' => 'permissiondenied', 'info' => "You don't have permission to restore deleted revisions"),
+ );
+
+ /**
+ * Output the error message related to a certain array
+ * @param array $error Element of a getUserPermissionsErrors()
+ */
+ public function dieUsageMsg($error) {
+ $key = array_shift($error);
+ if(isset(self::$messageMap[$key]))
+ $this->dieUsage(wfMsgReplaceArgs(self::$messageMap[$key]['info'], $error), wfMsgReplaceArgs(self::$messageMap[$key]['code'], $error));
+ // If the key isn't present, throw an "unknown error"
+ $this->dieUsageMsg(array('unknownerror', $key));
+ }
/**
* Internal code errors should be reported with this method
@@ -510,6 +642,28 @@ abstract class ApiBase {
}
/**
+ * Indicates if API needs to check maxlag
+ */
+ public function shouldCheckMaxlag() {
+ return true;
+ }
+
+ /**
+ * Indicates if this module requires edit mode
+ */
+ public function isEditMode() {
+ return false;
+ }
+
+ /**
+ * Indicates whether this module must be called with a POST request
+ */
+ public function mustBePosted() {
+ return false;
+ }
+
+
+ /**
* Profiling: total module execution time
*/
private $mTimeIn = 0, $mModuleTime = 0;
@@ -610,10 +764,12 @@ abstract class ApiBase {
print "\n</pre>\n";
}
- public abstract function getVersion();
+ /**
+ * Returns a String that identifies the version of this class.
+ */
public static function getBaseVersion() {
- return __CLASS__ . ': $Id: ApiBase.php 24934 2007-08-20 08:04:12Z nickj $';
- }
+ return __CLASS__ . ': $Id: ApiBase.php 31259 2008-02-25 14:14:55Z catrope $';
+ }
}
diff --git a/includes/api/ApiBlock.php b/includes/api/ApiBlock.php
new file mode 100644
index 00000000..e5c238ae
--- /dev/null
+++ b/includes/api/ApiBlock.php
@@ -0,0 +1,164 @@
+<?php
+
+/*
+ * Created on Sep 4, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+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.
+*
+ * @addtogroup API
+ */
+class ApiBlock extends ApiBase {
+
+ /**
+ * Std ctor.
+ */
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ /**
+ * Blocks the user specified in the parameters for the given expiry, with the
+ * given reason, and with all other settings provided in the params. If the block
+ * succeeds, produces a result containing the details of the block and notice
+ * of success. If it fails, the result will specify the nature of the error.
+ */
+ public function execute() {
+ global $wgUser;
+ $this->getMain()->requestWriteMode();
+ $params = $this->extractRequestParams();
+
+ if($params['gettoken'])
+ {
+ $res['blocktoken'] = $wgUser->editToken();
+ $this->getResult()->addValue(null, $this->getModuleName(), $res);
+ return;
+ }
+
+ if(is_null($params['user']))
+ $this->dieUsageMsg(array('missingparam', 'user'));
+ if(is_null($params['token']))
+ $this->dieUsageMsg(array('missingparam', 'token'));
+ if(!$wgUser->matchEditToken($params['token']))
+ $this->dieUsageMsg(array('sessionfailure'));
+ if(!$wgUser->isAllowed('block'))
+ $this->dieUsageMsg(array('cantblock'));
+ if($params['hidename'] && !$wgUser->isAllowed('hideuser'))
+ $this->dieUsageMsg(array('canthide'));
+ if($params['noemail'] && !$wgUser->isAllowed('blockemail'))
+ $this->dieUsageMsg(array('cantblock-email'));
+ if(wfReadOnly())
+ $this->dieUsageMsg(array('readonlytext'));
+
+ $form = new IPBlockForm('');
+ $form->BlockAddress = $params['user'];
+ $form->BlockReason = (is_null($params['reason']) ? '' : $params['reason']);
+ $form->BlockReasonList = 'other';
+ $form->BlockExpiry = ($params['expiry'] == 'never' ? 'infinite' : $params['expiry']);
+ $form->BlockOther = '';
+ $form->BlockAnonOnly = $params['anononly'];
+ $form->BlockCreateAccount = $params['nocreate'];
+ $form->BlockEnableAutoBlock = $params['autoblock'];
+ $form->BlockEmail = $params['noemail'];
+ $form->BlockHideName = $params['hidename'];
+
+ $dbw = wfGetDb(DB_MASTER);
+ $dbw->begin();
+ $retval = $form->doBlock($userID, $expiry);
+ if(!empty($retval))
+ // We don't care about multiple errors, just report one of them
+ $this->dieUsageMsg($retval);
+
+ $dbw->commit();
+ $res['user'] = $params['user'];
+ $res['userID'] = $userID;
+ $res['expiry'] = ($expiry == Block::infinity() ? 'infinite' : $expiry);
+ $res['reason'] = $params['reason'];
+ if($params['anononly'])
+ $res['anononly'] = '';
+ if($params['nocreate'])
+ $res['nocreate'] = '';
+ if($params['autoblock'])
+ $res['autoblock'] = '';
+ if($params['noemail'])
+ $res['noemail'] = '';
+ if($params['hidename'])
+ $res['hidename'] = '';
+
+ $this->getResult()->addValue(null, $this->getModuleName(), $res);
+ }
+
+ public function mustBePosted() { return true; }
+
+ public function getAllowedParams() {
+ return array (
+ 'user' => null,
+ 'token' => null,
+ 'gettoken' => false,
+ 'expiry' => 'never',
+ 'reason' => null,
+ 'anononly' => false,
+ 'nocreate' => false,
+ 'autoblock' => false,
+ 'noemail' => false,
+ 'hidename' => false,
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'user' => 'Username, IP address or IP range you want to block',
+ 'token' => 'A block token previously obtained through the gettoken parameter',
+ 'gettoken' => 'If set, a block token will be returned, and no other action will be taken',
+ 'expiry' => 'Relative expiry time, e.g. \'5 months\' or \'2 weeks\'. If set to \'infinite\', \'indefinite\' or \'never\', the block will never expire.',
+ 'reason' => 'Reason for block (optional)',
+ 'anononly' => 'Block anonymous users only (i.e. disable anonymous edits for this IP)',
+ 'nocreate' => 'Prevent account creation',
+ 'autoblock' => 'Automatically block the last used IP address, and any subsequent IP addresses they try to login from',
+ 'noemail' => 'Prevent user from sending e-mail through the wiki. (Requires the "blockemail" right.)',
+ 'hidename' => 'Hide the username from the block log. (Requires the "hideuser" right.)'
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Block a user.'
+ );
+ }
+
+ protected 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'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiBlock.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiChangeRights.php b/includes/api/ApiChangeRights.php
new file mode 100644
index 00000000..647a5194
--- /dev/null
+++ b/includes/api/ApiChangeRights.php
@@ -0,0 +1,155 @@
+<?php
+
+/*
+ * Created on Sep 11, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+/**
+ * API module that facilitates the changing of user rights. The API eqivalent of
+ * Special:Userrights. Requires API write mode to be enabled.
+ *
+ * @addtogroup API
+ */
+class ApiChangeRights extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ global $wgUser, $wgRequest;
+ $this->getMain()->requestWriteMode();
+
+ if(wfReadOnly())
+ $this->dieUsage('The wiki is in read-only mode', 'readonly');
+ $params = $this->extractRequestParams();
+
+ $ur = new UserrightsPage($wgRequest);
+ $allowed = $ur->changeableGroups();
+ $res = array();
+
+ $u = $ur->fetchUser_real($params['user']);
+ if(is_array($u))
+ switch($u[0])
+ {
+ case UserrightsPage::FETCHUSER_NO_INTERWIKI:
+ $this->dieUsage("You don't have permission to change users' rights on other wikis", 'nointerwiki');
+ case UserrightsPage::FETCHUSER_NO_DATABASE:
+ $this->dieUsage("Database ``{$u[1]}'' does not exist or is not local", 'nosuchdatabase');
+ case UserrightsPage::FETCHUSER_NO_USER:
+ $this->dieUsage("You specified an empty username, or none at all", 'emptyuser');
+ case UserrightsPage::FETCHUSER_NOSUCH_USERID:
+ $this->dieUsage("There is no user with ID ``{$u[1]}''", 'nosuchuserid');
+ case UserrightsPage::FETCHUSER_NOSUCH_USERNAME:
+ $this->dieUsage("There is no user with username ``{$u[1]}''", 'nosuchusername');
+ default:
+ $this->dieDebug(__METHOD__, "UserrightsPage::fetchUser_real() returned an unknown error ({$u[0]})");
+ }
+
+ $curgroups = $u->getGroups();
+ if($params['listgroups'])
+ {
+ $res['user'] = $u->getName();
+ $res['allowedgroups'] = $allowed;
+ $res['ingroups'] = $curgroups;
+ $this->getResult()->setIndexedTagName($res['ingroups'], 'group');
+ $this->getResult()->setIndexedTagName($res['allowedgroups']['add'], 'group');
+ $this->getResult()->setIndexedTagName($res['allowedgroups']['remove'], 'group');
+ }
+;
+ if($params['gettoken'])
+ {
+ $res['changerightstoken'] = $wgUser->editToken($u->getName());
+ $this->getResult()->addValue(null, $this->getModuleName(), $res);
+ return;
+ }
+
+ if(empty($params['addto']) && empty($params['rmfrom']))
+ $this->dieUsage('At least one of the addto and rmfrom parameters must be set', 'noaddrm');
+ if(is_null($params['token']))
+ $this->dieUsage('The token parameter must be set', 'notoken');
+ if(!$wgUser->matchEditToken($params['token'], $u->getName()))
+ $this->dieUsage('Invalid token', 'badtoken');
+
+ $dbw = wfGetDb(DB_MASTER);
+ $dbw->begin();
+ $ur->saveUserGroups($u, $params['rmfrom'], $params['addto'], $params['reason']);
+ $dbw->commit();
+ $res['user'] = $u->getName();
+ $res['addedto'] = (array)$params['addto'];
+ $res['removedfrom'] = (array)$params['rmfrom'];
+ $res['reason'] = $params['reason'];
+
+ $this->getResult()->setIndexedTagName($res['addedto'], 'group');
+ $this->getResult()->setIndexedTagName($res['removedfrom'], 'group');
+ $this->getResult()->addValue(null, $this->getModuleName(), $res);
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'user' => null,
+ 'token' => null,
+ 'gettoken' => false,
+ 'listgroups' => false,
+ 'addto' => array(
+ ApiBase :: PARAM_ISMULTI => true,
+ ),
+ 'rmfrom' => array(
+ ApiBase :: PARAM_ISMULTI => true,
+ ),
+ 'reason' => ''
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'user' => 'The user you want to add to or remove from groups.',
+ 'token' => 'A changerights token previously obtained through the gettoken parameter.',
+ 'gettoken' => 'Output a token. Note that the user parameter still has to be set.',
+ 'listgroups' => 'List the groups the user is in, and the ones you can add them to and remove them from.',
+ 'addto' => 'Pipe-separated list of groups to add this user to',
+ 'rmfrom' => 'Pipe-separated list of groups to remove this user from',
+ 'reason' => 'Reason for change (optional)'
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Add or remove a user from certain groups.'
+ );
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=changerights&user=Bob&gettoken&listgroups',
+ 'api.php?action=changerights&user=Bob&token=123ABC&addto=sysop&reason=Promoting%20per%20RFA'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiChangeRights.php 28216 2007-12-06 18:33:18Z vasilievvv $';
+ }
+}
diff --git a/includes/api/ApiDelete.php b/includes/api/ApiDelete.php
new file mode 100644
index 00000000..cd747e7e
--- /dev/null
+++ b/includes/api/ApiDelete.php
@@ -0,0 +1,155 @@
+<?php
+
+/*
+ * Created on Jun 30, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+
+/**
+ * API module that facilitates deleting pages. The API eqivalent of action=delete.
+ * Requires API write mode to be enabled.
+ *
+ * @addtogroup API
+ */
+class ApiDelete extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ /**
+ * Extracts the title, token, and reason from the request parameters and invokes
+ * the local delete() function with these as arguments. It does not make use of
+ * the delete function specified by Article.php. If the deletion succeeds, the
+ * details of the article deleted and the reason for deletion are added to the
+ * result object.
+ */
+ public function execute() {
+ global $wgUser;
+ $this->getMain()->requestWriteMode();
+ $params = $this->extractRequestParams();
+
+ $titleObj = NULL;
+ if(!isset($params['title']))
+ $this->dieUsageMsg(array('missingparam', 'title'));
+ if(!isset($params['token']))
+ $this->dieUsageMsg(array('missingparam', 'token'));
+
+ $titleObj = Title::newFromText($params['title']);
+ if(!$titleObj)
+ $this->dieUsageMsg(array('invalidtitle', $params['title']));
+ if(!$titleObj->exists())
+ $this->dieUsageMsg(array('notanarticle'));
+
+ $articleObj = new Article($titleObj);
+ $reason = (isset($params['reason']) ? $params['reason'] : NULL);
+ $dbw = wfGetDb(DB_MASTER);
+ $dbw->begin();
+ $retval = self::delete($articleObj, $params['token'], $reason);
+
+ if(!empty($retval))
+ // We don't care about multiple errors, just report one of them
+ $this->dieUsageMsg(current($retval));
+
+ $dbw->commit();
+ $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason);
+ $this->getResult()->addValue(null, $this->getModuleName(), $r);
+ }
+
+ /**
+ * We have our own delete() function, since Article.php's implementation is split in two phases
+ *
+ * @param Article $article - Article object to work on
+ * @param string $token - Delete token (same as edit token)
+ * @param string $reason - Reason for the deletion. Autogenerated if NULL
+ * @return Title::getUserPermissionsErrors()-like array
+ */
+ public static function delete(&$article, $token, &$reason = NULL)
+ {
+ global $wgUser;
+
+ // Check permissions
+ $errors = $article->mTitle->getUserPermissionsErrors('delete', $wgUser);
+ if(!empty($errors))
+ return $errors;
+ if(wfReadOnly())
+ return array(array('readonlytext'));
+ if($wgUser->isBlocked())
+ return array(array('blocked'));
+
+ // Check token
+ if(!$wgUser->matchEditToken($token))
+ return array(array('sessionfailure'));
+
+ // Auto-generate a summary, if necessary
+ if(is_null($reason))
+ {
+ $reason = $article->generateReason($hasHistory);
+ if($reason === false)
+ return array(array('cannotdelete'));
+ }
+
+ // Luckily, Article.php provides a reusable delete function that does the hard work for us
+ if($article->doDeleteArticle($reason))
+ return array();
+ return array(array('cannotdelete', $article->mTitle->getPrefixedText()));
+ }
+
+ public function mustBePosted() { return true; }
+
+ public function getAllowedParams() {
+ return array (
+ 'title' => null,
+ 'token' => null,
+ 'reason' => null,
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'title' => 'Title of the page you want to delete.',
+ 'token' => 'A delete token previously retrieved through prop=info',
+ 'reason' => 'Reason for the deletion. If not set, an automatically generated reason will be used.'
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Deletes a page. You need to be logged in as a sysop to use this function, see also action=login.'
+ );
+ }
+
+ protected 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'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiDelete.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiExpandTemplates.php b/includes/api/ApiExpandTemplates.php
new file mode 100644
index 00000000..278896fa
--- /dev/null
+++ b/includes/api/ApiExpandTemplates.php
@@ -0,0 +1,97 @@
+<?php
+
+/*
+ * Created on Oct 05, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Yuri Astrakhan <Firstname><Lastname>@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+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
+ * to the caller.
+ *
+ * @addtogroup API
+ */
+class ApiExpandTemplates extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ // Get parameters
+ $params = $this->extractRequestParams();
+ $text = $params['text'];
+ $title = $params['title'];
+ $retval = '';
+
+ //Create title for parser
+ $title_obj = Title :: newFromText($params['title']);
+ if(!$title_obj)
+ $title_obj = Title :: newFromText("API"); // Default title is "API". For example, ExpandTemplates uses "ExpendTemplates" for it
+
+ // Parse text
+ global $wgParser;
+ $retval = $wgParser->preprocess( $text, $title_obj, new ParserOptions() );
+
+ // Return result
+ $result = $this->getResult();
+ $retval_array = array();
+ $result->setContent( $retval_array, $retval );
+ $result->addValue( null, $this->getModuleName(), $retval_array );
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'title' => array(
+ ApiBase :: PARAM_DFLT => 'API',
+ ),
+ 'text' => null
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'text' => 'Wikitext to convert',
+ 'title' => 'Title of page',
+ );
+ }
+
+ public function getDescription() {
+ return 'This module expand all templates in wikitext';
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=expandtemplates&text={{Project:Sandbox}}'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiExpandTemplates.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
+
diff --git a/includes/api/ApiFeedWatchlist.php b/includes/api/ApiFeedWatchlist.php
index b2f6ceff..9b17b9d3 100644
--- a/includes/api/ApiFeedWatchlist.php
+++ b/includes/api/ApiFeedWatchlist.php
@@ -62,17 +62,24 @@ class ApiFeedWatchlist extends ApiBase {
// limit to the number of hours going from now back
$endTime = wfTimestamp(TS_MW, time() - intval($params['hours'] * 60 * 60));
- // Prepare nested request
- $fauxReq = new FauxRequest(array (
+ $dbr = wfGetDB( DB_SLAVE );
+ // Prepare parameters for nested request
+ $fauxReqArr = array (
'action' => 'query',
'meta' => 'siteinfo',
'siprop' => 'general',
'list' => 'watchlist',
'wlprop' => 'title|user|comment|timestamp',
'wldir' => 'older', // reverse order - from newest to oldest
- 'wlend' => $endTime, // stop at this time
+ 'wlend' => $dbr->timestamp($endTime), // stop at this time
'wllimit' => 50
- ));
+ );
+
+ // Check for 'allrev' parameter, and if found, show all revisions to each page on wl.
+ if ( ! is_null ( $params['allrev'] ) ) $fauxReqArr['wlallrev'] = '';
+
+ // Create the request
+ $fauxReq = new FauxRequest ( $fauxReqArr );
// Execute
$module = new ApiMain($fauxReq);
@@ -131,7 +138,7 @@ class ApiFeedWatchlist extends ApiBase {
return new FeedItem($titleStr, $completeText, $titleUrl, $timestamp, $user);
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
global $wgFeedClasses;
$feedFormatNames = array_keys($wgFeedClasses);
return array (
@@ -144,18 +151,20 @@ class ApiFeedWatchlist extends ApiBase {
ApiBase :: PARAM_TYPE => 'integer',
ApiBase :: PARAM_MIN => 1,
ApiBase :: PARAM_MAX => 72,
- )
+ ),
+ 'allrev' => null
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'feedformat' => 'The format of the feed',
- 'hours' => 'List pages modified within this many hours from now'
+ 'hours' => 'List pages modified within this many hours from now',
+ 'allrev' => 'Include multiple revisions of the same page within given timeframe.'
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'This module returns a watchlist feed';
}
@@ -166,7 +175,7 @@ class ApiFeedWatchlist extends ApiBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFeedWatchlist.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiFeedWatchlist.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiFormatBase.php b/includes/api/ApiFormatBase.php
index 861310d2..768a18ac 100644
--- a/includes/api/ApiFormatBase.php
+++ b/includes/api/ApiFormatBase.php
@@ -35,7 +35,7 @@ if (!defined('MEDIAWIKI')) {
*/
abstract class ApiFormatBase extends ApiBase {
- private $mIsHtml, $mFormat;
+ private $mIsHtml, $mFormat, $mUnescapeAmps, $mHelp;
/**
* Create a new instance of the formatter.
@@ -69,6 +69,18 @@ abstract class ApiFormatBase extends ApiBase {
}
/**
+ * Specify whether or not ampersands should be escaped to '&amp;' when rendering. This
+ * should only be set to true for the help message when rendered in the default (xmlfm)
+ * format. This is a temporary special-case fix that should be removed once the help
+ * has been reworked to use a fully html interface.
+ *
+ * @param boolean Whether or not ampersands should be escaped.
+ */
+ public function setUnescapeAmps ( $b ) {
+ $this->mUnescapeAmps = $b;
+ }
+
+ /**
* Returns true when an HTML filtering printer should be used.
* The default implementation assumes that formats ending with 'fm'
* should be formatted in HTML.
@@ -99,7 +111,11 @@ abstract class ApiFormatBase extends ApiBase {
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <title>MediaWiki API</title>
+<?php if ($this->mUnescapeAmps) {
+?> <title>MediaWiki API</title>
+<?php } else {
+?> <title>MediaWiki API Result</title>
+<?php } ?>
</head>
<body>
<?php
@@ -154,13 +170,20 @@ See <a href='http://www.mediawiki.org/wiki/API'>complete documentation</a>, or
}
/**
+ * Says pretty-printer that it should use *bold* and $italics$ formatting
+ */
+ public function setHelp( $help = true ) {
+ $this->mHelp = true;
+ }
+
+ /**
* Prety-print various elements in HTML format, such as xml tags and URLs.
* This method also replaces any '<' with &lt;
*/
protected function formatHTML($text) {
// Escape everything first for full coverage
$text = htmlspecialchars($text);
-
+
// encode all comments or tags as safe blue strings
$text = preg_replace('/\&lt;(!--.*?--|.*?)\&gt;/', '<span style="color:blue;">&lt;\1&gt;</span>', $text);
// identify URLs
@@ -168,10 +191,19 @@ See <a href='http://www.mediawiki.org/wiki/API'>complete documentation</a>, or
$text = ereg_replace("($protos)://[^ \\'\"()<\n]+", '<a href="\\0">\\0</a>', $text);
// identify requests to api.php
$text = ereg_replace("api\\.php\\?[^ \\()<\n\t]+", '<a href="\\0">\\0</a>', $text);
- // make strings inside * bold
- $text = ereg_replace("\\*[^<>\n]+\\*", '<b>\\0</b>', $text);
- // make strings inside $ italic
- $text = ereg_replace("\\$[^<>\n]+\\$", '<b><i>\\0</i></b>', $text);
+ if( $this->mHelp ) {
+ // make strings inside * bold
+ $text = ereg_replace("\\*[^<>\n]+\\*", '<b>\\0</b>', $text);
+ // make strings inside $ italic
+ $text = ereg_replace("\\$[^<>\n]+\\$", '<b><i>\\0</i></b>', $text);
+ }
+
+ /* Temporary fix for bad links in help messages. As a special case,
+ * XML-escaped metachars are de-escaped one level in the help message
+ * for legibility. Should be removed once we have completed a fully-html
+ * version of the help message. */
+ if ( $this->mUnescapeAmps )
+ $text = preg_replace( '/&amp;(amp|quot|lt|gt);/', '&\1;', $text );
return $text;
}
@@ -183,12 +215,12 @@ See <a href='http://www.mediawiki.org/wiki/API'>complete documentation</a>, or
return 'api.php?action=query&meta=siteinfo&siprop=namespaces&format=' . $this->getModuleName();
}
- protected function getDescription() {
+ public function getDescription() {
return $this->getIsHtml() ? ' (pretty-print in HTML)' : '';
}
public static function getBaseVersion() {
- return __CLASS__ . ': $Id: ApiFormatBase.php 25746 2007-09-10 21:36:51Z brion $';
+ return __CLASS__ . ': $Id: ApiFormatBase.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
@@ -250,6 +282,6 @@ class ApiFormatFeedWrapper extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatBase.php 25746 2007-09-10 21:36:51Z brion $';
+ return __CLASS__ . ': $Id: ApiFormatBase.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiFormatDbg.php b/includes/api/ApiFormatDbg.php
new file mode 100644
index 00000000..f0fc5e91
--- /dev/null
+++ b/includes/api/ApiFormatDbg.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * Created on Oct 22, 2006
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ('ApiFormatBase.php');
+}
+
+/**
+ * @addtogroup API
+ */
+class ApiFormatDbg extends ApiFormatBase {
+
+ public function __construct($main, $format) {
+ parent :: __construct($main, $format);
+ }
+
+ public function getMimeType() {
+ # This looks like it should be text/plain, but IE7 is so
+ # brain-damaged it tries to parse text/plain as HTML if it
+ # contains HTML tags. Using MIME text/text works around this bug
+ return 'text/text';
+ }
+
+ public function execute() {
+ $this->printText(var_export($this->getResultData(), true));
+ }
+
+ public function getDescription() {
+ return 'Output data in PHP\'s var_export() format' . parent :: getDescription();
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiFormatPhp.php 23531 2007-06-29 01:19:14Z simetrical $';
+ }
+}
+
diff --git a/includes/api/ApiFormatJson.php b/includes/api/ApiFormatJson.php
index 59f3b492..852a64b6 100644
--- a/includes/api/ApiFormatJson.php
+++ b/includes/api/ApiFormatJson.php
@@ -66,19 +66,19 @@ class ApiFormatJson extends ApiFormatBase {
}
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'callback' => null
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'callback' => 'If specified, wraps the output into a given function call. For safety, all user-specific data will be restricted.',
);
}
- protected function getDescription() {
+ public function getDescription() {
if ($this->mIsRaw)
return 'Output data with the debuging elements in JSON format' . parent :: getDescription();
else
@@ -86,7 +86,7 @@ class ApiFormatJson extends ApiFormatBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatJson.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiFormatJson.php 31484 2008-03-03 05:46:20Z brion $';
}
}
diff --git a/includes/api/ApiFormatPhp.php b/includes/api/ApiFormatPhp.php
index 766d7041..f830d8e1 100644
--- a/includes/api/ApiFormatPhp.php
+++ b/includes/api/ApiFormatPhp.php
@@ -45,12 +45,12 @@ class ApiFormatPhp extends ApiFormatBase {
$this->printText(serialize($this->getResultData()));
}
- protected function getDescription() {
+ public function getDescription() {
return 'Output data in serialized PHP format' . parent :: getDescription();
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatPhp.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiFormatPhp.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiFormatTxt.php b/includes/api/ApiFormatTxt.php
new file mode 100644
index 00000000..c4c45f68
--- /dev/null
+++ b/includes/api/ApiFormatTxt.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * Created on Oct 22, 2006
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ('ApiFormatBase.php');
+}
+
+/**
+ * @addtogroup API
+ */
+class ApiFormatTxt extends ApiFormatBase {
+
+ public function __construct($main, $format) {
+ parent :: __construct($main, $format);
+ }
+
+ public function getMimeType() {
+ # This looks like it should be text/plain, but IE7 is so
+ # brain-damaged it tries to parse text/plain as HTML if it
+ # contains HTML tags. Using MIME text/text works around this bug
+ return 'text/text';
+ }
+
+ public function execute() {
+ $this->printText(print_r($this->getResultData(), true));
+ }
+
+ public function getDescription() {
+ return 'Output data in PHP\'s print_r() format' . parent :: getDescription();
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiFormatPhp.php 23531 2007-06-29 01:19:14Z simetrical $';
+ }
+}
+
diff --git a/includes/api/ApiFormatWddx.php b/includes/api/ApiFormatWddx.php
index 0ddfac73..22a0e482 100644
--- a/includes/api/ApiFormatWddx.php
+++ b/includes/api/ApiFormatWddx.php
@@ -80,12 +80,12 @@ class ApiFormatWddx extends ApiFormatBase {
}
}
- protected function getDescription() {
+ public function getDescription() {
return 'Output data in WDDX format' . parent :: getDescription();
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatWddx.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiFormatWddx.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiFormatXml.php b/includes/api/ApiFormatXml.php
index 02647923..d39e8049 100644
--- a/includes/api/ApiFormatXml.php
+++ b/includes/api/ApiFormatXml.php
@@ -136,12 +136,12 @@ class ApiFormatXml extends ApiFormatBase {
break;
}
}
- protected function getDescription() {
+ public function getDescription() {
return 'Output data in XML format' . parent :: getDescription();
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatXml.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiFormatXml.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiFormatYaml.php b/includes/api/ApiFormatYaml.php
index 400c0a4b..5e15aee6 100644
--- a/includes/api/ApiFormatYaml.php
+++ b/includes/api/ApiFormatYaml.php
@@ -45,12 +45,12 @@ class ApiFormatYaml extends ApiFormatBase {
$this->printText(Spyc :: YAMLDump($this->getResultData()));
}
- protected function getDescription() {
+ public function getDescription() {
return 'Output data in YAML format' . parent :: getDescription();
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiFormatYaml.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiFormatYaml.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiFormatYaml_spyc.php b/includes/api/ApiFormatYaml_spyc.php
index b3ccff0f..b2973b8c 100644
--- a/includes/api/ApiFormatYaml_spyc.php
+++ b/includes/api/ApiFormatYaml_spyc.php
@@ -385,6 +385,18 @@
return false;
}
}
+
+ /**
+ * Find out whether a string needs to be output as a literal rather than in plain style.
+ * Added by Roan Kattouw 13-03-2008
+ * @param $value The string to check
+ * @return bool
+ */
+ function _needLiteral($value) {
+ # Check whether the string contains # or : or begins with any of:
+ # [ - ? , [ ] { } ! * & | > ' " % @ ` ]
+ return (bool)(preg_match("/[#:]/", $value) || preg_match("/^[-?,[\]{}!*&|>'\"%@`]/", $value));
+ }
/**
* Returns YAML from a key and a value
@@ -396,7 +408,7 @@
*/
function _dumpNode($key,$value,$indent) {
// do some folding here, for blocks
- if (strpos($value,"\n")) {
+ if (strpos($value,"\n") || $this->_needLiteral($value)) {
$value = $this->_doLiteralBlock($value,$indent);
} else {
$value = $this->_doFolding($value,$indent);
diff --git a/includes/api/ApiHelp.php b/includes/api/ApiHelp.php
index 9f1e88ea..47a45ea1 100644
--- a/includes/api/ApiHelp.php
+++ b/includes/api/ApiHelp.php
@@ -46,14 +46,18 @@ class ApiHelp extends ApiBase {
$this->dieUsage('', 'help');
}
- protected function getDescription() {
+ public function shouldCheckMaxlag() {
+ return false;
+ }
+
+ public function getDescription() {
return array (
'Display this help screen.'
);
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiHelp.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiHelp.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiLogin.php b/includes/api/ApiLogin.php
index af68b29d..3e66ed79 100644
--- a/includes/api/ApiLogin.php
+++ b/includes/api/ApiLogin.php
@@ -40,7 +40,7 @@ class ApiLogin extends ApiBase {
* Time (in seconds) a user must wait after submitting
* a bad login (will be multiplied by the THROTTLE_FACTOR for each bad attempt)
*/
- const THROTTLE_TIME = 1;
+ const THROTTLE_TIME = 5;
/**
* The factor by which the wait-time in between authentication
@@ -91,10 +91,15 @@ class ApiLogin extends ApiBase {
'wpRemember' => ''
));
+ // Init session if necessary
+ if( session_id() == '' ) {
+ wfSetupSession();
+ }
+
$loginForm = new LoginForm($params);
switch ($loginForm->authenticateUserData()) {
case LoginForm :: SUCCESS :
- global $wgUser;
+ global $wgUser, $wgCookiePrefix;
$wgUser->setOption('rememberpassword', 1);
$wgUser->setCookies();
@@ -103,6 +108,8 @@ class ApiLogin extends ApiBase {
$result['lguserid'] = $_SESSION['wsUserID'];
$result['lgusername'] = $_SESSION['wsUserName'];
$result['lgtoken'] = $_SESSION['wsToken'];
+ $result['cookieprefix'] = $wgCookiePrefix;
+ $result['sessionid'] = session_id();
break;
case LoginForm :: NO_NAME :
@@ -129,6 +136,7 @@ class ApiLogin extends ApiBase {
if ($result['result'] != 'Success') {
$result['wait'] = $this->cacheBadLogin();
+ $result['details'] = "Please wait " . self::THROTTLE_TIME . " seconds before next log-in attempt";
}
// if we were allowed to try to login, memcache is fine
@@ -209,8 +217,10 @@ class ApiLogin extends ApiBase {
private function getMemCacheKey() {
return wfMemcKey( 'apilogin', 'badlogin', 'ip', wfGetIP() );
}
+
+ public function mustBePosted() { return true; }
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'name' => null,
'password' => null,
@@ -218,7 +228,7 @@ class ApiLogin extends ApiBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'name' => 'User Name',
'password' => 'Password',
@@ -226,7 +236,7 @@ class ApiLogin extends ApiBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return array (
'This module is used to login and get the authentication tokens. ',
'In the event of a successful log-in, a cookie will be attached',
@@ -243,7 +253,7 @@ class ApiLogin extends ApiBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiLogin.php 24695 2007-08-09 09:53:05Z yurik $';
+ return __CLASS__ . ': $Id: ApiLogin.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiLogout.php b/includes/api/ApiLogout.php
new file mode 100644
index 00000000..d578acf3
--- /dev/null
+++ b/includes/api/ApiLogout.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * Created on Jan 4, 2008
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2008 Yuri Astrakhan <Firstname><Lastname>@gmail.com,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+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.
+ *
+ * @addtogroup API
+ */
+class ApiLogout extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ global $wgUser;
+ $wgUser->logout();
+ }
+
+ public function getAllowedParams() {
+ return array ();
+ }
+
+ public function getParamDescription() {
+ return array ();
+ }
+
+ public function getDescription() {
+ return array (
+ 'This module is used to logout and clear session data'
+ );
+ }
+
+ protected function getExamples() {
+ return array(
+ 'api.php?action=logout'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id$';
+ }
+}
diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php
index 00b3f63f..874e531c 100644
--- a/includes/api/ApiMain.php
+++ b/includes/api/ApiMain.php
@@ -53,10 +53,26 @@ class ApiMain extends ApiBase {
*/
private static $Modules = array (
'login' => 'ApiLogin',
+ 'logout' => 'ApiLogout',
'query' => 'ApiQuery',
+ 'expandtemplates' => 'ApiExpandTemplates',
+ 'parse' => 'ApiParse',
'opensearch' => 'ApiOpenSearch',
'feedwatchlist' => 'ApiFeedWatchlist',
'help' => 'ApiHelp',
+ 'paraminfo' => 'ApiParamInfo',
+ );
+
+ private static $WriteModules = array (
+ 'rollback' => 'ApiRollback',
+ 'delete' => 'ApiDelete',
+ 'undelete' => 'ApiUndelete',
+ 'protect' => 'ApiProtect',
+ 'block' => 'ApiBlock',
+ 'unblock' => 'ApiUnblock',
+ 'move' => 'ApiMove',
+ #'changerights' => 'ApiChangeRights'
+ # Disabled for now
);
/**
@@ -73,7 +89,11 @@ class ApiMain extends ApiBase {
'xmlfm' => 'ApiFormatXml',
'yaml' => 'ApiFormatYaml',
'yamlfm' => 'ApiFormatYaml',
- 'rawfm' => 'ApiFormatJson'
+ 'rawfm' => 'ApiFormatJson',
+ 'txt' => 'ApiFormatTxt',
+ 'txtfm' => 'ApiFormatTxt',
+ 'dbg' => 'ApiFormatDbg',
+ 'dbgfm' => 'ApiFormatDbg'
);
private $mPrinter, $mModules, $mModuleNames, $mFormats, $mFormatNames;
@@ -108,14 +128,17 @@ class ApiMain extends ApiBase {
if (!$wgUser->isAllowed('read')) {
self::$Modules = array(
- 'login' => self::$Modules['login'],
- 'help' => self::$Modules['help']
+ 'login' => self::$Modules['login'],
+ 'logout' => self::$Modules['logout'],
+ 'help' => self::$Modules['help'],
);
}
}
- global $wgAPIModules; // extension modules
+ global $wgAPIModules, $wgEnableWriteAPI; // extension modules
$this->mModules = $wgAPIModules + self :: $Modules;
+ if($wgEnableWriteAPI)
+ $this->mModules += self::$WriteModules;
$this->mModuleNames = array_keys($this->mModules); // todo: optimize
$this->mFormats = self :: $Formats;
@@ -157,7 +180,7 @@ class ApiMain extends ApiBase {
public function requestWriteMode() {
if (!$this->mEnableWrite)
$this->dieUsage('Editing of this site is disabled. Make sure the $wgEnableWriteAPI=true; ' .
- 'statement is included in the site\'s LocalSettings.php file', 'readonly');
+ 'statement is included in the site\'s LocalSettings.php file', 'noapiwrite');
}
/**
@@ -271,7 +294,7 @@ class ApiMain extends ApiBase {
// Something is seriously wrong
//
$errMessage = array (
- 'code' => 'internal_api_error',
+ 'code' => 'internal_api_error_'. get_class($e),
'info' => "Exception Caught: {$e->getMessage()}"
);
ApiResult :: setContent($errMessage, "\n\n{$e->getTraceAsString()}\n\n");
@@ -287,16 +310,34 @@ class ApiMain extends ApiBase {
* Execute the actual module, without any error handling
*/
protected function executeAction() {
-
+
$params = $this->extractRequestParams();
-
+
$this->mShowVersions = $params['version'];
$this->mAction = $params['action'];
// Instantiate the module requested by the user
$module = new $this->mModules[$this->mAction] ($this, $this->mAction);
-
+
+ if( $module->shouldCheckMaxlag() && isset( $params['maxlag'] ) ) {
+ // Check for maxlag
+ global $wgLoadBalancer, $wgShowHostnames;
+ $maxLag = $params['maxlag'];
+ list( $host, $lag ) = $wgLoadBalancer->getMaxLag();
+ if ( $lag > $maxLag ) {
+ if( $wgShowHostnames ) {
+ ApiBase :: dieUsage( "Waiting for $host: $lag seconds lagged", 'maxlag' );
+ } else {
+ ApiBase :: dieUsage( "Waiting for a database server: $lag seconds lagged", 'maxlag' );
+ }
+ return;
+ }
+ }
+
if (!$this->mInternalMode) {
+ // Ignore mustBePosted() for internal calls
+ if($module->mustBePosted() && !$this->mRequest->wasPosted())
+ $this->dieUsage("The {$this->mAction} module requires a POST request", 'mustbeposted');
// See if custom printer is used
$this->mPrinter = $module->getCustomPrinter();
@@ -326,7 +367,16 @@ class ApiMain extends ApiBase {
protected function printResult($isError) {
$printer = $this->mPrinter;
$printer->profileIn();
+
+ /* If the help message is requested in the default (xmlfm) format,
+ * tell the printer not to escape ampersands so that our links do
+ * not break. */
+ $params = $this->extractRequestParams();
+ $printer->setUnescapeAmps ( ( $this->mAction == 'help' || $isError )
+ && $params['format'] == ApiMain::API_DEFAULT_FORMAT );
+
$printer->initPrinter($isError);
+
$printer->execute();
$printer->closePrinter();
$printer->profileOut();
@@ -335,7 +385,7 @@ class ApiMain extends ApiBase {
/**
* See ApiBase for description.
*/
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'format' => array (
ApiBase :: PARAM_DFLT => ApiMain :: API_DEFAULT_FORMAT,
@@ -345,25 +395,29 @@ class ApiMain extends ApiBase {
ApiBase :: PARAM_DFLT => 'help',
ApiBase :: PARAM_TYPE => $this->mModuleNames
),
- 'version' => false
+ 'version' => false,
+ 'maxlag' => array (
+ ApiBase :: PARAM_TYPE => 'integer'
+ ),
);
}
/**
* See ApiBase for description.
*/
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'format' => 'The format of the output',
'action' => 'What action you would like to perform',
- 'version' => 'When showing help, include version for each module'
+ 'version' => 'When showing help, include version for each module',
+ 'maxlag' => 'Maximum lag'
);
}
/**
* See ApiBase for description.
*/
- protected function getDescription() {
+ public function getDescription() {
return array (
'',
'',
@@ -396,8 +450,9 @@ class ApiMain extends ApiBase {
*/
protected function getCredits() {
return array(
- 'This API is being implemented by Yuri Astrakhan [[User:Yurik]] / <Firstname><Lastname>@gmail.com',
- 'Please leave your comments and suggestions at http://www.mediawiki.org/wiki/API'
+ 'This API is being implemented by Roan Kattouw <Firstname>.<Lastname>@home.nl',
+ 'Please send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org',
+ 'or file a bug report at http://bugzilla.wikimedia.org/'
);
}
@@ -405,6 +460,8 @@ class ApiMain extends ApiBase {
* Override the parent to generate help messages for all available modules.
*/
public function makeHelpMsg() {
+
+ $this->mPrinter->setHelp();
// Use parent to make default message for the main module
$msg = parent :: makeHelpMsg();
@@ -445,11 +502,12 @@ class ApiMain extends ApiBase {
}
private $mIsBot = null;
-
private $mIsSysop = null;
+ private $mCanApiHighLimits = null;
/**
* Returns true if the currently logged in user is a bot, false otherwise
+ * OBSOLETE, use canApiHighLimits() instead
*/
public function isBot() {
if (!isset ($this->mIsBot)) {
@@ -462,6 +520,7 @@ class ApiMain extends ApiBase {
/**
* Similar to isBot(), this method returns true if the logged in user is
* a sysop, and false if not.
+ * OBSOLETE, use canApiHighLimits() instead
*/
public function isSysop() {
if (!isset ($this->mIsSysop)) {
@@ -471,6 +530,15 @@ class ApiMain extends ApiBase {
return $this->mIsSysop;
}
+
+ public function canApiHighLimits() {
+ if (!isset($this->mCanApiHighLimits)) {
+ global $wgUser;
+ $this->mCanApiHighLimits = $wgUser->isAllowed('apihighlimits');
+ }
+
+ return $this->mCanApiHighLimits;
+ }
public function getShowVersions() {
return $this->mShowVersions;
@@ -483,7 +551,7 @@ class ApiMain extends ApiBase {
public function getVersion() {
$vers = array ();
$vers[] = 'MediaWiki ' . SpecialVersion::getVersion();
- $vers[] = __CLASS__ . ': $Id: ApiMain.php 25364 2007-08-31 15:23:48Z tstarling $';
+ $vers[] = __CLASS__ . ': $Id: ApiMain.php 31484 2008-03-03 05:46:20Z brion $';
$vers[] = ApiBase :: getBaseVersion();
$vers[] = ApiFormatBase :: getBaseVersion();
$vers[] = ApiQueryBase :: getBaseVersion();
@@ -515,6 +583,13 @@ class ApiMain extends ApiBase {
protected function addFormat( $fmtName, $fmtClass ) {
$this->mFormats[$fmtName] = $fmtClass;
}
+
+ /**
+ * Get the array mapping module names to class names
+ */
+ function getModules() {
+ return $this->mModules;
+ }
}
/**
@@ -539,3 +614,4 @@ class UsageException extends Exception {
}
}
+
diff --git a/includes/api/ApiMove.php b/includes/api/ApiMove.php
new file mode 100644
index 00000000..a8c39c9a
--- /dev/null
+++ b/includes/api/ApiMove.php
@@ -0,0 +1,152 @@
+<?php
+
+/*
+ * Created on Oct 31, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+
+/**
+ * @addtogroup API
+ */
+class ApiMove extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ global $wgUser;
+ $this->getMain()->requestWriteMode();
+ $params = $this->extractRequestParams();
+ if(is_null($params['reason']))
+ $params['reason'] = '';
+
+ $titleObj = NULL;
+ if(!isset($params['from']))
+ $this->dieUsageMsg(array('missingparam', 'from'));
+ if(!isset($params['to']))
+ $this->dieUsageMsg(array('missingparam', 'to'));
+ if(!isset($params['token']))
+ $this->dieUsageMsg(array('missingparam', 'token'));
+ if(!$wgUser->matchEditToken($params['token']))
+ $this->dieUsageMsg(array('sessionfailure'));
+
+ $fromTitle = Title::newFromText($params['from']);
+ if(!$fromTitle)
+ $this->dieUsageMsg(array('invalidtitle', $params['from']));
+ if(!$fromTitle->exists())
+ $this->dieUsageMsg(array('notanarticle'));
+ $fromTalk = $fromTitle->getTalkPage();
+
+ $toTitle = Title::newFromText($params['to']);
+ if(!$toTitle)
+ $this->dieUsageMsg(array('invalidtitle', $params['to']));
+ $toTalk = $toTitle->getTalkPage();
+
+ // Run getUserPermissionsErrors() here so we get message arguments too,
+ // rather than just a message key. The latter is troublesome for messages
+ // that use arguments.
+ // FIXME: moveTo() should really return an array, requires some
+ // refactoring of other code, though (mainly SpecialMovepage.php)
+ $errors = array_merge($fromTitle->getUserPermissionsErrors('move', $wgUser),
+ $fromTitle->getUserPermissionsErrors('edit', $wgUser),
+ $toTitle->getUserPermissionsErrors('move', $wgUser),
+ $toTitle->getUserPermissionsErrors('edit', $wgUser));
+ if(!empty($errors))
+ // We don't care about multiple errors, just report one of them
+ $this->dieUsageMsg(current($errors));
+
+ $dbw = wfGetDB(DB_MASTER);
+ $dbw->begin();
+ $retval = $fromTitle->moveTo($toTitle, true, $params['reason'], !$params['noredirect']);
+ if($retval !== true)
+ $this->dieUsageMsg(array($retval));
+
+ $r = array('from' => $fromTitle->getPrefixedText(), 'to' => $toTitle->getPrefixedText(), 'reason' => $params['reason']);
+ if(!$params['noredirect'])
+ $r['redirectcreated'] = '';
+
+ if($params['movetalk'] && $fromTalk->exists() && !$fromTitle->isTalkPage())
+ {
+ // We need to move the talk page as well
+ $toTalk = $toTitle->getTalkPage();
+ $retval = $fromTalk->moveTo($toTalk, true, $params['reason'], !$params['noredirect']);
+ if($retval === true)
+ {
+ $r['talkfrom'] = $fromTalk->getPrefixedText();
+ $r['talkto'] = $toTalk->getPrefixedText();
+ }
+ // We're not gonna dieUsage() on failure, since we already changed something
+ else
+ {
+ $r['talkmove-error-code'] = ApiBase::$messageMap[$retval]['code'];
+ $r['talkmove-error-info'] = ApiBase::$messageMap[$retval]['info'];
+ }
+ }
+ $dbw->commit(); // Make sure all changes are really written to the DB
+ $this->getResult()->addValue(null, $this->getModuleName(), $r);
+ }
+
+ public function mustBePosted() { return true; }
+
+ public function getAllowedParams() {
+ return array (
+ 'from' => null,
+ 'to' => null,
+ 'token' => null,
+ 'reason' => null,
+ 'movetalk' => false,
+ 'noredirect' => false
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'from' => 'Title of the page you want to move.',
+ 'to' => 'Title you want to rename the page to.',
+ 'token' => 'A move token previously retrieved through prop=info',
+ 'reason' => 'Reason for the move (optional).',
+ 'movetalk' => 'Move the talk page, if it exists.',
+ 'noredirect' => 'Don\'t create a redirect'
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Moves a page.'
+ );
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=move&from=Exampel&to=Example&token=123ABC&reason=Misspelled%20title&movetalk&noredirect'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiMove.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiOpenSearch.php b/includes/api/ApiOpenSearch.php
index 8484b163..f4b600fe 100644
--- a/includes/api/ApiOpenSearch.php
+++ b/includes/api/ApiOpenSearch.php
@@ -44,37 +44,12 @@ class ApiOpenSearch extends ApiBase {
public function execute() {
$params = $this->extractRequestParams();
$search = $params['search'];
+ $limit = $params['limit'];
// Open search results may be stored for a very long time
$this->getMain()->setCacheMaxAge(1200);
-
- $title = Title :: newFromText($search);
- if(!$title)
- return; // Return empty result
-
- // Prepare nested request
- $req = new FauxRequest(array (
- 'action' => 'query',
- 'list' => 'allpages',
- 'apnamespace' => $title->getNamespace(),
- 'aplimit' => 10,
- 'apprefix' => $title->getDBkey()
- ));
-
- // Execute
- $module = new ApiMain($req);
- $module->execute();
-
- // Get resulting data
- $data = $module->getResultData();
-
- // Reformat useful data for future printing by JSON engine
- $srchres = array ();
- foreach ($data['query']['allpages'] as & $pageinfo) {
- // Note: this data will no be printable by the xml engine
- // because it does not support lists of unnamed items
- $srchres[] = $pageinfo['title'];
- }
+
+ $srchres = PrefixSearch::titleSearch( $search, $limit );
// Set top level elements
$result = $this->getResult();
@@ -82,19 +57,27 @@ class ApiOpenSearch extends ApiBase {
$result->addValue(null, 1, $srchres);
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
- 'search' => null
+ 'search' => null,
+ 'limit' => array (
+ ApiBase :: PARAM_DFLT => 10,
+ ApiBase :: PARAM_TYPE => 'limit',
+ ApiBase :: PARAM_MIN => 1,
+ ApiBase :: PARAM_MAX => 100,
+ ApiBase :: PARAM_MAX2 => 100
+ )
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
- 'search' => 'Search string'
+ 'search' => 'Search string',
+ 'limit' => 'Maximum amount of results to return'
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'This module implements OpenSearch protocol';
}
@@ -105,7 +88,7 @@ class ApiOpenSearch extends ApiBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiOpenSearch.php 24099 2007-07-15 00:52:35Z yurik $';
+ return __CLASS__ . ': $Id: ApiOpenSearch.php 30275 2008-01-30 01:07:49Z brion $';
}
}
diff --git a/includes/api/ApiParamInfo.php b/includes/api/ApiParamInfo.php
new file mode 100644
index 00000000..7de22252
--- /dev/null
+++ b/includes/api/ApiParamInfo.php
@@ -0,0 +1,167 @@
+<?php
+
+/*
+ * Created on Dec 01, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2008 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+/**
+ * @addtogroup API
+ */
+class ApiParamInfo extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ // Get parameters
+ $params = $this->extractRequestParams();
+ $result = $this->getResult();
+ $r = array();
+ if(is_array($params['modules']))
+ {
+ $modArr = $this->getMain()->getModules();
+ foreach($params['modules'] as $m)
+ {
+ if(!isset($modArr[$m]))
+ {
+ $r['modules'][] = array('name' => $m, 'missing' => '');
+ continue;
+ }
+ $obj = new $modArr[$m]($this->getMain(), $m);
+ $a = $this->getClassInfo($obj);
+ $a['name'] = $m;
+ $r['modules'][] = $a;
+ }
+ $result->setIndexedTagName($r['modules'], 'module');
+ }
+ if(is_array($params['querymodules']))
+ {
+ $queryObj = new ApiQuery($this->getMain(), 'query');
+ $qmodArr = $queryObj->getModules();
+ foreach($params['querymodules'] as $qm)
+ {
+ if(!isset($qmodArr[$qm]))
+ {
+ $r['querymodules'][] = array('name' => $qm, 'missing' => '');
+ continue;
+ }
+ $obj = new $qmodArr[$qm]($this, $qm);
+ $a = $this->getClassInfo($obj);
+ $a['name'] = $qm;
+ $r['querymodules'][] = $a;
+ }
+ $result->setIndexedTagName($r['querymodules'], 'module');
+ }
+ $result->addValue(null, $this->getModuleName(), $r);
+ }
+
+ function getClassInfo($obj)
+ {
+ $result = $this->getResult();
+ $retval['classname'] = get_class($obj);
+ $retval['description'] = (is_array($obj->getDescription()) ? implode("\n", $obj->getDescription()) : $obj->getDescription());
+ $retval['prefix'] = $obj->getModulePrefix();
+ $allowedParams = $obj->getAllowedParams();
+ if(!is_array($allowedParams))
+ return $retval;
+ $retval['parameters'] = array();
+ $paramDesc = $obj->getParamDescription();
+ foreach($obj->getAllowedParams() as $n => $p)
+ {
+ $a = array('name' => $n);
+ if(!is_array($p))
+ {
+ if(is_bool($p))
+ {
+ $a['type'] = 'bool';
+ $a['default'] = ($p ? 'true' : 'false');
+ }
+ if(is_string($p))
+ $a['default'] = $p;
+ $retval['parameters'][] = $a;
+ continue;
+ }
+
+ if(isset($p[ApiBase::PARAM_DFLT]))
+ $a['default'] = $p[ApiBase::PARAM_DFLT];
+ if(isset($p[ApiBase::PARAM_ISMULTI]))
+ if($p[ApiBase::PARAM_ISMULTI])
+ $a['multi'] = '';
+ if(isset($p[ApiBase::PARAM_TYPE]))
+ {
+ $a['type'] = $p[ApiBase::PARAM_TYPE];
+ if(is_array($a['type']))
+ $result->setIndexedTagName($a['type'], 't');
+ }
+ if(isset($p[ApiBase::PARAM_MAX]))
+ $a['max'] = $p[ApiBase::PARAM_MAX];
+ if(isset($p[ApiBase::PARAM_MAX2]))
+ $a['highmax'] = $p[ApiBase::PARAM_MAX2];
+ if(isset($p[ApiBase::PARAM_MIN]))
+ $a['min'] = $p[ApiBase::PARAM_MIN];
+ if(isset($paramDesc[$n]))
+ $a['description'] = (is_array($paramDesc[$n]) ? implode("\n", $paramDesc[$n]) : $paramDesc[$n]);
+ $retval['parameters'][] = $a;
+ }
+ $result->setIndexedTagName($retval['parameters'], 'param');
+ return $retval;
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'modules' => array(
+ ApiBase :: PARAM_ISMULTI => true
+ ),
+ 'querymodules' => array(
+ ApiBase :: PARAM_ISMULTI => true
+ )
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'modules' => 'List of module names (value of the action= parameter)',
+ 'querymodules' => 'List of query module names (value of prop=, meta= or list= parameter)',
+ );
+ }
+
+ public function getDescription() {
+ return 'Obtain information about certain API parameters';
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=paraminfo&modules=parse&querymodules=allpages|siteinfo'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiParse.php 29810 2008-01-15 21:33:08Z catrope $';
+ }
+}
+
diff --git a/includes/api/ApiParse.php b/includes/api/ApiParse.php
new file mode 100644
index 00000000..21a21e8d
--- /dev/null
+++ b/includes/api/ApiParse.php
@@ -0,0 +1,202 @@
+<?php
+
+/*
+ * Created on Dec 01, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Yuri Astrakhan <Firstname><Lastname>@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+/**
+ * @addtogroup API
+ */
+class ApiParse extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ // Get parameters
+ $params = $this->extractRequestParams();
+ $text = $params['text'];
+ $title = $params['title'];
+ $page = $params['page'];
+ if(!is_null($page) && (!is_null($text) || $title != "API"))
+ $this->dieUsage("The page parameter cannot be used together with the text and title parameters", 'params');
+ $prop = array_flip($params['prop']);
+
+ global $wgParser, $wgUser;
+ if(!is_null($page)) {
+ $titleObj = Title::newFromText($page);
+ if(!$titleObj)
+ $this->dieUsageMsg(array('missingtitle', $page));
+
+ // Try the parser cache first
+ $articleObj = new Article($titleObj);
+ $pcache =& ParserCache::singleton();
+ $p_result = $pcache->get($articleObj, $wgUser);
+ if(!$p_result) {
+ $p_result = $wgParser->parse($articleObj->getContent(), $titleObj, new ParserOptions());
+ global $wgUseParserCache;
+ if($wgUseParserCache)
+ $pcache->save($p_result, $articleObj, $wgUser);
+ }
+ } else {
+ $titleObj = Title::newFromText($title);
+ if(!$titleObj)
+ $titleObj = Title::newFromText("API");
+ $p_result = $wgParser->parse($text, $titleObj, new ParserOptions());
+ }
+
+ // Return result
+ $result = $this->getResult();
+ $result_array = array();
+ if(isset($prop['text'])) {
+ $result_array['text'] = array();
+ $result->setContent($result_array['text'], $p_result->getText());
+ }
+ if(isset($prop['langlinks']))
+ $result_array['langlinks'] = $this->formatLangLinks($p_result->getLanguageLinks());
+ if(isset($prop['categories']))
+ $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories());
+ if(isset($prop['links']))
+ $result_array['links'] = $this->formatLinks($p_result->getLinks());
+ if(isset($prop['templates']))
+ $result_array['templates'] = $this->formatLinks($p_result->getTemplates());
+ if(isset($prop['images']))
+ $result_array['images'] = array_keys($p_result->getImages());
+ if(isset($prop['externallinks']))
+ $result_array['externallinks'] = array_keys($p_result->getExternalLinks());
+ if(isset($prop['sections']))
+ $result_array['sections'] = $p_result->getSections();
+
+ $result_mapping = array(
+ 'langlinks' => 'll',
+ 'categories' => 'cl',
+ 'links' => 'pl',
+ 'templates' => 'tl',
+ 'images' => 'img',
+ 'externallinks' => 'el',
+ 'sections' => 's',
+ );
+ $this->setIndexedTagNames( $result_array, $result_mapping );
+ $result->addValue( null, $this->getModuleName(), $result_array );
+ }
+
+ private function formatLangLinks( $links ) {
+ $result = array();
+ foreach( $links as $link ) {
+ $entry = array();
+ $bits = split( ':', $link, 2 );
+ $entry['lang'] = $bits[0];
+ $this->getResult()->setContent( $entry, $bits[1] );
+ $result[] = $entry;
+ }
+ return $result;
+ }
+
+ private function formatCategoryLinks( $links ) {
+ $result = array();
+ foreach( $links as $link => $sortkey ) {
+ $entry = array();
+ $entry['sortkey'] = $sortkey;
+ $this->getResult()->setContent( $entry, $link );
+ $result[] = $entry;
+ }
+ return $result;
+ }
+
+ private function formatLinks( $links ) {
+ $result = array();
+ foreach( $links as $ns => $nslinks ) {
+ foreach( $nslinks as $title => $id ) {
+ $entry = array();
+ $entry['ns'] = $ns;
+ $this->getResult()->setContent( $entry, Title::makeTitle( $ns, $title )->getFullText() );
+ if( $id != 0 )
+ $entry['exists'] = '';
+ $result[] = $entry;
+ }
+ }
+ return $result;
+ }
+
+ private function setIndexedTagNames( &$array, $mapping ) {
+ foreach( $mapping as $key => $name ) {
+ if( isset( $array[$key] ) )
+ $this->getResult()->setIndexedTagName( $array[$key], $name );
+ }
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'title' => array(
+ ApiBase :: PARAM_DFLT => 'API',
+ ),
+ 'text' => null,
+ 'page' => null,
+ 'prop' => array(
+ ApiBase :: PARAM_DFLT => 'text|langlinks|categories|links|templates|images|externallinks|sections',
+ ApiBase :: PARAM_ISMULTI => true,
+ ApiBase :: PARAM_TYPE => array(
+ 'text',
+ 'langlinks',
+ 'categories',
+ 'links',
+ 'templates',
+ 'images',
+ 'externallinks',
+ 'sections'
+ )
+ )
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'text' => 'Wikitext to parse',
+ 'title' => 'Title of page the text belongs to',
+ 'page' => 'Parse the content of this page. Cannot be used together with text and title',
+ 'prop' => array('Which pieces of information to get.',
+ 'NOTE: Section tree is only generated if there are more than 4 sections, or if the __TOC__ keyword is present'
+ ),
+ );
+ }
+
+ public function getDescription() {
+ return 'This module parses wikitext and returns parser output';
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=parse&text={{Project:Sandbox}}'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiParse.php 30262 2008-01-29 14:47:27Z catrope $';
+ }
+}
+
diff --git a/includes/api/ApiProtect.php b/includes/api/ApiProtect.php
new file mode 100644
index 00000000..40a4b73d
--- /dev/null
+++ b/includes/api/ApiProtect.php
@@ -0,0 +1,154 @@
+<?php
+
+/*
+ * Created on Sep 1, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+/**
+ * @addtogroup API
+ */
+class ApiProtect extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ global $wgUser;
+ $this->getMain()->requestWriteMode();
+ $params = $this->extractRequestParams();
+
+ $titleObj = NULL;
+ if(!isset($params['title']))
+ $this->dieUsageMsg(array('missingparam', 'title'));
+ if(!isset($params['token']))
+ $this->dieUsageMsg(array('missingparam', 'token'));
+ if(!isset($params['protections']) || empty($params['protections']))
+ $this->dieUsageMsg(array('missingparam', 'protections'));
+
+ if(!$wgUser->matchEditToken($params['token']))
+ $this->dieUsageMsg(array('sessionfailure'));
+
+ $titleObj = Title::newFromText($params['title']);
+ if(!$titleObj)
+ $this->dieUsageMsg(array('invalidtitle', $params['title']));
+
+ $errors = $titleObj->getUserPermissionsErrors('protect', $wgUser);
+ if(!empty($errors))
+ // We don't care about multiple errors, just report one of them
+ $this->dieUsageMsg(current($errors));
+
+ if(in_array($params['expiry'], array('infinite', 'indefinite', 'never')))
+ $expiry = Block::infinity();
+ else
+ {
+ $expiry = strtotime($params['expiry']);
+ if($expiry < 0 || $expiry == false)
+ $this->dieUsageMsg(array('invalidexpiry'));
+
+ $expiry = wfTimestamp(TS_MW, $expiry);
+ if($expiry < wfTimestampNow())
+ $this->dieUsageMsg(array('pastexpiry'));
+ }
+
+ $protections = array();
+ foreach($params['protections'] as $prot)
+ {
+ $p = explode('=', $prot);
+ $protections[$p[0]] = ($p[1] == 'all' ? '' : $p[1]);
+ if($titleObj->exists() && $p[0] == 'create')
+ $this->dieUsageMsg(array('create-titleexists'));
+ if(!$titleObj->exists() && $p[0] != 'create')
+ $this->dieUsageMsg(array('missingtitles-createonly'));
+ }
+
+ $dbw = wfGetDb(DB_MASTER);
+ $dbw->begin();
+ if($titleObj->exists()) {
+ $articleObj = new Article($titleObj);
+ $ok = $articleObj->updateRestrictions($protections, $params['reason'], $params['cascade'], $expiry);
+ } else
+ $ok = $titleObj->updateTitleProtection($protections['create'], $params['reason'], $expiry);
+ 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());
+ $dbw->commit();
+ $res = array('title' => $titleObj->getPrefixedText(), 'reason' => $params['reason']);
+ if($expiry == Block::infinity())
+ $res['expiry'] = 'infinity';
+ else
+ $res['expiry'] = wfTimestamp(TS_ISO_8601, $expiry);
+
+ if($params['cascade'])
+ $res['cascade'] = '';
+ $res['protections'] = $protections;
+ $this->getResult()->addValue(null, $this->getModuleName(), $res);
+ }
+
+ public function mustBePosted() { return true; }
+
+ public function getAllowedParams() {
+ return array (
+ 'title' => null,
+ 'token' => null,
+ 'protections' => array(
+ ApiBase :: PARAM_ISMULTI => true
+ ),
+ 'expiry' => 'infinite',
+ 'reason' => '',
+ 'cascade' => false
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'title' => 'Title of the page you want to restore.',
+ 'token' => 'A protect token previously retrieved through prop=info',
+ 'protections' => 'Pipe-separated list of protection levels, formatted action=group (e.g. edit=sysop)',
+ 'expiry' => 'Expiry timestamp. If set to \'infinite\', \'indefinite\' or \'never\', the protection will never expire.',
+ 'reason' => 'Reason for (un)protecting (optional)',
+ 'cascade' => 'Enable cascading protection (i.e. protect pages included in this page)'
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Change the protection level of a page.'
+ );
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=protect&title=Main%20Page&token=123ABC&protections=edit=sysop|move=sysop&cascade&expiry=20070901163000',
+ 'api.php?action=protect&title=Main%20Page&token=123ABC&protections=edit=all|move=all&reason=Lifting%20restrictions'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiProtect.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php
index 76dbb338..29abd859 100644
--- a/includes/api/ApiQuery.php
+++ b/includes/api/ApiQuery.php
@@ -60,9 +60,12 @@ class ApiQuery extends ApiBase {
private $mQueryListModules = array (
'allpages' => 'ApiQueryAllpages',
'alllinks' => 'ApiQueryAllLinks',
+ 'allcategories' => 'ApiQueryAllCategories',
'allusers' => 'ApiQueryAllUsers',
'backlinks' => 'ApiQueryBacklinks',
+ 'blocks' => 'ApiQueryBlocks',
'categorymembers' => 'ApiQueryCategoryMembers',
+ 'deletedrevs' => 'ApiQueryDeletedrevs',
'embeddedin' => 'ApiQueryBacklinks',
'imageusage' => 'ApiQueryBacklinks',
'logevents' => 'ApiQueryLogEvents',
@@ -71,11 +74,14 @@ class ApiQuery extends ApiBase {
'usercontribs' => 'ApiQueryContributions',
'watchlist' => 'ApiQueryWatchlist',
'exturlusage' => 'ApiQueryExtLinksUsage',
+ 'users' => 'ApiQueryUsers',
+ 'random' => 'ApiQueryRandom',
);
private $mQueryMetaModules = array (
'siteinfo' => 'ApiQuerySiteinfo',
'userinfo' => 'ApiQueryUserInfo',
+ 'allmessages' => 'ApiQueryAllmessages',
);
private $mSlaveDB = null;
@@ -143,6 +149,13 @@ class ApiQuery extends ApiBase {
public function getPageSet() {
return $this->mPageSet;
}
+
+ /**
+ * Get the array mapping module names to class names
+ */
+ function getModules() {
+ return array_merge($this->mQueryPropModules, $this->mQueryListModules, $this->mQueryMetaModules);
+ }
/**
* Query execution happens in the following steps:
@@ -375,7 +388,7 @@ class ApiQuery extends ApiBase {
* Returns the list of allowed parameters for this module.
* Qurey module also lists all ApiPageSet parameters as its own.
*/
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'prop' => array (
ApiBase :: PARAM_ISMULTI => true,
@@ -456,8 +469,13 @@ class ApiQuery extends ApiBase {
$psModule = new ApiPageSet($this);
return $psModule->makeHelpMsgParameters() . parent :: makeHelpMsgParameters();
}
+
+ // @todo should work correctly
+ public function shouldCheckMaxlag() {
+ return true;
+ }
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => 'Which properties to get for the titles/revisions/pageids',
'list' => 'Which lists to get',
@@ -468,7 +486,7 @@ class ApiQuery extends ApiBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return array (
'Query API module allows applications to get needed pieces of data from the MediaWiki databases,',
'and is loosely based on the Query API interface currently available on all MediaWiki servers.',
@@ -485,7 +503,7 @@ class ApiQuery extends ApiBase {
public function getVersion() {
$psModule = new ApiPageSet($this);
$vers = array ();
- $vers[] = __CLASS__ . ': $Id: ApiQuery.php 24494 2007-07-31 17:53:37Z yurik $';
+ $vers[] = __CLASS__ . ': $Id: ApiQuery.php 30222 2008-01-28 19:05:26Z catrope $';
$vers[] = $psModule->getVersion();
return $vers;
}
diff --git a/includes/api/ApiQueryAllCategories.php b/includes/api/ApiQueryAllCategories.php
new file mode 100644
index 00000000..84494876
--- /dev/null
+++ b/includes/api/ApiQueryAllCategories.php
@@ -0,0 +1,142 @@
+<?php
+
+/*
+ * Created on December 12, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+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.
+ *
+ * @addtogroup API
+ */
+class ApiQueryAllCategories extends ApiQueryGeneratorBase {
+
+ public function __construct($query, $moduleName) {
+ parent :: __construct($query, $moduleName, 'ac');
+ }
+
+ public function execute() {
+ $this->run();
+ }
+
+ public function executeGenerator($resultPageSet) {
+ $this->run($resultPageSet);
+ }
+
+ private function run($resultPageSet = null) {
+
+ $db = $this->getDB();
+ $params = $this->extractRequestParams();
+
+ $this->addTables('categorylinks');
+ $this->addFields('cl_to');
+
+ if (!is_null($params['from']))
+ $this->addWhere('cl_to>=' . $db->addQuotes(ApiQueryBase :: titleToKey($params['from'])));
+ if (isset ($params['prefix']))
+ $this->addWhere("cl_to LIKE '" . $db->escapeLike(ApiQueryBase :: titleToKey($params['prefix'])) . "%'");
+
+ $this->addOption('LIMIT', $params['limit']+1);
+ $this->addOption('ORDER BY', 'cl_to' . ($params['dir'] == 'descending' ? ' DESC' : ''));
+ $this->addOption('DISTINCT');
+
+ $res = $this->select(__METHOD__);
+
+ $pages = array();
+ $count = 0;
+ while ($row = $db->fetchObject($res)) {
+ if (++ $count > $params['limit']) {
+ // We've reached the one extra which shows that there are additional cats to be had. Stop here...
+ // TODO: Security issue - if the user has no right to view next title, it will still be shown
+ $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->cl_to));
+ break;
+ }
+
+ // Normalize titles
+ $titleObj = Title::makeTitle(NS_CATEGORY, $row->cl_to);
+ if(!is_null($resultPageSet))
+ $pages[] = $titleObj->getPrefixedText();
+ else
+ // Don't show "Category:" everywhere in non-generator mode
+ $pages[] = $titleObj->getText();
+ }
+ $db->freeResult($res);
+
+ if (is_null($resultPageSet)) {
+ $result = $this->getResult();
+ $result->setIndexedTagName($pages, 'c');
+ $result->addValue('query', $this->getModuleName(), $pages);
+ } else {
+ $resultPageSet->populateFromTitles($pages);
+ }
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'from' => null,
+ 'prefix' => null,
+ 'dir' => array(
+ ApiBase :: PARAM_DFLT => 'ascending',
+ ApiBase :: PARAM_TYPE => array(
+ 'ascending',
+ 'descending'
+ ),
+ ),
+ 'limit' => array (
+ ApiBase :: PARAM_DFLT => 10,
+ ApiBase :: PARAM_TYPE => 'limit',
+ ApiBase :: PARAM_MIN => 1,
+ ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
+ ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
+ )
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'from' => 'The category to start enumerating from.',
+ 'prefix' => 'Search for all category titles that begin with this value.',
+ 'dir' => 'Direction to sort in.',
+ 'limit' => 'How many categories to return.'
+ );
+ }
+
+ public function getDescription() {
+ return 'Enumerate all categories';
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=query&generator=allcategories&gacprefix=List&prop=info',
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryAllLinks.php 28216 2007-12-06 18:33:18Z vasilievvv $';
+ }
+}
diff --git a/includes/api/ApiQueryAllLinks.php b/includes/api/ApiQueryAllLinks.php
index 17f24b65..d5b80644 100644
--- a/includes/api/ApiQueryAllLinks.php
+++ b/includes/api/ApiQueryAllLinks.php
@@ -125,7 +125,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
}
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'from' => null,
'prefix' => null,
@@ -152,7 +152,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'from' => 'The page title to start enumerating from.',
'prefix' => 'Search for all page titles that begin with this value.',
@@ -163,7 +163,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Enumerate all links that point to a given namespace';
}
@@ -174,6 +174,6 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllLinks.php 24453 2007-07-30 08:09:15Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryAllLinks.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php
index 92bcc1a1..e055b3c5 100644
--- a/includes/api/ApiQueryAllUsers.php
+++ b/includes/api/ApiQueryAllUsers.php
@@ -48,8 +48,9 @@ class ApiQueryAllUsers extends ApiQueryBase {
$prop = array_flip($prop);
$fld_editcount = isset($prop['editcount']);
$fld_groups = isset($prop['groups']);
+ $fld_registration = isset($prop['registration']);
} else {
- $fld_editcount = $fld_groups = false;
+ $fld_editcount = $fld_groups = $fld_registration = false;
}
$limit = $params['limit'];
@@ -80,6 +81,9 @@ class ApiQueryAllUsers extends ApiQueryBase {
} else {
$sqlLimit = $limit+1;
}
+
+ if ($fld_registration)
+ $this->addFields('user_registration');
$this->addOption('LIMIT', $sqlLimit);
$this->addTables($tables);
@@ -129,6 +133,8 @@ class ApiQueryAllUsers extends ApiQueryBase {
$lastUserData = array( 'name' => $lastUser );
if ($fld_editcount)
$lastUserData['editcount'] = intval($row->user_editcount);
+ if ($fld_registration)
+ $lastUserData['registration'] = wfTimestamp(TS_ISO_8601, $row->user_registration);
}
@@ -152,7 +158,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
$result->addValue('query', $this->getModuleName(), $data);
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'from' => null,
'prefix' => null,
@@ -164,6 +170,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
ApiBase :: PARAM_TYPE => array (
'editcount',
'groups',
+ 'registration',
)
),
'limit' => array (
@@ -176,7 +183,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'from' => 'The user name to start enumerating from.',
'prefix' => 'Search for all page titles that begin with this value.',
@@ -188,7 +195,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Enumerate all registered users';
}
@@ -199,6 +206,6 @@ class ApiQueryAllUsers extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllUsers.php 24870 2007-08-17 13:01:35Z robchurch $';
+ return __CLASS__ . ': $Id: ApiQueryAllUsers.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryAllmessages.php b/includes/api/ApiQueryAllmessages.php
new file mode 100644
index 00000000..b7c86a91
--- /dev/null
+++ b/includes/api/ApiQueryAllmessages.php
@@ -0,0 +1,129 @@
+<?php
+
+/*
+ * Created on Dec 1, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ('ApiQueryBase.php');
+}
+
+/**
+ * A query action to return messages from site message cache
+ *
+ * @addtogroup API
+ */
+class ApiQueryAllmessages extends ApiQueryBase {
+
+ public function __construct($query, $moduleName) {
+ parent :: __construct($query, $moduleName, 'am');
+ }
+
+ public function execute() {
+ global $wgMessageCache;
+ $params = $this->extractRequestParams();
+
+ if(!is_null($params['lang']))
+ {
+ global $wgLang;
+ $wgLang = Language::factory($params['lang']);
+ }
+
+
+ //Determine which messages should we print
+ $messages_target = array();
+ if( $params['messages'] == '*' ) {
+ $wgMessageCache->loadAllMessages();
+ $message_names = array_keys( array_merge( Language::getMessagesFor( 'en' ), $wgMessageCache->getExtensionMessagesFor( 'en' ) ) );
+ sort( $message_names );
+ $messages_target = $message_names;
+ } else {
+ $messages_target = explode( '|', $params['messages'] );
+ }
+
+ //Filter messages
+ if( isset( $params['filter'] ) ) {
+ $messages_filtered = array();
+ foreach( $messages_target as $message ) {
+ if( strpos( $message, $params['filter'] ) !== false ) { //!== is used because filter can be at the beginnig of the string
+ $messages_filtered[] = $message;
+ }
+ }
+ $messages_target = $messages_filtered;
+ }
+
+ $wgMessageCache->disableTransform();
+
+ //Get all requested messages
+ $messages = array();
+ foreach( $messages_target as $message ) {
+ $message = trim( $message ); //Message list can be formatted like "msg1 | msg2 | msg3", so let's trim() it
+ $messages[$message] = wfMsg( $message );
+ }
+
+ //Print the result
+ $result = $this->getResult();
+ $messages_out = array();
+ foreach( $messages as $name => $value ) {
+ $message = array();
+ $message['name'] = $name;
+ $result->setContent( $message, $value );
+ $messages_out[] = $message;
+ }
+ $result->setIndexedTagName( $messages_out, 'message' );
+ $result->addValue( 'query', $this->getModuleName(), $messages_out );
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'messages' => array (
+ ApiBase :: PARAM_DFLT => '*',
+ ),
+ 'filter' => array(),
+ 'lang' => null,
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'messages' => 'Which messages to output. "*" means all messages',
+ 'filter' => 'Return only messages that contains specified string',
+ 'lang' => 'Language code',
+ );
+ }
+
+ public function getDescription() {
+ return 'Return messages from this site.';
+ }
+
+ protected function getExamples() {
+ return array(
+ 'api.php?action=query&meta=allmessages&amfilter=ipb-',
+ 'api.php?action=query&meta=allmessages&ammessages=august|mainpage&amlang=de',
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryAllmessages.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiQueryAllpages.php b/includes/api/ApiQueryAllpages.php
index d9715b1a..280d1de2 100644
--- a/includes/api/ApiQueryAllpages.php
+++ b/includes/api/ApiQueryAllpages.php
@@ -86,6 +86,8 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
$prlevel = $params['prlevel'];
if (!is_null($prlevel) && $prlevel != '' && $prlevel != '*')
$this->addWhereFld('pr_level', $prlevel);
+
+ $this->addOption('DISTINCT');
$forceNameTitleIndex = false;
@@ -93,10 +95,22 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
$this->dieUsage('prlevel may not be used without prtype', 'params');
}
- $this->addTables('page');
+ if($params['filterlanglinks'] == 'withoutlanglinks') {
+ $pageName = $this->getDB()->tableName('page');
+ $llName = $this->getDB()->tableName('langlinks');
+ $tables = "$pageName LEFT JOIN $llName ON page_id=ll_from";
+ $this->addWhere('ll_from IS NULL');
+ $this->addTables($tables);
+ $forceNameTitleIndex = false;
+ } else if($params['filterlanglinks'] == 'withlanglinks') {
+ $this->addTables(array('page', 'langlinks'));
+ $this->addWhere('page_id=ll_from');
+ $forceNameTitleIndex = false;
+ } else {
+ $this->addTables('page');
+ }
if ($forceNameTitleIndex)
$this->addOption('USE INDEX', 'name_title');
-
if (is_null($resultPageSet)) {
$this->addFields(array (
@@ -110,7 +124,8 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
$limit = $params['limit'];
$this->addOption('LIMIT', $limit+1);
- $this->addOption('ORDER BY', 'page_namespace, page_title');
+ $this->addOption('ORDER BY', 'page_namespace, page_title' .
+ ($params['dir'] == 'descending' ? ' DESC' : ''));
$res = $this->select(__METHOD__);
@@ -143,7 +158,7 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
}
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
global $wgRestrictionTypes, $wgRestrictionLevels;
return array (
@@ -169,9 +184,11 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
),
'prtype' => array (
ApiBase :: PARAM_TYPE => $wgRestrictionTypes,
+ ApiBase :: PARAM_ISMULTI => true
),
'prlevel' => array (
ApiBase :: PARAM_TYPE => $wgRestrictionLevels,
+ ApiBase :: PARAM_ISMULTI => true
),
'limit' => array (
ApiBase :: PARAM_DFLT => 10,
@@ -179,25 +196,42 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
ApiBase :: PARAM_MIN => 1,
ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
+ ),
+ 'dir' => array (
+ ApiBase :: PARAM_DFLT => 'ascending',
+ ApiBase :: PARAM_TYPE => array (
+ 'ascending',
+ 'descending'
+ )
+ ),
+ 'filterlanglinks' => array(
+ ApiBase :: PARAM_TYPE => array(
+ 'withlanglinks',
+ 'withoutlanglinks',
+ 'all'
+ ),
+ ApiBase :: PARAM_DFLT => 'all'
)
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'from' => 'The page title to start enumerating from.',
'prefix' => 'Search for all page titles that begin with this value.',
'namespace' => 'The namespace to enumerate.',
'filterredir' => 'Which pages to list.',
+ 'dir' => 'The direction in which to list',
'minsize' => 'Limit to pages with at least this many bytes',
'maxsize' => 'Limit to pages with at most this many bytes',
'prtype' => 'Limit to protected pages only',
'prlevel' => 'The protection level (must be used with apprtype= parameter)',
+ 'filterlanglinks' => 'Filter based on whether a page has langlinks',
'limit' => 'How many total pages to return.'
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Enumerate all pages sequentially in a given namespace';
}
@@ -215,7 +249,7 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryAllpages.php 24694 2007-08-09 08:41:58Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryAllpages.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryBacklinks.php b/includes/api/ApiQueryBacklinks.php
index a676b4bf..1ca5c33a 100644
--- a/includes/api/ApiQueryBacklinks.php
+++ b/includes/api/ApiQueryBacklinks.php
@@ -179,7 +179,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
}
$db->freeResult($res);
- if (is_null($resultPageSet) && !empty($data)) {
+ if (is_null($resultPageSet)) {
$result = $this->getResult();
$result->setIndexedTagName($data, $this->bl_code);
$result->addValue('query', $this->getModuleName(), $data);
@@ -315,7 +315,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
'|' . $lastPageID;
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'title' => null,
@@ -343,7 +343,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'title' => 'Title to search. If null, titles= parameter will be used instead, but will be obsolete soon.',
'continue' => 'When more results are available, use this to continue.',
@@ -354,7 +354,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
switch ($this->getModuleName()) {
case 'backlinks' :
return 'Find all pages that link to the given page';
@@ -387,7 +387,7 @@ class ApiQueryBacklinks extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryBacklinks.php 25476 2007-09-04 14:44:46Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryBacklinks.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php
index c810cfa7..031e3c02 100644
--- a/includes/api/ApiQueryBase.php
+++ b/includes/api/ApiQueryBase.php
@@ -110,8 +110,9 @@ abstract class ApiQueryBase extends ApiBase {
if (!is_null($end))
$this->addWhere($field . $before . $db->addQuotes($end));
-
- $this->addOption('ORDER BY', $field . ($isDirNewer ? '' : ' DESC'));
+
+ if (!isset($this->options['ORDER BY']))
+ $this->addOption('ORDER BY', $field . ($isDirNewer ? '' : ' DESC'));
}
protected function addOption($name, $value = null) {
@@ -230,7 +231,7 @@ abstract class ApiQueryBase extends ApiBase {
}
public static function getBaseVersion() {
- return __CLASS__ . ': $Id: ApiQueryBase.php 24533 2007-08-01 22:46:22Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryBase.php 31484 2008-03-03 05:46:20Z brion $';
}
}
diff --git a/includes/api/ApiQueryBlocks.php b/includes/api/ApiQueryBlocks.php
new file mode 100644
index 00000000..165792b5
--- /dev/null
+++ b/includes/api/ApiQueryBlocks.php
@@ -0,0 +1,239 @@
+<?php
+
+/*
+ * Created on Sep 10, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ('ApiQueryBase.php');
+}
+
+/**
+ * Query module to enumerate all available pages.
+ *
+ * @addtogroup API
+ */
+class ApiQueryBlocks extends ApiQueryBase {
+
+ public function __construct($query, $moduleName) {
+ parent :: __construct($query, $moduleName, 'bk');
+ }
+
+ public function execute() {
+ $this->run();
+ }
+
+ private function run() {
+ global $wgUser;
+
+ $params = $this->extractRequestParams();
+ $prop = array_flip($params['prop']);
+ $fld_id = isset($prop['id']);
+ $fld_user = isset($prop['user']);
+ $fld_by = isset($prop['by']);
+ $fld_timestamp = isset($prop['timestamp']);
+ $fld_expiry = isset($prop['expiry']);
+ $fld_reason = isset($prop['reason']);
+ $fld_range = isset($prop['range']);
+ $fld_flags = isset($prop['flags']);
+
+ $result = $this->getResult();
+ $pageSet = $this->getPageSet();
+ $titles = $pageSet->getTitles();
+ $data = array();
+
+ $this->addTables('ipblocks');
+ if($fld_id)
+ $this->addFields('ipb_id');
+ if($fld_user)
+ $this->addFields(array('ipb_address', 'ipb_user'));
+ if($fld_by)
+ {
+ $this->addTables('user');
+ $this->addFields(array('ipb_by', 'user_name'));
+ $this->addWhere('user_id = ipb_by');
+ }
+ if($fld_timestamp)
+ $this->addFields('ipb_timestamp');
+ if($fld_expiry)
+ $this->addFields('ipb_expiry');
+ if($fld_reason)
+ $this->addFields('ipb_reason');
+ if($fld_range)
+ $this->addFields(array('ipb_range_start', 'ipb_range_end'));
+ if($fld_flags)
+ $this->addFields(array('ipb_auto', 'ipb_anon_only', 'ipb_create_account', 'ipb_enable_autoblock', 'ipb_block_email', 'ipb_deleted'));
+
+ $this->addOption('LIMIT', $params['limit'] + 1);
+ $this->addWhereRange('ipb_timestamp', $params['dir'], $params['start'], $params['end']);
+ if(isset($params['ids']))
+ $this->addWhere(array('ipb_id' => $params['ids']));
+ if(isset($params['users']))
+ $this->addWhere(array('ipb_address' => $params['users']));
+ if(!$wgUser->isAllowed('oversight'))
+ $this->addWhere(array('ipb_deleted' => 0));
+
+ // Purge expired entries on one in every 10 queries
+ if(!mt_rand(0, 10))
+ Block::purgeExpired();
+
+ $res = $this->select(__METHOD__);
+ $db = wfGetDB();
+
+ $count = 0;
+ while($row = $db->fetchObject($res))
+ {
+ if($count++ == $params['limit'])
+ {
+ // We've had enough
+ $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->ipb_timestamp));
+ break;
+ }
+ $block = array();
+ if($fld_id)
+ $block['id'] = $row->ipb_id;
+ if($fld_user && !$row->ipb_auto)
+ {
+ $block['user'] = $row->ipb_address;
+ }
+ if($fld_by)
+ {
+ $block['by'] = $row->user_name;
+ }
+ if($fld_timestamp)
+ $block['timestamp'] = wfTimestamp(TS_ISO_8601, $row->ipb_timestamp);
+ if($fld_expiry)
+ $block['expiry'] = Block::decodeExpiry($row->ipb_expiry, TS_ISO_8601);
+ if($fld_reason)
+ $block['reason'] = $row->ipb_reason;
+ if($fld_range)
+ {
+ $block['rangestart'] = $this->convertHexIP($row->ipb_range_start);
+ $block['rangeend'] = $this->convertHexIP($row->ipb_range_end);
+ }
+ if($fld_flags)
+ {
+ // For clarity, these flags use the same names as their action=block counterparts
+ if($row->ipb_auto)
+ $block['automatic'] = '';
+ if($row->ipb_anon_only)
+ $block['anononly'] = '';
+ if($row->ipb_create_account)
+ $block['nocreate'] = '';
+ if($row->ipb_enable_autoblock)
+ $block['autoblock'] = '';
+ if($row->ipb_block_email)
+ $block['noemail'] = '';
+ if($row->ipb_deleted)
+ $block['hidden'] = '';
+ }
+ $data[] = $block;
+ }
+ $result->setIndexedTagName($data, 'block');
+ $result->addValue('query', $this->getModuleName(), $data);
+ }
+
+ protected function convertHexIP($ip)
+ {
+ // Converts a hexadecimal IP to nnn.nnn.nnn.nnn format
+ $dec = wfBaseConvert($ip, 16, 10);
+ $parts[0] = (int)($dec / (256*256*256));
+ $dec %= 256*256*256;
+ $parts[1] = (int)($dec / (256*256));
+ $dec %= 256*256;
+ $parts[2] = (int)($dec / 256);
+ $parts[3] = $dec % 256;
+ return implode('.', $parts);
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'start' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp'
+ ),
+ 'end' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp',
+ ),
+ 'dir' => array(
+ ApiBase :: PARAM_TYPE => array(
+ 'newer',
+ 'older'
+ ),
+ ApiBase :: PARAM_DFLT => 'older'
+ ),
+ 'ids' => array(
+ ApiBase :: PARAM_TYPE => 'integer',
+ ApiBase :: PARAM_ISMULTI => true
+ ),
+ 'users' => array(
+ ApiBase :: PARAM_ISMULTI => true
+ ),
+ 'limit' => array(
+ ApiBase :: PARAM_DFLT => 10,
+ ApiBase :: PARAM_TYPE => 'limit',
+ ApiBase :: PARAM_MIN => 1,
+ ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
+ ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
+ ),
+ 'prop' => array(
+ ApiBase :: PARAM_DFLT => 'id|user|by|timestamp|expiry|reason|flags',
+ ApiBase :: PARAM_TYPE => array(
+ 'id',
+ 'user',
+ 'by',
+ 'timestamp',
+ 'expiry',
+ 'reason',
+ 'range',
+ 'flags'
+ ),
+ ApiBase :: PARAM_ISMULTI => true
+ )
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'start' => 'The timestamp to start enumerating from',
+ 'end' => 'The timestamp to stop enumerating at',
+ 'dir' => 'The direction in which to enumerate',
+ 'ids' => 'Pipe-separated list of block IDs to list (optional)',
+ 'users' => 'Pipe-separated list of users to search for (optional)',
+ 'limit' => 'The maximum amount of blocks to list',
+ 'prop' => 'Which properties to get',
+ );
+ }
+
+ public function getDescription() {
+ return 'List all blocked users and IP addresses.';
+ }
+
+ protected function getExamples() {
+ return array (
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryBlocks.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiQueryCategories.php b/includes/api/ApiQueryCategories.php
index 42bc1c38..63d42bfa 100644
--- a/includes/api/ApiQueryCategories.php
+++ b/includes/api/ApiQueryCategories.php
@@ -120,7 +120,7 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
$db->freeResult($res);
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'prop' => array (
ApiBase :: PARAM_ISMULTI => true,
@@ -131,13 +131,13 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => 'Which additional properties to get for each category.',
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'List all categories the page(s) belong to';
}
@@ -151,7 +151,7 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryCategories.php 24092 2007-07-14 19:04:31Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryCategories.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryCategoryMembers.php b/includes/api/ApiQueryCategoryMembers.php
index 58a454a5..e831f291 100644
--- a/includes/api/ApiQueryCategoryMembers.php
+++ b/includes/api/ApiQueryCategoryMembers.php
@@ -51,12 +51,18 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
$params = $this->extractRequestParams();
- $category = $params['category'];
- if (is_null($category))
- $this->dieUsage("Category parameter is required", 'param_category');
- $categoryTitle = Title::makeTitleSafe( NS_CATEGORY, $category );
- if ( is_null( $categoryTitle ) )
- $this->dieUsage("Category name $category is not valid", 'param_category');
+ if (is_null($params['category'])) {
+ if (is_null($params['title']))
+ $this->dieUsage("Either the cmcategory or the cmtitle parameter is required", 'notitle');
+ else
+ $categoryTitle = Title::newFromText($params['title']);
+ } else if(is_null($params['title']))
+ $categoryTitle = Title::makeTitleSafe(NS_CATEGORY, $params['category']);
+ else
+ $this->dieUsage("The cmcategory and cmtitle parameters can't be used together", 'titleandcategory');
+
+ if ( is_null( $categoryTitle ) || $categoryTitle->getNamespace() != NS_CATEGORY )
+ $this->dieUsage("The category name you entered is not valid", 'invalidcategory');
$prop = array_flip($params['prop']);
$fld_ids = isset($prop['ids']);
@@ -78,18 +84,19 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
if($params['sort'] == 'timestamp')
{
$this->addOption('USE INDEX', 'cl_timestamp');
- $this->addOption('ORDER BY', 'cl_to, cl_timestamp');
+ $this->addOption('ORDER BY', 'cl_to, cl_timestamp' . ($params['dir'] == 'desc' ? ' DESC' : ''));
}
else
{
$this->addOption('USE INDEX', 'cl_sortkey');
- $this->addOption('ORDER BY', 'cl_to, cl_sortkey, cl_from');
+ $this->addOption('ORDER BY', 'cl_to, cl_sortkey' . ($params['dir'] == 'desc' ? ' DESC' : '') . ', cl_from');
}
$this->addWhere('cl_from=page_id');
$this->setContinuation($params['continue']);
$this->addWhereFld('cl_to', $categoryTitle->getDBkey());
$this->addWhereFld('page_namespace', $params['namespace']);
+ $this->addWhereRange('cl_timestamp', ($params['dir'] == 'asc' ? 'newer' : 'older'), $params['start'], $params['end']);
$limit = $params['limit'];
$this->addOption('LIMIT', $limit +1);
@@ -172,9 +179,10 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
}
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
- 'category' => null,
+ 'title' => null,
+ 'category' => null, // DEPRECATED, will be removed in early March
'prop' => array (
ApiBase :: PARAM_DFLT => 'ids|title',
ApiBase :: PARAM_ISMULTI => true,
@@ -203,36 +211,53 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
'sortkey',
'timestamp'
)
+ ),
+ 'dir' => array(
+ ApiBase :: PARAM_DFLT => 'asc',
+ ApiBase :: PARAM_TYPE => array(
+ 'asc',
+ 'desc'
+ )
+ ),
+ 'start' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp'
+ ),
+ 'end' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp'
)
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
- 'category' => 'Which category to enumerate (required)',
+ 'title' => 'Which category to enumerate (required). Must include Category: prefix',
'prop' => 'What pieces of information to include',
'namespace' => 'Only include pages in these namespaces',
'sort' => 'Property to sort by',
+ 'dir' => 'In which direction to sort',
+ 'start' => 'Timestamp to start listing from',
+ 'end' => 'Timestamp to end listing at',
'continue' => 'For large categories, give the value retured from previous query',
'limit' => 'The maximum number of pages to return.',
+ 'category' => 'DEPRECATED. Like title, but without the Category: prefix.',
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'List all pages in a given category';
}
protected function getExamples() {
return array (
- "Get first 10 pages in the categories [[Physics]]:",
- " api.php?action=query&list=categorymembers&cmcategory=Physics",
- "Get page info about first 10 pages in the categories [[Physics]]:",
- " api.php?action=query&generator=categorymembers&gcmcategory=Physics&prop=info",
+ "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",
);
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryCategoryMembers.php 25474 2007-09-04 14:30:31Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryCategoryMembers.php 30670 2008-02-07 15:17:42Z catrope $';
}
}
diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php
new file mode 100644
index 00000000..1b7fbdb0
--- /dev/null
+++ b/includes/api/ApiQueryDeletedrevs.php
@@ -0,0 +1,235 @@
+<?php
+
+/*
+ * Created on Jul 2, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ('ApiQueryBase.php');
+}
+
+/**
+ * Query module to enumerate all available pages.
+ *
+ * @addtogroup API
+ */
+class ApiQueryDeletedrevs extends ApiQueryBase {
+
+ public function __construct($query, $moduleName) {
+ parent :: __construct($query, $moduleName, 'dr');
+ }
+
+ public function execute() {
+
+ global $wgUser;
+ // Before doing anything at all, let's check permissions
+ if(!$wgUser->isAllowed('deletedhistory'))
+ $this->dieUsage('You don\'t have permission to view deleted revision information', 'permissiondenied');
+
+ $db = $this->getDB();
+ $params = $this->extractRequestParams(false);
+ $prop = array_flip($params['prop']);
+ $fld_revid = isset($prop['revid']);
+ $fld_user = isset($prop['user']);
+ $fld_comment = isset($prop['comment']);
+ $fld_minor = isset($prop['minor']);
+ $fld_len = isset($prop['len']);
+ $fld_content = isset($prop['content']);
+ $fld_token = isset($prop['token']);
+
+ $result = $this->getResult();
+ $pageSet = $this->getPageSet();
+ $titles = $pageSet->getTitles();
+ $data = array();
+
+ $this->addTables('archive');
+ $this->addFields(array('ar_title', 'ar_namespace', 'ar_timestamp'));
+ if($fld_revid)
+ $this->addFields('ar_rev_id');
+ if($fld_user)
+ $this->addFields('ar_user_text');
+ if($fld_comment)
+ $this->addFields('ar_comment');
+ if($fld_minor)
+ $this->addFields('ar_minor_edit');
+ if($fld_len)
+ $this->addFields('ar_len');
+ if($fld_content)
+ {
+ $this->addTables('text');
+ $this->addFields(array('ar_text', 'ar_text_id', 'old_text', 'old_flags'));
+ $this->addWhere('ar_text_id = old_id');
+
+ // This also means stricter restrictions
+ if(!$wgUser->isAllowed('undelete'))
+ $this->dieUsage('You don\'t have permission to view deleted revision content', 'permissiondenied');
+ }
+ // Check limits
+ $userMax = $fld_content ? ApiBase :: LIMIT_SML1 : ApiBase :: LIMIT_BIG1;
+ $botMax = $fld_content ? ApiBase :: LIMIT_SML2 : ApiBase :: LIMIT_BIG2;
+ if( $limit == 'max' ) {
+ $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
+ $this->getResult()->addValue( 'limits', 'limit', $limit );
+ }
+ $this->validateLimit('limit', $params['limit'], 1, $userMax, $botMax);
+ if($fld_token)
+ // Undelete tokens are identical for all pages, so we cache one here
+ $token = $wgUser->editToken();
+
+ // We need a custom WHERE clause that matches all titles.
+ if(count($titles) > 0)
+ {
+ $lb = new LinkBatch($titles);
+ $where = $lb->constructSet('ar', $db);
+ $this->addWhere($where);
+ }
+
+ $this->addOption('LIMIT', $params['limit'] + 1);
+ $this->addWhereRange('ar_timestamp', $params['dir'], $params['start'], $params['end']);
+ if(isset($params['namespace']))
+ $this->addWhereFld('ar_namespace', $params['namespace']);
+ $res = $this->select(__METHOD__);
+ $pages = array();
+ $count = 0;
+ // First populate the $pages array
+ while($row = $db->fetchObject($res))
+ {
+ if($count++ == $params['limit'])
+ {
+ // We've had enough
+ $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->ar_timestamp));
+ break;
+ }
+
+ $rev = array();
+ $rev['timestamp'] = wfTimestamp(TS_ISO_8601, $row->ar_timestamp);
+ if($fld_revid)
+ $rev['revid'] = $row->ar_rev_id;
+ if($fld_user)
+ $rev['user'] = $row->ar_user_text;
+ if($fld_comment)
+ $rev['comment'] = $row->ar_comment;
+ if($fld_minor)
+ if($row->ar_minor_edit == 1)
+ $rev['minor'] = '';
+ if($fld_len)
+ $rev['len'] = $row->ar_len;
+ if($fld_content)
+ ApiResult::setContent($rev, Revision::getRevisionText($row));
+
+ $t = Title::makeTitle($row->ar_namespace, $row->ar_title);
+ if(!isset($pages[$t->getPrefixedText()]))
+ {
+ $pages[$t->getPrefixedText()] = array(
+ 'title' => $t->getPrefixedText(),
+ 'ns' => intval($row->ar_namespace),
+ 'revisions' => array($rev)
+ );
+ if($fld_token)
+ $pages[$t->getPrefixedText()]['token'] = $token;
+ }
+ else
+ $pages[$t->getPrefixedText()]['revisions'][] = $rev;
+ }
+ $db->freeResult($res);
+
+ // We don't want entire pagenames as keys, so let's make this array indexed
+ foreach($pages as $page)
+ {
+ $result->setIndexedTagName($page['revisions'], 'rev');
+ $data[] = $page;
+ }
+ $result->setIndexedTagName($data, 'page');
+ $result->addValue('query', $this->getModuleName(), $data);
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'start' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp'
+ ),
+ 'end' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp',
+ ),
+ 'dir' => array(
+ ApiBase :: PARAM_TYPE => array(
+ 'newer',
+ 'older'
+ ),
+ ApiBase :: PARAM_DFLT => 'older'
+ ),
+ 'namespace' => array(
+ ApiBase :: PARAM_ISMULTI => true,
+ ApiBase :: PARAM_TYPE => 'namespace'
+ ),
+ 'limit' => array(
+ ApiBase :: PARAM_DFLT => 10,
+ ApiBase :: PARAM_TYPE => 'limit',
+ ApiBase :: PARAM_MIN => 1,
+ ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
+ ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
+ ),
+ 'prop' => array(
+ ApiBase :: PARAM_DFLT => 'user|comment',
+ ApiBase :: PARAM_TYPE => array(
+ 'revid',
+ 'user',
+ 'comment',
+ 'minor',
+ 'len',
+ 'content',
+ 'token'
+ ),
+ ApiBase :: PARAM_ISMULTI => true
+ )
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'start' => 'The timestamp to start enumerating from',
+ 'end' => 'The timestamp to stop enumerating at',
+ 'dir' => 'The direction in which to enumerate',
+ 'namespace' => 'The namespaces to search in',
+ 'limit' => 'The maximum amount of revisions to list',
+ 'prop' => 'Which properties to get'
+ );
+ }
+
+ public function getDescription() {
+ return 'List deleted revisions.';
+ }
+
+ protected function getExamples() {
+ return array (
+ 'List the first 50 deleted revisions in the Category and Category talk namespaces',
+ ' api.php?action=query&list=deletedrevs&drdir=newer&drlimit=50&drnamespace=14|15',
+ 'List the last deleted revisions of Main Page and Talk:Main Page, with content:',
+ ' api.php?action=query&list=deletedrevs&titles=Main%20Page|Talk:Main%20Page&drprop=user|comment|content'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryDeletedrevs.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiQueryExtLinksUsage.php b/includes/api/ApiQueryExtLinksUsage.php
index 385ae65b..896a0171 100644
--- a/includes/api/ApiQueryExtLinksUsage.php
+++ b/includes/api/ApiQueryExtLinksUsage.php
@@ -134,7 +134,7 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
}
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
global $wgUrlProtocols;
$protocols = array();
foreach ($wgUrlProtocols as $p) {
@@ -173,7 +173,7 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => 'What pieces of information to include',
'offset' => 'Used for paging. Use the value returned for "continue"',
@@ -184,7 +184,7 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Enumerate pages that contain a given URL';
}
@@ -195,6 +195,6 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryExtLinksUsage.php 24694 2007-08-09 08:41:58Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryExtLinksUsage.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryExternalLinks.php b/includes/api/ApiQueryExternalLinks.php
index 440b31d6..07183910 100644
--- a/includes/api/ApiQueryExternalLinks.php
+++ b/includes/api/ApiQueryExternalLinks.php
@@ -75,7 +75,7 @@ class ApiQueryExternalLinks extends ApiQueryBase {
$db->freeResult($res);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Returns all external urls (not interwikies) from the given page(s)';
}
@@ -87,7 +87,7 @@ class ApiQueryExternalLinks extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryExternalLinks.php 23819 2007-07-07 03:05:09Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryExternalLinks.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryImageInfo.php b/includes/api/ApiQueryImageInfo.php
index 3d568ba1..3714ccf6 100644
--- a/includes/api/ApiQueryImageInfo.php
+++ b/includes/api/ApiQueryImageInfo.php
@@ -42,15 +42,20 @@ class ApiQueryImageInfo extends ApiQueryBase {
public function execute() {
$params = $this->extractRequestParams();
- $history = $params['history'];
-
$prop = array_flip($params['prop']);
- $fld_timestamp = isset($prop['timestamp']);
- $fld_user = isset($prop['user']);
- $fld_comment = isset($prop['comment']);
- $fld_url = isset($prop['url']);
- $fld_size = isset($prop['size']);
- $fld_sha1 = isset($prop['sha1']);
+ $this->fld_timestamp = isset($prop['timestamp']);
+ $this->fld_user = isset($prop['user']);
+ $this->fld_comment = isset($prop['comment']);
+ $this->fld_url = isset($prop['url']);
+ $this->fld_size = isset($prop['size']);
+ $this->fld_sha1 = isset($prop['sha1']);
+ $this->fld_metadata = isset($prop['metadata']);
+
+ if($params['urlheight'] != -1 && $params['urlwidth'] == -1)
+ $this->dieUsage("iiurlheight cannot be used without iiurlwidth", 'iiurlwidth');
+ $this->scale = ($params['urlwidth'] != -1);
+ $this->urlwidth = $params['urlwidth'];
+ $this->urlheight = $params['urlheight'];
$pageIds = $this->getPageSet()->getAllTitlesByNamespace();
if (!empty($pageIds[NS_IMAGE])) {
@@ -65,54 +70,84 @@ class ApiQueryImageInfo extends ApiQueryBase {
} else {
$repository = $img->getRepoName();
-
- $isCur = true;
- while($line = $img->nextHistoryLine()) { // assignment
- $row = get_object_vars( $line );
- $vals = array();
- $prefix = $isCur ? 'img' : 'oi';
-
- if ($fld_timestamp)
- $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row["${prefix}_timestamp"]);
- if ($fld_user) {
- $vals['user'] = $row["${prefix}_user_text"];
- if(!$row["${prefix}_user"])
- $vals['anon'] = '';
- }
- if ($fld_size) {
- $vals['size'] = intval($row["{$prefix}_size"]);
- $vals['width'] = intval($row["{$prefix}_width"]);
- $vals['height'] = intval($row["{$prefix}_height"]);
- }
- if ($fld_url)
- $vals['url'] = $isCur ? $img->getURL() : $img->getArchiveUrl($row["oi_archive_name"]);
- if ($fld_comment)
- $vals['comment'] = $row["{$prefix}_description"];
-
- if ($fld_sha1)
- $vals['sha1'] = wfBaseConvert($row["{$prefix}_sha1"], 36, 16, 40);
-
- $data[] = $vals;
-
- if (!$history) // Stop after the first line.
- break;
-
- $isCur = false;
+
+ // Get information about the current version first
+ // Check that the current version is within the start-end boundaries
+ if((is_null($params['start']) || $img->getTimestamp() <= $params['start']) &&
+ (is_null($params['end']) || $img->getTimestamp() >= $params['end'])) {
+ $data[] = $this->getInfo($img);
}
- $img->resetHistory();
+ // Now get the old revisions
+ // Get one more to facilitate query-continue functionality
+ $count = count($data);
+ $oldies = $img->getHistory($params['limit'] - $count + 1, $params['start'], $params['end']);
+ foreach($oldies as $oldie) {
+ if(++$count > $params['limit']) {
+ // We've reached the extra one which shows that there are additional pages to be had. Stop here...
+ // Only set a query-continue if there was only one title
+ if(count($pageIds[NS_IMAGE]) == 1)
+ $this->setContinueEnumParameter('start', $oldie->getTimestamp());
+ break;
+ }
+ $data[] = $this->getInfo($oldie);
+ }
}
- $this->getResult()->addValue(array ('query', 'pages', intval($pageId)),
- 'imagerepository',
- $repository);
- if (!empty($data))
- $this->addPageSubItems($pageId, $data);
+ $this->getResult()->addValue(array(
+ 'query', 'pages', intval($pageId)),
+ 'imagerepository', $repository
+ );
+ if (!empty($data))
+ $this->addPageSubItems($pageId, $data);
}
}
}
- protected function getAllowedParams() {
+ /**
+ * Get result information for an image revision
+ * @param File f The image
+ * @return array Result array
+ */
+ protected function getInfo($f) {
+ $vals = array();
+ if($this->fld_timestamp)
+ $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $f->getTimestamp());
+ if($this->fld_user) {
+ $vals['user'] = $f->getUser();
+ if(!$f->getUser('id'))
+ $vals['anon'] = '';
+ }
+ if($this->fld_size) {
+ $vals['size'] = intval($f->getSize());
+ $vals['width'] = intval($f->getWidth());
+ $vals['height'] = intval($f->getHeight());
+ }
+ if($this->fld_url) {
+ if($this->scale && !$f->isOld()) {
+ $thumb = $f->getThumbnail($this->urlwidth, $this->urlheight);
+ if($thumb)
+ {
+ $vals['thumburl'] = $thumb->getURL();
+ $vals['thumbwidth'] = $thumb->getWidth();
+ $vals['thumbheight'] = $thumb->getHeight();
+ }
+ }
+ $vals['url'] = $f->getURL();
+ }
+ if($this->fld_comment)
+ $vals['comment'] = $f->getDescription();
+ if($this->fld_sha1)
+ $vals['sha1'] = wfBaseConvert($f->getSha1(), 36, 16, 40);
+ if($this->fld_metadata) {
+ $metadata = unserialize($f->getMetadata());
+ $vals['metadata'] = $metadata ? $metadata : null;
+ $this->getResult()->setIndexedTagName_recursive($vals['metadata'], 'meta');
+ }
+ return $vals;
+ }
+
+ public function getAllowedParams() {
return array (
'prop' => array (
ApiBase :: PARAM_ISMULTI => true,
@@ -123,21 +158,46 @@ class ApiQueryImageInfo extends ApiQueryBase {
'comment',
'url',
'size',
- 'sha1'
+ 'sha1',
+ 'metadata'
)
),
- 'history' => false,
+ 'limit' => array(
+ ApiBase :: PARAM_TYPE => 'limit',
+ ApiBase :: PARAM_DFLT => 1,
+ ApiBase :: PARAM_MIN => 1,
+ ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
+ ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
+ ),
+ 'start' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp'
+ ),
+ 'end' => array(
+ ApiBase :: PARAM_TYPE => 'timestamp'
+ ),
+ 'urlwidth' => array(
+ ApiBase :: PARAM_TYPE => 'integer',
+ ApiBase :: PARAM_DFLT => -1
+ ),
+ 'urlheight' => array(
+ ApiBase :: PARAM_TYPE => 'integer',
+ ApiBase :: PARAM_DFLT => -1
+ )
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => 'What image information to get.',
- 'history' => 'Include upload history',
+ 'limit' => 'How many image revisions to return',
+ 'start' => 'Timestamp to start listing from',
+ 'end' => 'Timestamp to stop listing at',
+ 'urlwidth' => 'If iiprop=url is set, a URL to an image scaled to this width will be returned. Only the current version of the image can be scaled.',
+ 'urlheight' => 'Similar to iiurlwidth. Cannot be used without iiurlwidth',
);
}
- protected function getDescription() {
+ public function getDescription() {
return array (
'Returns image information and upload history'
);
@@ -146,11 +206,11 @@ class ApiQueryImageInfo extends ApiQueryBase {
protected function getExamples() {
return array (
'api.php?action=query&titles=Image:Albert%20Einstein%20Head.jpg&prop=imageinfo',
- 'api.php?action=query&titles=Image:Test.jpg&prop=imageinfo&iihistory&iiprop=timestamp|user|url',
+ 'api.php?action=query&titles=Image:Test.jpg&prop=imageinfo&iilimit=50&iiend=20071231235959&iiprop=timestamp|user|url',
);
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryImageInfo.php 25456 2007-09-03 19:58:05Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryImageInfo.php 30665 2008-02-07 12:21:48Z catrope $';
}
}
diff --git a/includes/api/ApiQueryImages.php b/includes/api/ApiQueryImages.php
index d64a653b..f7405374 100644
--- a/includes/api/ApiQueryImages.php
+++ b/includes/api/ApiQueryImages.php
@@ -98,7 +98,7 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
$db->freeResult($res);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Returns all images contained on the given page(s)';
}
@@ -112,7 +112,7 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryImages.php 24092 2007-07-14 19:04:31Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryImages.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php
index bebf4006..2dee22b0 100644
--- a/includes/api/ApiQueryInfo.php
+++ b/includes/api/ApiQueryInfo.php
@@ -40,6 +40,7 @@ class ApiQueryInfo extends ApiQueryBase {
}
public function requestExtraData($pageSet) {
+ $pageSet->requestField('page_restrictions');
$pageSet->requestField('page_is_redirect');
$pageSet->requestField('page_is_new');
$pageSet->requestField('page_counter');
@@ -65,11 +66,16 @@ class ApiQueryInfo extends ApiQueryBase {
$tok_protect = $this->getTokenFlag($token, 'protect');
$tok_move = $this->getTokenFlag($token, 'move');
}
+ else
+ // Fix E_NOTICEs about unset variables
+ $token = $tok_edit = $tok_delete = $tok_protect = $tok_move = null;
$pageSet = $this->getPageSet();
$titles = $pageSet->getGoodTitles();
+ $missing = $pageSet->getMissingTitles();
$result = $this->getResult();
+ $pageRestrictions = $pageSet->getCustomField('page_restrictions');
$pageIsRedir = $pageSet->getCustomField('page_is_redirect');
$pageIsNew = $pageSet->getCustomField('page_is_new');
$pageCounter = $pageSet->getCustomField('page_counter');
@@ -77,23 +83,46 @@ class ApiQueryInfo extends ApiQueryBase {
$pageLatest = $pageSet->getCustomField('page_latest');
$pageLength = $pageSet->getCustomField('page_len');
- if ($fld_protection && count($titles) > 0) {
+ $db = $this->getDB();
+ if ($fld_protection && !empty($titles)) {
$this->addTables('page_restrictions');
- $this->addFields(array('pr_page', 'pr_type', 'pr_level', 'pr_expiry'));
+ $this->addFields(array('pr_page', 'pr_type', 'pr_level', 'pr_expiry', 'pr_cascade'));
$this->addWhereFld('pr_page', array_keys($titles));
- $db = $this->getDB();
$res = $this->select(__METHOD__);
while($row = $db->fetchObject($res)) {
- $protections[$row->pr_page][] = array(
- 'type' => $row->pr_type,
- 'level' => $row->pr_level,
- 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 )
- );
+ $a = array(
+ 'type' => $row->pr_type,
+ 'level' => $row->pr_level,
+ 'expiry' => Block::decodeExpiry( $row->pr_expiry, TS_ISO_8601 )
+ );
+ if($row->pr_cascade)
+ $a['cascade'] = '';
+ $protections[$row->pr_page][] = $a;
}
$db->freeResult($res);
}
-
+ // We don't need to check for pt stuff if there are no nonexistent titles
+ if($fld_protection && !empty($missing))
+ {
+ $this->resetQueryParams();
+ // Construct a custom WHERE clause that matches all titles in $missing
+ $lb = new LinkBatch($missing);
+ $this->addTables('protected_titles');
+ $this->addFields(array('pt_title', 'pt_namespace', 'pt_create_perm', 'pt_expiry'));
+ $this->addWhere($lb->constructSet('pt', $db));
+ $res = $this->select(__METHOD__);
+ $prottitles = array();
+ while($row = $db->fetchObject($res)) {
+ $prottitles[$row->pt_namespace][$row->pt_title] = array(
+ 'type' => 'create',
+ 'level' => $row->pt_create_perm,
+ 'expiry' => Block::decodeExpiry($row->pt_expiry, TS_ISO_8601)
+ );
+ }
+ $db->freeResult($res);
+ }
+
foreach ( $titles as $pageid => $title ) {
$pageInfo = array (
'touched' => wfTimestamp(TS_ISO_8601, $pageTouched[$pageid]),
@@ -125,7 +154,36 @@ class ApiQueryInfo extends ApiQueryBase {
$pageInfo['protection'] = $protections[$pageid];
$result->setIndexedTagName($pageInfo['protection'], 'pr');
} else {
- $pageInfo['protection'] = array();
+ # Also check old restrictions
+ if( $pageRestrictions[$pageid] ) {
+ foreach( explode( ':', trim( $pageRestrictions[$pageid] ) ) as $restrict ) {
+ $temp = explode( '=', trim( $restrict ) );
+ if(count($temp) == 1) {
+ // old old format should be treated as edit/move restriction
+ $restriction = trim( $temp[0] );
+ $pageInfo['protection'][] = array(
+ 'type' => 'edit',
+ 'level' => $restriction,
+ 'expiry' => 'infinity',
+ );
+ $pageInfo['protection'][] = array(
+ 'type' => 'move',
+ 'level' => $restriction,
+ 'expiry' => 'infinity',
+ );
+ } else {
+ $restriction = trim( $temp[1] );
+ $pageInfo['protection'][] = array(
+ 'type' => $temp[0],
+ 'level' => $restriction,
+ 'expiry' => 'infinity',
+ );
+ }
+ }
+ $result->setIndexedTagName($pageInfo['protection'], 'pr');
+ } else {
+ $pageInfo['protection'] = array();
+ }
}
}
@@ -135,18 +193,31 @@ class ApiQueryInfo extends ApiQueryBase {
), $pageid, $pageInfo);
}
- // Get edit tokens for missing titles if requested
- // Delete, protect and move tokens are N/A for missing titles anyway
- if($tok_edit)
+ // Get edit/protect tokens and protection data for missing titles if requested
+ // Delete and move tokens are N/A for missing titles anyway
+ if($tok_edit || $tok_protect || $fld_protection)
{
- $missing = $pageSet->getMissingTitles();
- $res = $result->getData();
- foreach($missing as $pageid => $title)
- $res['query']['pages'][$pageid]['edittoken'] = $wgUser->editToken();
+ $res = &$result->getData();
+ foreach($missing as $pageid => $title) {
+ if($tok_edit)
+ $res['query']['pages'][$pageid]['edittoken'] = $wgUser->editToken();
+ if($tok_protect)
+ $res['query']['pages'][$pageid]['protecttoken'] = $wgUser->editToken();
+ if($fld_protection)
+ {
+ // Apparently the XML formatting code doesn't like array(null)
+ // This is painful to fix, so we'll just work around it
+ if(isset($prottitles[$title->getNamespace()][$title->getDBkey()]))
+ $res['query']['pages'][$pageid]['protection'][] = $prottitles[$title->getNamespace()][$title->getDBkey()];
+ else
+ $res['query']['pages'][$pageid]['protection'] = array();
+ $result->setIndexedTagName($res['query']['pages'][$pageid]['protection'], 'pr');
+ }
+ }
}
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'prop' => array (
ApiBase :: PARAM_DFLT => NULL,
@@ -166,7 +237,7 @@ class ApiQueryInfo extends ApiQueryBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => array (
'Which additional properties to get:',
@@ -177,7 +248,7 @@ class ApiQueryInfo extends ApiQueryBase {
}
- protected function getDescription() {
+ public function getDescription() {
return 'Get basic page information such as namespace, title, last touched date, ...';
}
@@ -189,7 +260,7 @@ class ApiQueryInfo extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryInfo.php 25457 2007-09-03 20:17:53Z catrope $';
+ return __CLASS__ . ': $Id: ApiQueryInfo.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryLangLinks.php b/includes/api/ApiQueryLangLinks.php
index ae5ff790..04a930db 100644
--- a/includes/api/ApiQueryLangLinks.php
+++ b/includes/api/ApiQueryLangLinks.php
@@ -76,7 +76,7 @@ class ApiQueryLangLinks extends ApiQueryBase {
$db->freeResult($res);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Returns all interlanguage links from the given page(s)';
}
@@ -88,7 +88,7 @@ class ApiQueryLangLinks extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryLangLinks.php 23819 2007-07-07 03:05:09Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryLangLinks.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryLinks.php b/includes/api/ApiQueryLinks.php
index 7ec20f44..d77e627a 100644
--- a/includes/api/ApiQueryLinks.php
+++ b/includes/api/ApiQueryLinks.php
@@ -123,7 +123,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
$db->freeResult($res);
}
- protected function getAllowedParams()
+ public function getAllowedParams()
{
return array(
'namespace' => array(
@@ -133,14 +133,14 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
);
}
- protected function getParamDescription()
+ public function getParamDescription()
{
return array(
'namespace' => "Show {$this->description}s in this namespace(s) only"
);
}
- protected function getDescription() {
+ public function getDescription() {
return "Returns all {$this->description}s from the given page(s)";
}
@@ -156,7 +156,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryLinks.php 24092 2007-07-14 19:04:31Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryLinks.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php
index 0f143658..e25e5275 100644
--- a/includes/api/ApiQueryLogEvents.php
+++ b/includes/api/ApiQueryLogEvents.php
@@ -198,7 +198,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
global $wgLogTypes;
return array (
'prop' => array (
@@ -243,8 +243,9 @@ class ApiQueryLogEvents extends ApiQueryBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
+ 'prop' => 'Which properties to get',
'type' => 'Filter log entries to only this type(s)',
'start' => 'The timestamp to start enumerating from.',
'end' => 'The timestamp to end enumerating.',
@@ -255,7 +256,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Get events from logs.';
}
@@ -266,7 +267,7 @@ class ApiQueryLogEvents extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryLogEvents.php 24256 2007-07-18 21:47:09Z robchurch $';
+ return __CLASS__ . ': $Id: ApiQueryLogEvents.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryRandom.php b/includes/api/ApiQueryRandom.php
new file mode 100644
index 00000000..b8282098
--- /dev/null
+++ b/includes/api/ApiQueryRandom.php
@@ -0,0 +1,157 @@
+<?php
+
+/*
+ * Created on Monday, January 28, 2008
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2008 Brent Garber
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ('ApiQueryBase.php');
+}
+
+/**
+ * Query module to get list of random pages
+ *
+ * @addtogroup API
+ */
+
+ class ApiQueryRandom extends ApiQueryGeneratorBase {
+
+ public function __construct($query, $moduleName) {
+ parent :: __construct($query, $moduleName, 'rn');
+ }
+
+ public function execute() {
+ $this->run();
+ }
+
+ public function executeGenerator($resultPageSet) {
+ $this->run($resultPageSet);
+ }
+
+ protected function prepareQuery($randstr, $limit, $namespace, &$resultPageSet) {
+ $this->resetQueryParams();
+ $this->addTables('page');
+ $this->addOption('LIMIT', $limit);
+ $this->addWhereFld('page_namespace', $namespace);
+ $this->addWhereRange('page_random', 'newer', $randstr, null);
+ $this->addWhere(array('page_is_redirect' => 0));
+ $this->addOption('USE INDEX', 'page_random');
+ if(is_null($resultPageSet))
+ $this->addFields(array('page_id', 'page_title', 'page_namespace'));
+ else
+ $this->addFields($resultPageSet->getPageTableFields());
+ }
+
+ protected function runQuery(&$data, &$resultPageSet) {
+ $db = $this->getDB();
+ $res = $this->select(__METHOD__);
+ $count = 0;
+ while($row = $db->fetchObject($res)) {
+ $count++;
+ if(is_null($resultPageSet))
+ {
+ // Prevent duplicates
+ if(!in_array($row->page_id, $this->pageIDs))
+ {
+ $data[] = $this->extractRowInfo($row);
+ $this->pageIDs[] = $row->page_id;
+ }
+ }
+ else
+ $resultPageSet->processDbRow($row);
+ }
+ $db->freeResult($res);
+ return $count;
+ }
+
+ public function run($resultPageSet = null) {
+ $params = $this->extractRequestParams();
+ $result = $this->getResult();
+ $data = array();
+ $this->pageIDs = array();
+ $this->prepareQuery(wfRandom(), $params['limit'], $params['namespace'], $resultPageSet);
+ $count = $this->runQuery($data, $resultPageSet);
+ if($count < $params['limit'])
+ {
+ /* We got too few pages, we probably picked a high value
+ * for page_random. We'll just take the lowest ones, see
+ * also the comment in Title::getRandomTitle()
+ */
+ $this->prepareQuery(0, $params['limit'] - $count, $params['namespace'], $resultPageSet);
+ $this->runQuery($data, $resultPageSet);
+ }
+
+ if(is_null($resultPageSet)) {
+ $result->setIndexedTagName($data, 'page');
+ $result->addValue('query', $this->getModuleName(), $data);
+ }
+ }
+
+ private function extractRowInfo($row) {
+ $title = Title::makeTitle($row->page_namespace, $row->page_title);
+ $vals = array();
+ $vals['title'] = $title->getPrefixedText();
+ $vals['ns'] = $row->page_namespace;
+ $vals['id'] = $row->page_id;
+ return $vals;
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'namespace' => array(
+ ApiBase :: PARAM_TYPE => 'namespace',
+ ApiBase :: PARAM_ISMULTI => true
+ ),
+ 'limit' => array (
+ ApiBase :: PARAM_TYPE => 'limit',
+ ApiBase :: PARAM_DFLT => 1,
+ ApiBase :: PARAM_MIN => 1,
+ ApiBase :: PARAM_MAX => 10,
+ ApiBase :: PARAM_MAX2 => 20
+ ),
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'namespace' => 'Return pages in these namespaces only',
+ 'limit' => 'Limit how many random pages will be returned'
+ );
+ }
+
+ public function getDescription() {
+ return array( 'Get a set of random pages',
+ 'NOTE: Pages are listed in a fixed sequence, only the starting point is random. This means that if, for example, "Main Page" is the first ',
+ ' random page on your list, "List of fictional monkeys" will *always* be second, "List of people on stamps of Vanuatu" third, etc.',
+ 'NOTE: If the number of pages in the namespace is lower than rnlimit, you will get fewer pages. You will not get the same page twice.'
+ );
+ }
+
+ protected function getExamples() {
+ return 'api.php?action=query&list=random&rnnamespace=0&rnlimit=2';
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryRandom.php overlordq$';
+ }
+}
diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php
index 309beaf9..44093854 100644
--- a/includes/api/ApiQueryRecentChanges.php
+++ b/includes/api/ApiQueryRecentChanges.php
@@ -44,20 +44,40 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$fld_timestamp = false, $fld_title = false, $fld_ids = false,
$fld_sizes = false;
+ /**
+ * Generates and outputs the result of this query based upon the provided parameters.
+ */
public function execute() {
- $limit = $prop = $namespace = $show = $dir = $start = $end = null;
+ /* Initialize vars */
+ $limit = $prop = $namespace = $show = $type = $dir = $start = $end = null;
+
+ /* Get the parameters of the request. */
extract($this->extractRequestParams());
+ /* Build our basic query. Namely, something along the lines of:
+ * SELECT * from recentchanges WHERE rc_timestamp > $start
+ * AND rc_timestamp < $end AND rc_namespace = $namespace
+ * AND rc_deleted = '0'
+ */
$this->addTables('recentchanges');
$this->addWhereRange('rc_timestamp', $dir, $start, $end);
$this->addWhereFld('rc_namespace', $namespace);
$this->addWhereFld('rc_deleted', 0);
+ if(!is_null($type))
+ $this->addWhereFld('rc_type', $this->parseRCType($type));
if (!is_null($show)) {
$show = array_flip($show);
- if ((isset ($show['minor']) && isset ($show['!minor'])) || (isset ($show['bot']) && isset ($show['!bot'])) || (isset ($show['anon']) && isset ($show['!anon'])))
+
+ /* Check for conflicting parameters. */
+ if ((isset ($show['minor']) && isset ($show['!minor']))
+ || (isset ($show['bot']) && isset ($show['!bot']))
+ || (isset ($show['anon']) && isset ($show['!anon']))) {
+
$this->dieUsage("Incorrect parameter - mutually exclusive values may not be supplied", 'show');
+ }
+ /* Add additional conditions to query depending upon parameters. */
$this->addWhereIf('rc_minor = 0', isset ($show['!minor']));
$this->addWhereIf('rc_minor != 0', isset ($show['minor']));
$this->addWhereIf('rc_bot = 0', isset ($show['!bot']));
@@ -66,6 +86,7 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$this->addWhereIf('rc_user != 0', isset ($show['!anon']));
}
+ /* Add the fields we're concerned with to out query. */
$this->addFields(array (
'rc_timestamp',
'rc_namespace',
@@ -75,9 +96,11 @@ class ApiQueryRecentChanges extends ApiQueryBase {
'rc_moved_to_title'
));
+ /* Determine what properties we need to display. */
if (!is_null($prop)) {
$prop = array_flip($prop);
+ /* Set up internal members based upon params. */
$this->fld_comment = isset ($prop['comment']);
$this->fld_user = isset ($prop['user']);
$this->fld_flags = isset ($prop['flags']);
@@ -85,7 +108,8 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$this->fld_title = isset ($prop['title']);
$this->fld_ids = isset ($prop['ids']);
$this->fld_sizes = isset ($prop['sizes']);
-
+
+ /* Add fields to our query if they are specified as a needed parameter. */
$this->addFieldsIf('rc_id', $this->fld_ids);
$this->addFieldsIf('rc_cur_id', $this->fld_ids);
$this->addFieldsIf('rc_this_oldid', $this->fld_ids);
@@ -100,14 +124,21 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$this->addFieldsIf('rc_new_len', $this->fld_sizes);
}
+ /* Specify the limit for our query. It's $limit+1 because we (possibly) need to
+ * generate a "continue" parameter, to allow paging. */
$this->addOption('LIMIT', $limit +1);
+
+ /* Specify the index to use in the query as rc_timestamp, instead of rc_revid (default). */
$this->addOption('USE INDEX', 'rc_timestamp');
$data = array ();
$count = 0;
+
+ /* Perform the actual query. */
$db = $this->getDB();
$res = $this->select(__METHOD__);
-
+
+ /* Iterate through the rows, adding data extracted from them to our query result. */
while ($row = $db->fetchObject($res)) {
if (++ $count > $limit) {
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
@@ -115,33 +146,61 @@ class ApiQueryRecentChanges extends ApiQueryBase {
break;
}
+ /* Extract the data from a single row. */
$vals = $this->extractRowInfo($row);
+
+ /* Add that row's data to our final output. */
if($vals)
$data[] = $vals;
}
+
$db->freeResult($res);
+ /* Format the result */
$result = $this->getResult();
$result->setIndexedTagName($data, 'rc');
$result->addValue('query', $this->getModuleName(), $data);
}
+ /**
+ * Extracts from a single sql row the data needed to describe one recent change.
+ *
+ * @param $row The row from which to extract the data.
+ * @return An array mapping strings (descriptors) to their respective string values.
+ * @access private
+ */
private function extractRowInfo($row) {
+ /* If page was moved somewhere, get the title of the move target. */
$movedToTitle = false;
if (!empty($row->rc_moved_to_title))
$movedToTitle = Title :: makeTitle($row->rc_moved_to_ns, $row->rc_moved_to_title);
+ /* Determine the title of the page that has been changed. */
$title = Title :: makeTitle($row->rc_namespace, $row->rc_title);
+
+ /* Our output data. */
$vals = array ();
- $vals['type'] = intval($row->rc_type);
+ $type = intval ( $row->rc_type );
+ /* Determine what kind of change this was. */
+ switch ( $type ) {
+ case RC_EDIT: $vals['type'] = 'edit'; break;
+ case RC_NEW: $vals['type'] = 'new'; break;
+ case RC_MOVE: $vals['type'] = 'move'; break;
+ case RC_LOG: $vals['type'] = 'log'; break;
+ case RC_MOVE_OVER_REDIRECT: $vals['type'] = 'move over redirect'; break;
+ default: $vals['type'] = $type;
+ }
+
+ /* Create a new entry in the result for the title. */
if ($this->fld_title) {
ApiQueryBase :: addTitleInfo($vals, $title);
if ($movedToTitle)
ApiQueryBase :: addTitleInfo($vals, $movedToTitle, "new_");
}
+ /* Add ids, such as rcid, pageid, revid, and oldid to the change's info. */
if ($this->fld_ids) {
$vals['rcid'] = intval($row->rc_id);
$vals['pageid'] = intval($row->rc_cur_id);
@@ -149,12 +208,14 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$vals['old_revid'] = intval( $row->rc_last_oldid );
}
+ /* Add user data and 'anon' flag, if use is anonymous. */
if ($this->fld_user) {
$vals['user'] = $row->rc_user_text;
if(!$row->rc_user)
$vals['anon'] = '';
}
+ /* Add flags, such as new, minor, bot. */
if ($this->fld_flags) {
if ($row->rc_bot)
$vals['bot'] = '';
@@ -164,22 +225,42 @@ class ApiQueryRecentChanges extends ApiQueryBase {
$vals['minor'] = '';
}
+ /* Add sizes of each revision. (Only available on 1.10+) */
if ($this->fld_sizes) {
$vals['oldlen'] = intval($row->rc_old_len);
$vals['newlen'] = intval($row->rc_new_len);
}
-
+
+ /* Add the timestamp. */
if ($this->fld_timestamp)
$vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp);
+ /* Add edit summary / log summary. */
if ($this->fld_comment && !empty ($row->rc_comment)) {
$vals['comment'] = $row->rc_comment;
}
return $vals;
}
+
+ private function parseRCType($type)
+ {
+ if(is_array($type))
+ {
+ $retval = array();
+ foreach($type as $t)
+ $retval[] = $this->parseRCType($t);
+ return $retval;
+ }
+ switch($type)
+ {
+ case 'edit': return RC_EDIT;
+ case 'new': return RC_NEW;
+ case 'log': return RC_LOG;
+ }
+ }
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'start' => array (
ApiBase :: PARAM_TYPE => 'timestamp'
@@ -228,11 +309,19 @@ class ApiQueryRecentChanges extends ApiQueryBase {
ApiBase :: PARAM_MIN => 1,
ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
+ ),
+ 'type' => array (
+ ApiBase :: PARAM_ISMULTI => true,
+ ApiBase :: PARAM_TYPE => array (
+ 'edit',
+ 'new',
+ 'log'
+ )
)
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'start' => 'The timestamp to start enumerating from.',
'end' => 'The timestamp to end enumerating.',
@@ -243,11 +332,12 @@ class ApiQueryRecentChanges extends ApiQueryBase {
'Show only items that meet this criteria.',
'For example, to see only minor edits done by logged-in users, set show=minor|!anon'
),
+ 'type' => 'Which types of changes to show.',
'limit' => 'How many total pages to return.'
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Enumerate recent changes';
}
@@ -258,7 +348,7 @@ class ApiQueryRecentChanges extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryRecentChanges.php 24100 2007-07-15 01:12:54Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryRecentChanges.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php
index 2672478b..e22d3b30 100644
--- a/includes/api/ApiQueryRevisions.php
+++ b/includes/api/ApiQueryRevisions.php
@@ -45,14 +45,15 @@ class ApiQueryRevisions extends ApiQueryBase {
$fld_comment = false, $fld_user = false, $fld_content = false;
public function execute() {
- $limit = $startid = $endid = $start = $end = $dir = $prop = $user = $excludeuser = null;
- extract($this->extractRequestParams());
+ $limit = $startid = $endid = $start = $end = $dir = $prop = $user = $excludeuser = $token = null;
+ extract($this->extractRequestParams(false));
// If any of those parameters are used, work in 'enumeration' mode.
// Enum mode can only be used when exactly one page is provided.
- // Enumerating revisions on multiple pages make it extremelly
- // difficult to manage continuations and require additional sql indexes
+ // Enumerating revisions on multiple pages make it extremely
+ // difficult to manage continuations and require additional SQL indexes
$enumRevMode = (!is_null($user) || !is_null($excludeuser) || !is_null($limit) || !is_null($startid) || !is_null($endid) || $dir === 'newer' || !is_null($start) || !is_null($end));
+
$pageSet = $this->getPageSet();
$pageCount = $pageSet->getGoodTitleCount();
@@ -66,7 +67,7 @@ class ApiQueryRevisions extends ApiQueryBase {
$this->dieUsage('The revids= parameter may not be used with the list options (limit, startid, endid, dirNewer, start, end).', 'revids');
if ($pageCount > 1 && $enumRevMode)
- $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start, and end parameters may only be used on a single page.', 'multpages');
+ $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start and end parameters may only be used on a single page.', 'multpages');
$this->addTables('revision');
$this->addWhere('rev_deleted=0');
@@ -84,12 +85,20 @@ class ApiQueryRevisions extends ApiQueryBase {
$this->fld_timestamp = $this->addFieldsIf('rev_timestamp', isset ($prop['timestamp']));
$this->fld_comment = $this->addFieldsIf('rev_comment', isset ($prop['comment']));
$this->fld_size = $this->addFieldsIf('rev_len', isset ($prop['size']));
+ $this->tok_rollback = false; // Prevent PHP undefined property notice
+ if(!is_null($token))
+ {
+ $this->tok_rollback = $this->getTokenFlag($token, 'rollback');
+ }
if (isset ($prop['user'])) {
$this->addFields('rev_user');
$this->addFields('rev_user_text');
$this->fld_user = true;
}
+ else if($this->tok_rollback)
+ $this->addFields('rev_user_text');
+
if (isset ($prop['content'])) {
// For each page we will request, the user must have read rights for that page
@@ -105,15 +114,22 @@ class ApiQueryRevisions extends ApiQueryBase {
$this->addFields('old_id');
$this->addFields('old_text');
$this->addFields('old_flags');
+
$this->fld_content = true;
+
+ $this->expandTemplates = $expandtemplates;
}
- $userMax = ($this->fld_content ? 50 : 500);
- $botMax = ($this->fld_content ? 200 : 10000);
+ $userMax = ( $this->fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1 );
+ $botMax = ( $this->fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2 );
+ if( $limit == 'max' ) {
+ $limit = $this->getMain()->canApiHighLimits() ? $botMax : $userMax;
+ $this->getResult()->addValue( 'limits', $this->getModuleName(), $limit );
+ }
if ($enumRevMode) {
- // This is mostly to prevent parameter errors (and optimize sql?)
+ // This is mostly to prevent parameter errors (and optimize SQL?)
if (!is_null($startid) && !is_null($start))
$this->dieUsage('start and startid cannot be used together', 'badparams');
@@ -130,7 +146,7 @@ class ApiQueryRevisions extends ApiQueryBase {
// one row with the same timestamp for the same page.
// The order needs to be the same as start parameter to avoid SQL filesort.
- if (is_null($startid))
+ if (is_null($startid) && is_null($endid))
$this->addWhereRange('rev_timestamp', $dir, $start, $end);
else
$this->addWhereRange('rev_id', $dir, $startid, $endid);
@@ -201,7 +217,7 @@ class ApiQueryRevisions extends ApiQueryBase {
$this->extractRowInfo($row));
}
$db->freeResult($res);
-
+
// Ensure that all revisions are shown as '<rev>' elements
$result = $this->getResult();
if ($result->getIsRawMode()) {
@@ -244,14 +260,27 @@ class ApiQueryRevisions extends ApiQueryBase {
$vals['comment'] = $row->rev_comment;
}
- if ($this->fld_content) {
- ApiResult :: setContent($vals, Revision :: getRevisionText($row));
+ if($this->tok_rollback || ($this->fld_content && $this->expandTemplates))
+ $title = Title::newFromID($row->rev_page);
+
+ if($this->tok_rollback) {
+ global $wgUser;
+ $vals['rollbacktoken'] = $wgUser->editToken(array($title->getPrefixedText(), $row->rev_user_text));
}
+
+ if ($this->fld_content) {
+ $text = Revision :: getRevisionText($row);
+ if ($this->expandTemplates) {
+ global $wgParser;
+ $text = $wgParser->preprocess( $text, $title, new ParserOptions() );
+ }
+ ApiResult :: setContent($vals, $text);
+ }
return $vals;
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'prop' => array (
ApiBase :: PARAM_ISMULTI => true,
@@ -269,8 +298,8 @@ class ApiQueryRevisions extends ApiQueryBase {
'limit' => array (
ApiBase :: PARAM_TYPE => 'limit',
ApiBase :: PARAM_MIN => 1,
- ApiBase :: PARAM_MAX => ApiBase :: LIMIT_SML1,
- ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_SML2
+ ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
+ ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
),
'startid' => array (
ApiBase :: PARAM_TYPE => 'integer'
@@ -296,11 +325,19 @@ class ApiQueryRevisions extends ApiQueryBase {
),
'excludeuser' => array(
ApiBase :: PARAM_TYPE => 'user'
- )
+ ),
+
+ 'expandtemplates' => false,
+ 'token' => array(
+ ApiBase :: PARAM_TYPE => array(
+ 'rollback'
+ ),
+ ApiBase :: PARAM_ISMULTI => true
+ ),
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => 'Which properties to get for each revision.',
'limit' => 'limit how many revisions will be returned (enum)',
@@ -311,10 +348,12 @@ class ApiQueryRevisions extends ApiQueryBase {
'dir' => 'direction of enumeration - towards "newer" or "older" revisions (enum)',
'user' => 'only include revisions made by user',
'excludeuser' => 'exclude revisions made by user',
+ 'expandtemplates' => 'expand templates in revision content',
+ 'token' => 'Which tokens to obtain for each revision',
);
}
- protected function getDescription() {
+ public function getDescription() {
return array (
'Get revision information.',
'This module may be used in several ways:',
@@ -343,7 +382,7 @@ class ApiQueryRevisions extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryRevisions.php 25407 2007-09-02 14:00:11Z tstarling $';
+ return __CLASS__ . ': $Id: ApiQueryRevisions.php 31259 2008-02-25 14:14:55Z catrope $';
}
}
diff --git a/includes/api/ApiQuerySearch.php b/includes/api/ApiQuerySearch.php
index 268616b1..b15f36ce 100644
--- a/includes/api/ApiQuerySearch.php
+++ b/includes/api/ApiQuerySearch.php
@@ -94,7 +94,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
}
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'search' => null,
'namespace' => array (
@@ -121,7 +121,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'search' => 'Search for all page titles (or content) that has this value.',
'namespace' => 'The namespace(s) to enumerate.',
@@ -132,7 +132,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Perform a full text search';
}
@@ -145,7 +145,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQuerySearch.php 24453 2007-07-30 08:09:15Z yurik $';
+ return __CLASS__ . ': $Id: ApiQuerySearch.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php
index 1fa3d8fc..81af7997 100644
--- a/includes/api/ApiQuerySiteinfo.php
+++ b/includes/api/ApiQuerySiteinfo.php
@@ -53,6 +53,9 @@ class ApiQuerySiteinfo extends ApiQueryBase {
case 'namespaces' :
$this->appendNamespaces($p);
break;
+ case 'namespacealiases' :
+ $this->appendNamespaceAliases($p);
+ break;
case 'interwikimap' :
$filteriw = isset($params['filteriw']) ? $params['filteriw'] : false;
$this->appendInterwikiMap($p, $filteriw);
@@ -68,7 +71,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
}
protected function appendGeneralInfo($property) {
- global $wgSitename, $wgVersion, $wgCapitalLinks, $wgRightsCode, $wgRightsText, $wgLanguageCode;
+ global $wgSitename, $wgVersion, $wgCapitalLinks, $wgRightsCode, $wgRightsText, $wgLanguageCode, $IP;
$data = array ();
$mainPage = Title :: newFromText(wfMsgForContent('mainpage'));
@@ -76,6 +79,10 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$data['base'] = $mainPage->getFullUrl();
$data['sitename'] = $wgSitename;
$data['generator'] = "MediaWiki $wgVersion";
+
+ $svn = SpecialVersion::getSvnRevision ( $IP );
+ if ( $svn ) $data['rev'] = $svn;
+
$data['case'] = $wgCapitalLinks ? 'first-letter' : 'case-sensitive'; // 'case-insensitive' option is reserved for future
if (isset($wgRightsCode))
$data['rightscode'] = $wgRightsCode;
@@ -100,6 +107,22 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$this->getResult()->addValue('query', $property, $data);
}
+ protected function appendNamespaceAliases($property) {
+ global $wgNamespaceAliases;
+
+ $data = array ();
+ foreach ($wgNamespaceAliases as $title => $ns) {
+ $item = array (
+ 'id' => $ns
+ );
+ ApiResult :: setContent($item, strtr($title, '_', ' '));
+ $data[] = $item;
+ }
+
+ $this->getResult()->setIndexedTagName($data, 'ns');
+ $this->getResult()->addValue('query', $property, $data);
+ }
+
protected function appendInterwikiMap($property, $filter) {
$this->resetQueryParams();
@@ -177,7 +200,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$this->getResult()->addValue('query', $property, $data);
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'prop' => array (
@@ -186,6 +209,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
ApiBase :: PARAM_TYPE => array (
'general',
'namespaces',
+ 'namespacealiases',
'interwikimap',
'dbrepllag',
'statistics',
@@ -201,12 +225,13 @@ class ApiQuerySiteinfo extends ApiQueryBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => array (
'Which sysinfo properties to get:',
' "general" - Overall system information',
' "namespaces" - List of registered namespaces (localized)',
+ ' "namespacealiases" - List of registered namespace aliases',
' "statistics" - Returns site statistics',
' "interwikimap" - Returns interwiki map (optionally filtered)',
' "dbrepllag" - Returns database server with the highest replication lag',
@@ -216,19 +241,19 @@ class ApiQuerySiteinfo extends ApiQueryBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Return general information about the site.';
}
protected function getExamples() {
return array(
- 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|statistics',
+ 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics',
'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local',
'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb',
);
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQuerySiteinfo.php 25238 2007-08-28 15:37:31Z robchurch $';
+ return __CLASS__ . ': $Id: ApiQuerySiteinfo.php 30484 2008-02-03 19:29:59Z btongminh $';
}
-} \ No newline at end of file
+}
diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php
index 05c3d945..57d51cdb 100644
--- a/includes/api/ApiQueryUserContributions.php
+++ b/includes/api/ApiQueryUserContributions.php
@@ -60,7 +60,11 @@ class ApiQueryContributions extends ApiQueryBase {
$db = $this->getDB();
// Prepare query
- $this->prepareUsername();
+ $this->usernames = array();
+ if(!is_array($this->params['user']))
+ $this->params['user'] = array($this->params['user']);
+ foreach($this->params['user'] as $u)
+ $this->prepareUsername($u);
$this->prepareQuery();
//Do the actual query.
@@ -96,8 +100,7 @@ class ApiQueryContributions extends ApiQueryBase {
* Validate the 'user' parameter and set the value to compare
* against `revision`.`rev_user_text`
*/
- private function prepareUsername() {
- $user = $this->params['user'];
+ private function prepareUsername($user) {
if( $user ) {
$name = User::isIP( $user )
? $user
@@ -105,7 +108,7 @@ class ApiQueryContributions extends ApiQueryBase {
if( $name === false ) {
$this->dieUsage( "User name {$user} is not valid", 'param_user' );
} else {
- $this->username = $name;
+ $this->usernames[] = $name;
}
} else {
$this->dieUsage( 'User parameter may not be empty', 'param_user' );
@@ -123,14 +126,11 @@ class ApiQueryContributions extends ApiQueryBase {
$this->addTables("$tbl_revision LEFT OUTER JOIN $tbl_page ON page_id=rev_page");
$this->addWhereFld('rev_deleted', 0);
-
- // We only want pages by the specified user.
- $this->addWhereFld( 'rev_user_text', $this->username );
-
+ // We only want pages by the specified users.
+ $this->addWhereFld( 'rev_user_text', $this->usernames );
// ... and in the specified timeframe.
$this->addWhereRange('rev_timestamp',
$this->params['dir'], $this->params['start'], $this->params['end'] );
-
$this->addWhereFld('page_namespace', $this->params['namespace']);
$show = $this->params['show'];
@@ -142,15 +142,16 @@ class ApiQueryContributions extends ApiQueryBase {
$this->addWhereIf('rev_minor_edit = 0', isset ($show['!minor']));
$this->addWhereIf('rev_minor_edit != 0', isset ($show['minor']));
}
-
$this->addOption('LIMIT', $this->params['limit'] + 1);
// Mandatory fields: timestamp allows request continuation
- // ns+title checks if the user has access rights for this page
+ // ns+title checks if the user has access rights for this page
+ // user_text is necessary if multiple users were specified
$this->addFields(array(
'rev_timestamp',
'page_namespace',
'page_title',
+ 'rev_user_text',
));
$this->addFieldsIf('rev_page', $this->fld_ids);
@@ -158,8 +159,6 @@ class ApiQueryContributions extends ApiQueryBase {
// $this->addFieldsIf('rev_text_id', $this->fld_ids); // Should this field be exposed?
$this->addFieldsIf('rev_comment', $this->fld_comment);
$this->addFieldsIf('rev_minor_edit', $this->fld_flags);
-
- // These fields depend only work if the page table is joined
$this->addFieldsIf('page_is_new', $this->fld_flags);
}
@@ -170,6 +169,7 @@ class ApiQueryContributions extends ApiQueryBase {
$vals = array();
+ $vals['user'] = $row->rev_user_text;
if ($this->fld_ids) {
$vals['pageid'] = intval($row->rev_page);
$vals['revid'] = intval($row->rev_id);
@@ -196,7 +196,7 @@ class ApiQueryContributions extends ApiQueryBase {
return $vals;
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'limit' => array (
ApiBase :: PARAM_DFLT => 10,
@@ -212,7 +212,7 @@ class ApiQueryContributions extends ApiQueryBase {
ApiBase :: PARAM_TYPE => 'timestamp'
),
'user' => array (
- ApiBase :: PARAM_TYPE => 'user'
+ ApiBase :: PARAM_ISMULTI => true
),
'dir' => array (
ApiBase :: PARAM_DFLT => 'older',
@@ -246,7 +246,7 @@ class ApiQueryContributions extends ApiQueryBase {
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'limit' => 'The maximum number of contributions to return.',
'start' => 'The start timestamp to return from.',
@@ -259,7 +259,7 @@ class ApiQueryContributions extends ApiQueryBase {
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Get all edits by a user';
}
@@ -270,7 +270,7 @@ class ApiQueryContributions extends ApiQueryBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryUserContributions.php 24754 2007-08-13 18:18:18Z robchurch $';
+ return __CLASS__ . ': $Id: ApiQueryUserContributions.php 30578 2008-02-05 15:40:58Z catrope $';
}
}
diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php
index a41b8679..010d9f4f 100644
--- a/includes/api/ApiQueryUserInfo.php
+++ b/includes/api/ApiQueryUserInfo.php
@@ -40,50 +40,90 @@ class ApiQueryUserInfo extends ApiQueryBase {
}
public function execute() {
-
- global $wgUser;
-
$params = $this->extractRequestParams();
$result = $this->getResult();
+ $r = array();
+ if (!is_null($params['prop'])) {
+ $this->prop = array_flip($params['prop']);
+ } else {
+ $this->prop = array();
+ }
+ $r = $this->getCurrentUserInfo();
+ $result->addValue("query", $this->getModuleName(), $r);
+ }
+
+ protected function getCurrentUserInfo() {
+ global $wgUser;
+ $result = $this->getResult();
$vals = array();
+ $vals['id'] = $wgUser->getId();
$vals['name'] = $wgUser->getName();
- if( $wgUser->isAnon() ) $vals['anon'] = '';
-
- if (!is_null($params['prop'])) {
- $prop = array_flip($params['prop']);
- if (isset($prop['blockinfo'])) {
- if ($wgUser->isBlocked()) {
- $vals['blockedby'] = User::whoIs($wgUser->blockedBy());
- $vals['blockreason'] = $wgUser->blockedFor();
- }
- }
- if (isset($prop['hasmsg']) && $wgUser->getNewtalk()) {
- $vals['messages'] = '';
- }
- if (isset($prop['groups'])) {
- $vals['groups'] = $wgUser->getGroups();
- $result->setIndexedTagName($vals['groups'], 'g'); // even if empty
- }
- if (isset($prop['rights'])) {
- $vals['rights'] = $wgUser->getRights();
- $result->setIndexedTagName($vals['rights'], 'r'); // even if empty
+ if($wgUser->isAnon())
+ $vals['anon'] = '';
+ if (isset($this->prop['blockinfo'])) {
+ if ($wgUser->isBlocked()) {
+ $vals['blockedby'] = User::whoIs($wgUser->blockedBy());
+ $vals['blockreason'] = $wgUser->blockedFor();
}
+ }
+ if (isset($this->prop['hasmsg']) && $wgUser->getNewtalk()) {
+ $vals['messages'] = '';
}
-
- if (!empty($params['option'])) {
- foreach( $params['option'] as $option ) {
- if (empty($option))
- $this->dieUsage('Empty value is not allowed for the option parameter', 'option');
- $vals['options'][$option] = $wgUser->getOption($option);
- }
+ if (isset($this->prop['groups'])) {
+ $vals['groups'] = $wgUser->getGroups();
+ $result->setIndexedTagName($vals['groups'], 'g'); // even if empty
}
-
- $result->addValue(null, $this->getModuleName(), $vals);
+ if (isset($this->prop['rights'])) {
+ $vals['rights'] = $wgUser->getRights();
+ $result->setIndexedTagName($vals['rights'], 'r'); // even if empty
+ }
+ if (isset($this->prop['options'])) {
+ $vals['options'] = (is_null($wgUser->mOptions) ? User::getDefaultOptions() : $wgUser->mOptions);
+ }
+ if (isset($this->prop['editcount'])) {
+ $vals['editcount'] = $wgUser->getEditCount();
+ }
+ if (isset($this->prop['ratelimits'])) {
+ $vals['ratelimits'] = $this->getRateLimits();
+ }
+ return $vals;
}
+
+ protected function getRateLimits()
+ {
+ global $wgUser, $wgRateLimits;
+ if(!$wgUser->isPingLimitable())
+ return array(); // No limits
+
+ // Find out which categories we belong to
+ $categories = array();
+ if($wgUser->isAnon())
+ $categories[] = 'anon';
+ else
+ $categories[] = 'user';
+ if($wgUser->isNewBie())
+ {
+ $categories[] = 'ip';
+ $categories[] = 'subnet';
+ if(!$wgUser->isAnon())
+ $categories[] = 'newbie';
+ }
+
+ // Now get the actual limits
+ $retval = array();
+ foreach($wgRateLimits as $action => $limits)
+ foreach($categories as $cat)
+ if(isset($limits[$cat]) && !is_null($limits[$cat]))
+ {
+ $retval[$action][$cat]['hits'] = $limits[$cat][0];
+ $retval[$action][$cat]['seconds'] = $limits[$cat][1];
+ }
+ return $retval;
+ }
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'prop' => array (
ApiBase :: PARAM_DFLT => NULL,
@@ -93,28 +133,30 @@ class ApiQueryUserInfo extends ApiQueryBase {
'hasmsg',
'groups',
'rights',
- )),
- 'option' => array (
- ApiBase :: PARAM_DFLT => NULL,
- ApiBase :: PARAM_ISMULTI => true,
- ),
+ 'options',
+ 'editcount',
+ 'ratelimits'
+ )
+ )
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'prop' => array(
'What pieces of information to include',
- ' blockinfo - tags if the user is blocked, by whom, and for what reason',
- ' hasmsg - adds a tag "message" if user has pending messages',
- ' groups - lists all the groups the current user belongs to',
- ' rights - lists of all rights the current user has',
- ),
- 'option' => 'A list of user preference options to get',
+ ' blockinfo - tags if the current user is blocked, by whom, and for what reason',
+ ' hasmsg - adds a tag "message" if the current user has pending messages',
+ ' groups - lists all the groups the current user belongs to',
+ ' rights - lists of all rights the current user has',
+ ' options - lists all preferences the current user has set',
+ ' editcount - adds the current user\'s edit count',
+ ' ratelimits - lists all rate limits applying to the current user'
+ )
);
}
- protected function getDescription() {
+ public function getDescription() {
return 'Get information about the current user';
}
@@ -122,12 +164,10 @@ class ApiQueryUserInfo extends ApiQueryBase {
return array (
'api.php?action=query&meta=userinfo',
'api.php?action=query&meta=userinfo&uiprop=blockinfo|groups|rights|hasmsg',
- 'api.php?action=query&meta=userinfo&uioption=rememberpassword',
);
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryUserInfo.php 24529 2007-08-01 20:11:29Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryUserInfo.php 30395 2008-02-01 14:46:46Z catrope $';
}
}
-
diff --git a/includes/api/ApiQueryUsers.php b/includes/api/ApiQueryUsers.php
new file mode 100644
index 00000000..144bfba2
--- /dev/null
+++ b/includes/api/ApiQueryUsers.php
@@ -0,0 +1,162 @@
+<?php
+
+/*
+ * Created on July 30, 2007
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ('ApiQueryBase.php');
+}
+
+/**
+ * Query module to get information about a list of users
+ *
+ * @addtogroup API
+ */
+
+ class ApiQueryUsers extends ApiQueryBase {
+
+ public function __construct($query, $moduleName) {
+ parent :: __construct($query, $moduleName, 'us');
+ }
+
+ public function execute() {
+ $params = $this->extractRequestParams();
+ $result = $this->getResult();
+ $r = array();
+
+ if (!is_null($params['prop'])) {
+ $this->prop = array_flip($params['prop']);
+ } else {
+ $this->prop = array();
+ }
+
+ if(is_array($params['users'])) {
+ $r = $this->getOtherUsersInfo($params['users']);
+ $result->setIndexedTagName($r, 'user');
+ }
+ $result->addValue("query", $this->getModuleName(), $r);
+ }
+
+ protected function getOtherUsersInfo($users) {
+ $goodNames = $retval = array();
+ // Canonicalize user names
+ foreach($users as $u) {
+ $n = User::getCanonicalName($u);
+ if($n === false)
+ $retval[] = array('name' => $u, 'invalid' => '');
+ else
+ $goodNames[] = $n;
+ }
+
+ $db = $this->getDb();
+ $userTable = $db->tableName('user');
+ $tables = "$userTable AS u1";
+ $this->addFields('u1.user_name');
+ $this->addWhereFld('u1.user_name', $goodNames);
+ $this->addFieldsIf('u1.user_editcount', isset($this->prop['editcount']));
+
+ if(isset($this->prop['groups'])) {
+ $ug = $db->tableName('user_groups');
+ $tables = "$tables LEFT JOIN $ug ON ug_user=u1.user_id";
+ $this->addFields('ug_group');
+ }
+ if(isset($this->prop['blockinfo'])) {
+ $ipb = $db->tableName('ipblocks');
+ $tables = "$tables LEFT JOIN $ipb ON ipb_user=u1.user_id";
+ $tables = "$tables LEFT JOIN $userTable AS u2 ON ipb_by=u2.user_id";
+ $this->addFields(array('ipb_reason', 'u2.user_name AS blocker_name'));
+ }
+ $this->addTables($tables);
+
+ $data = array();
+ $res = $this->select(__METHOD__);
+ while(($r = $db->fetchObject($res))) {
+ $data[$r->user_name]['name'] = $r->user_name;
+ if(isset($this->prop['editcount']))
+ $data[$r->user_name]['editcount'] = $r->user_editcount;
+ if(isset($this->prop['groups']))
+ // This row contains only one group, others will be added from other rows
+ if(!is_null($r->ug_group))
+ $data[$r->user_name]['groups'][] = $r->ug_group;
+ if(isset($this->prop['blockinfo']))
+ if(!is_null($r->blocker_name)) {
+ $data[$r->user_name]['blockedby'] = $r->blocker_name;
+ $data[$r->user_name]['blockreason'] = $r->ipb_reason;
+ }
+ }
+
+ // Second pass: add result data to $retval
+ foreach($goodNames as $u) {
+ if(!isset($data[$u]))
+ $retval[] = array('name' => $u, 'missing' => '');
+ else {
+ if(isset($this->prop['groups']) && isset($data[$u]['groups']))
+ $this->getResult()->setIndexedTagName($data[$u]['groups'], 'g');
+ $retval[] = $data[$u];
+ }
+ }
+ return $retval;
+ }
+
+ public function getAllowedParams() {
+ return array (
+ 'prop' => array (
+ ApiBase :: PARAM_DFLT => NULL,
+ ApiBase :: PARAM_ISMULTI => true,
+ ApiBase :: PARAM_TYPE => array (
+ 'blockinfo',
+ 'groups',
+ 'editcount'
+ )
+ ),
+ 'users' => array(
+ ApiBase :: PARAM_ISMULTI => true
+ )
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'prop' => array(
+ 'What pieces of information to include',
+ ' blockinfo - tags if the user is blocked, by whom, and for what reason',
+ ' groups - lists all the groups the user belongs to',
+ ' editcount - adds the user\'s edit count'
+ ),
+ 'users' => 'A list of users to obtain the same information for'
+ );
+ }
+
+ public function getDescription() {
+ return 'Get information about a list of users';
+ }
+
+ protected function getExamples() {
+ return 'api.php?action=query&list=users&ususers=brion|TimStarling&usprop=groups|editcount';
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiQueryUserInfo.php 30128 2008-01-24 17:59:07Z catrope $';
+ }
+}
diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php
index 16586a40..91a0c951 100644
--- a/includes/api/ApiQueryWatchlist.php
+++ b/includes/api/ApiQueryWatchlist.php
@@ -59,7 +59,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
if (!$wgUser->isLoggedIn())
$this->dieUsage('You must be logged-in to have a watchlist', 'notloggedin');
- $allrev = $start = $end = $namespace = $dir = $limit = $prop = null;
+ $allrev = $start = $end = $namespace = $dir = $limit = $prop = $show = null;
extract($this->extractRequestParams());
if (!is_null($prop) && is_null($resultPageSet)) {
@@ -135,7 +135,28 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
$this->addWhereFld('wl_namespace', $namespace);
$this->addWhereIf('rc_this_oldid=page_latest', !$allrev);
- # This is a index optimization for mysql, as done in the Special:Watchlist page
+ if (!is_null($show)) {
+ $show = array_flip($show);
+
+ /* Check for conflicting parameters. */
+ if ((isset ($show['minor']) && isset ($show['!minor']))
+ || (isset ($show['bot']) && isset ($show['!bot']))
+ || (isset ($show['anon']) && isset ($show['!anon']))) {
+
+ $this->dieUsage("Incorrect parameter - mutually exclusive values may not be supplied", 'show');
+ }
+
+ /* Add additional conditions to query depending upon parameters. */
+ $this->addWhereIf('rc_minor = 0', isset ($show['!minor']));
+ $this->addWhereIf('rc_minor != 0', isset ($show['minor']));
+ $this->addWhereIf('rc_bot = 0', isset ($show['!bot']));
+ $this->addWhereIf('rc_bot != 0', isset ($show['bot']));
+ $this->addWhereIf('rc_user = 0', isset ($show['anon']));
+ $this->addWhereIf('rc_user != 0', isset ($show['!anon']));
+ }
+
+
+ # This is an index optimization for mysql, as done in the Special:Watchlist page
$this->addWhereIf("rc_timestamp > ''", !isset ($start) && !isset ($end) && $wgDBtype == 'mysql');
$this->addOption('LIMIT', $limit +1);
@@ -222,7 +243,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
return $vals;
}
- protected function getAllowedParams() {
+ public function getAllowedParams() {
return array (
'allrev' => false,
'start' => array (
@@ -262,11 +283,22 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
'patrol',
'sizes',
)
+ ),
+ 'show' => array (
+ ApiBase :: PARAM_ISMULTI => true,
+ ApiBase :: PARAM_TYPE => array (
+ 'minor',
+ '!minor',
+ 'bot',
+ '!bot',
+ 'anon',
+ '!anon'
+ )
)
);
}
- protected function getParamDescription() {
+ public function getParamDescription() {
return array (
'allrev' => 'Include multiple revisions of the same page within given timeframe.',
'start' => 'The timestamp to start enumerating from.',
@@ -274,11 +306,15 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
'namespace' => 'Filter changes to only the given namespace(s).',
'dir' => 'In which direction to enumerate pages.',
'limit' => 'How many total pages to return per request.',
- 'prop' => 'Which additional items to get (non-generator mode only).'
+ 'prop' => 'Which additional items to get (non-generator mode only).',
+ 'show' => array (
+ 'Show only items that meet this criteria.',
+ 'For example, to see only minor edits done by logged-in users, set show=minor|!anon'
+ )
);
}
- protected function getDescription() {
+ public function getDescription() {
return '';
}
@@ -293,7 +329,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiQueryWatchlist.php 24092 2007-07-14 19:04:31Z yurik $';
+ return __CLASS__ . ': $Id: ApiQueryWatchlist.php 30222 2008-01-28 19:05:26Z catrope $';
}
}
diff --git a/includes/api/ApiResult.php b/includes/api/ApiResult.php
index a318d808..ffab51ef 100644
--- a/includes/api/ApiResult.php
+++ b/includes/api/ApiResult.php
@@ -139,6 +139,22 @@ class ApiResult extends ApiBase {
// Do not use setElement() as it is ok to call this more than once
$arr['_element'] = $tag;
}
+
+ /**
+ * Calls setIndexedTagName() on $arr and each sub-array
+ */
+ public function setIndexedTagName_recursive(&$arr, $tag)
+ {
+ if(!is_array($arr))
+ return;
+ foreach($arr as $a)
+ {
+ if(!is_array($a))
+ continue;
+ $this->setIndexedTagName($a, $tag);
+ $this->setIndexedTagName_recursive($a, $tag);
+ }
+ }
/**
* Add value to the output data at the given path.
@@ -175,7 +191,34 @@ class ApiResult extends ApiBase {
}
public function getVersion() {
- return __CLASS__ . ': $Id: ApiResult.php 23531 2007-06-29 01:19:14Z simetrical $';
+ return __CLASS__ . ': $Id: ApiResult.php 26855 2007-10-20 18:27:39Z catrope $';
}
}
+/* For compatibility with PHP versions < 5.1.0, define our own array_intersect_key function. */
+if (!function_exists('array_intersect_key')) {
+ function array_intersect_key($isec, $keys) {
+ $argc = func_num_args();
+
+ if ($argc > 2) {
+ for ($i = 1; !empty($isec) && $i < $argc; $i++) {
+ $arr = func_get_arg($i);
+
+ foreach (array_keys($isec) as $key) {
+ if (!isset($arr[$key]))
+ unset($isec[$key]);
+ }
+ }
+
+ return $isec;
+ } else {
+ $res = array();
+ foreach (array_keys($isec) as $key) {
+ if (isset($keys[$key]))
+ $res[$key] = $isec[$key];
+ }
+
+ return $res;
+ }
+ }
+}
diff --git a/includes/api/ApiRollback.php b/includes/api/ApiRollback.php
new file mode 100644
index 00000000..d714f99c
--- /dev/null
+++ b/includes/api/ApiRollback.php
@@ -0,0 +1,128 @@
+<?php
+
+/*
+ * Created on Jun 20, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+/**
+ * @addtogroup API
+ */
+class ApiRollback extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ global $wgUser;
+ $this->getMain()->requestWriteMode();
+ $params = $this->extractRequestParams();
+
+ $titleObj = NULL;
+ if(!isset($params['title']))
+ $this->dieUsageMsg(array('missingparam', 'title'));
+ if(!isset($params['user']))
+ $this->dieUsageMsg(array('missingparam', 'user'));
+ if(!isset($params['token']))
+ $this->dieUsageMsg(array('missingparam', 'token'));
+
+ $titleObj = Title::newFromText($params['title']);
+ if(!$titleObj)
+ $this->dieUsageMsg(array('invalidtitle', $params['title']));
+ if(!$titleObj->exists())
+ $this->dieUsageMsg(array('notanarticle'));
+
+ $username = User::getCanonicalName($params['user']);
+ if(!$username)
+ $this->dieUsageMsg(array('invaliduser', $params['user']));
+
+ $articleObj = new Article($titleObj);
+ $summary = (isset($params['summary']) ? $params['summary'] : "");
+ $details = null;
+ $dbw = wfGetDb(DB_MASTER);
+ $dbw->begin();
+ $retval = $articleObj->doRollback($username, $summary, $params['token'], $params['markbot'], $details);
+
+ if(!empty($retval))
+ // We don't care about multiple errors, just report one of them
+ $this->dieUsageMsg(current($retval));
+
+ $dbw->commit();
+ $current = $target = $summary = NULL;
+ extract($details);
+
+ $info = array(
+ 'title' => $titleObj->getPrefixedText(),
+ 'pageid' => $current->getPage(),
+ 'summary' => $summary,
+ 'revid' => $titleObj->getLatestRevID(),
+ 'old_revid' => $current->getID(),
+ 'last_revid' => $target->getID()
+ );
+
+ $this->getResult()->addValue(null, $this->getModuleName(), $info);
+ }
+
+ public function mustBePosted() { return true; }
+
+ public function getAllowedParams() {
+ return array (
+ 'title' => null,
+ 'user' => null,
+ 'token' => null,
+ 'summary' => null,
+ 'markbot' => false
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'title' => 'Title of the page you want to rollback.',
+ 'user' => 'Name of the user whose edits are to be rolled back. If set incorrectly, you\'ll get a badtoken error.',
+ 'token' => 'A rollback token previously retrieved through prop=info',
+ 'summary' => 'Custom edit summary. If not set, default summary will be used.',
+ 'markbot' => 'Mark the reverted edits and the revert as bot edits'
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Undoes the last edit to the page. If the last user who edited the page made multiple edits in a row,',
+ 'they will all be rolled back. You need to be logged in as a sysop to use this function, see also action=login.'
+ );
+ }
+
+ protected 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'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiRollback.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiUnblock.php b/includes/api/ApiUnblock.php
new file mode 100644
index 00000000..afbd3f0e
--- /dev/null
+++ b/includes/api/ApiUnblock.php
@@ -0,0 +1,124 @@
+<?php
+
+/*
+ * Created on Sep 7, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+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.
+ *
+ * @addtogroup API
+ */
+class ApiUnblock extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ /**
+ * Unblocks the specified user or provides the reason the unblock failed.
+ */
+ public function execute() {
+ global $wgUser;
+ $this->getMain()->requestWriteMode();
+ $params = $this->extractRequestParams();
+
+ if($params['gettoken'])
+ {
+ $res['unblocktoken'] = $wgUser->editToken();
+ $this->getResult()->addValue(null, $this->getModuleName(), $res);
+ return;
+ }
+
+ if(is_null($params['id']) && is_null($params['user']))
+ $this->dieUsageMsg(array('unblock-notarget'));
+ if(!is_null($params['id']) && !is_null($params['user']))
+ $this->dieUsageMsg(array('unblock-idanduser'));
+ if(is_null($params['token']))
+ $this->dieUsageMsg(array('missingparam', 'token'));
+ if(!$wgUser->matchEditToken($params['token']))
+ $this->dieUsageMsg(array('sessionfailure'));
+ if(!$wgUser->isAllowed('block'))
+ $this->dieUsageMsg(array('cantunblock'));
+ if(wfReadOnly())
+ $this->dieUsageMsg(array('readonlytext'));
+
+ $id = $params['id'];
+ $user = $params['user'];
+ $reason = (is_null($params['reason']) ? '' : $params['reason']);
+ $dbw = wfGetDb(DB_MASTER);
+ $dbw->begin();
+ $retval = IPUnblockForm::doUnblock($id, $user, $reason, $range);
+ if(!empty($retval))
+ $this->dieUsageMsg($retval);
+
+ $dbw->commit();
+ $res['id'] = $id;
+ $res['user'] = $user;
+ $res['reason'] = $reason;
+ $this->getResult()->addValue(null, $this->getModuleName(), $res);
+ }
+
+ public function mustBePosted() { return true; }
+
+ public function getAllowedParams() {
+ return array (
+ 'id' => null,
+ 'user' => null,
+ 'token' => null,
+ 'gettoken' => false,
+ 'reason' => null,
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'id' => 'ID of the block you want to unblock (obtained through list=blocks). Cannot be used together with user',
+ 'user' => 'Username, IP address or IP range you want to unblock. Cannot be used together with id',
+ 'token' => 'An unblock token previously obtained through the gettoken parameter',
+ 'gettoken' => 'If set, an unblock token will be returned, and no other action will be taken',
+ 'reason' => 'Reason for unblock (optional)',
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Unblock a user.'
+ );
+ }
+
+ protected function getExamples() {
+ return array (
+ 'api.php?action=unblock&id=105',
+ 'api.php?action=unblock&user=Bob&reason=Sorry%20Bob'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiUnblock.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}
diff --git a/includes/api/ApiUndelete.php b/includes/api/ApiUndelete.php
new file mode 100644
index 00000000..b27841a8
--- /dev/null
+++ b/includes/api/ApiUndelete.php
@@ -0,0 +1,123 @@
+<?php
+
+/*
+ * Created on Jul 3, 2007
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+ // Eclipse helper - will be ignored in production
+ require_once ("ApiBase.php");
+}
+
+/**
+ * @addtogroup API
+ */
+class ApiUndelete extends ApiBase {
+
+ public function __construct($main, $action) {
+ parent :: __construct($main, $action);
+ }
+
+ public function execute() {
+ global $wgUser;
+ $this->getMain()->requestWriteMode();
+ $params = $this->extractRequestParams();
+
+ $titleObj = NULL;
+ if(!isset($params['title']))
+ $this->dieUsageMsg(array('missingparam', 'title'));
+ if(!isset($params['token']))
+ $this->dieUsageMsg(array('missingparam', 'token'));
+
+ if(!$wgUser->isAllowed('undelete'))
+ $this->dieUsageMsg(array('permdenied-undelete'));
+ if($wgUser->isBlocked())
+ $this->dieUsageMsg(array('blockedtext'));
+ if(wfReadOnly())
+ $this->dieUsageMsg(array('readonlytext'));
+ if(!$wgUser->matchEditToken($params['token']))
+ $this->dieUsageMsg(array('sessionfailure'));
+
+ $titleObj = Title::newFromText($params['title']);
+ if(!$titleObj)
+ $this->dieUsageMsg(array('invalidtitle', $params['title']));
+
+ // Convert timestamps
+ if(!is_array($params['timestamps']))
+ $params['timestamps'] = array($params['timestamps']);
+ foreach($params['timestamps'] as $i => $ts)
+ $params['timestamps'][$i] = wfTimestamp(TS_MW, $ts);
+
+ $pa = new PageArchive($titleObj);
+ $dbw = wfGetDb(DB_MASTER);
+ $dbw->begin();
+ $retval = $pa->undelete((isset($params['timestamps']) ? $params['timestamps'] : array()), $params['reason']);
+ if(!is_array($retval))
+ $this->dieUsageMsg(array('cannotundelete'));
+
+ $dbw->commit();
+ $info['title'] = $titleObj->getPrefixedText();
+ $info['revisions'] = $retval[0];
+ $info['fileversions'] = $retval[1];
+ $info['reason'] = $retval[2];
+ $this->getResult()->addValue(null, $this->getModuleName(), $info);
+ }
+
+ public function mustBePosted() { return true; }
+
+ public function getAllowedParams() {
+ return array (
+ 'title' => null,
+ 'token' => null,
+ 'reason' => "",
+ 'timestamps' => array(
+ ApiBase :: PARAM_ISMULTI => true
+ )
+ );
+ }
+
+ public function getParamDescription() {
+ return array (
+ 'title' => 'Title of the page you want to restore.',
+ 'token' => 'An undelete token previously retrieved through list=deletedrevs',
+ 'reason' => 'Reason for restoring (optional)',
+ 'timestamps' => 'Timestamps of the revisions to restore. If not set, all revisions will be restored.'
+ );
+ }
+
+ public function getDescription() {
+ return array(
+ 'Restore certain revisions of a deleted page. A list of deleted revisions (including timestamps) can be',
+ 'retrieved through list=deletedrevs'
+ );
+ }
+
+ protected 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&timestamps=20070703220045|20070702194856'
+ );
+ }
+
+ public function getVersion() {
+ return __CLASS__ . ': $Id: ApiUndelete.php 30222 2008-01-28 19:05:26Z catrope $';
+ }
+}