From: Victor Vasiliev Date: Thu, 6 Dec 2007 18:22:15 +0000 (+0000) Subject: Create includes/api/query for Query API and includes/api/edit for Edit API X-Git-Tag: 1.31.0-rc.0~50523 X-Git-Url: https://git.cyclocoop.org/%7B%24admin_url%7Dmembres/supprimer.php?a=commitdiff_plain;h=4e4cdf079eadb114034698ca880d2ae1e4b9a857;p=lhc%2Fweb%2Fwiklou.git Create includes/api/query for Query API and includes/api/edit for Edit API --- diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index ec533ffe81..a24bbcca93 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -317,45 +317,47 @@ function __autoload($className) { 'ApiOpenSearch' => 'includes/api/ApiOpenSearch.php', 'ApiPageSet' => 'includes/api/ApiPageSet.php', 'ApiParse' => 'includes/api/ApiParse.php', - 'ApiQuery' => 'includes/api/ApiQuery.php', - 'ApiQueryAllpages' => 'includes/api/ApiQueryAllpages.php', - 'ApiQueryAllLinks' => 'includes/api/ApiQueryAllLinks.php', - 'ApiQueryAllUsers' => 'includes/api/ApiQueryAllUsers.php', - 'ApiQueryBase' => 'includes/api/ApiQueryBase.php', - 'ApiQueryGeneratorBase' => 'includes/api/ApiQueryBase.php', - 'ApiQueryBacklinks' => 'includes/api/ApiQueryBacklinks.php', - 'ApiQueryCategories' => 'includes/api/ApiQueryCategories.php', - 'ApiQueryCategoryMembers' => 'includes/api/ApiQueryCategoryMembers.php', - 'ApiQueryContributions' => 'includes/api/ApiQueryUserContributions.php', - 'ApiQueryExternalLinks' => 'includes/api/ApiQueryExternalLinks.php', - 'ApiQueryExtLinksUsage' => 'includes/api/ApiQueryExtLinksUsage.php', - 'ApiQueryImages' => 'includes/api/ApiQueryImages.php', - 'ApiQueryImageInfo' => 'includes/api/ApiQueryImageInfo.php', - 'ApiQueryInfo' => 'includes/api/ApiQueryInfo.php', - 'ApiQueryLangLinks' => 'includes/api/ApiQueryLangLinks.php', - 'ApiQueryLinks' => 'includes/api/ApiQueryLinks.php', - 'ApiQueryLogEvents' => 'includes/api/ApiQueryLogEvents.php', - 'ApiQueryRecentChanges'=> 'includes/api/ApiQueryRecentChanges.php', - 'ApiQueryRevisions' => 'includes/api/ApiQueryRevisions.php', - 'ApiQuerySearch' => 'includes/api/ApiQuerySearch.php', - 'ApiQueryAllmessages' => 'includes/api/ApiQueryAllmessages.php', - 'ApiQuerySiteinfo' => 'includes/api/ApiQuerySiteinfo.php', - 'ApiQueryUserInfo' => 'includes/api/ApiQueryUserInfo.php', - 'ApiQueryWatchlist' => 'includes/api/ApiQueryWatchlist.php', 'ApiRender' => 'includes/api/ApiRender.php', 'ApiResult' => 'includes/api/ApiResult.php', - # apiedit branch - 'ApiBlock' => 'includes/api/ApiBlock.php', - 'ApiChangeRights' => 'includes/api/ApiChangeRights.php', - 'ApiDelete' => 'includes/api/ApiDelete.php', - 'ApiMove' => 'includes/api/ApiMove.php', - 'ApiProtect' => 'includes/api/ApiProtect.php', - 'ApiQueryBlocks' => 'includes/api/ApiQueryBlocks.php', - 'ApiQueryDeletedrevs' => 'includes/api/ApiQueryDeletedrevs.php', - 'ApiRollback' => 'includes/api/ApiRollback.php', - 'ApiUnblock' => 'includes/api/ApiUnblock.php', - 'ApiUndelete' => 'includes/api/ApiUndelete.php' + # Query API + 'ApiQuery' => 'includes/api/query/ApiQuery.php', + 'ApiQueryAllpages' => 'includes/api/query/ApiQueryAllpages.php', + 'ApiQueryAllLinks' => 'includes/api/query/ApiQueryAllLinks.php', + 'ApiQueryAllUsers' => 'includes/api/query/ApiQueryAllUsers.php', + 'ApiQueryBase' => 'includes/api/query/ApiQueryBase.php', + 'ApiQueryGeneratorBase' => 'includes/api/query/ApiQueryBase.php', + 'ApiQueryBlocks' => 'includes/api/query/ApiQueryBlocks.php', + 'ApiQueryBacklinks' => 'includes/api/query/ApiQueryBacklinks.php', + 'ApiQueryCategories' => 'includes/api/query/ApiQueryCategories.php', + 'ApiQueryCategoryMembers' => 'includes/api/query/ApiQueryCategoryMembers.php', + 'ApiQueryContributions' => 'includes/api/query/ApiQueryUserContributions.php', + 'ApiQueryDeletedrevs' => 'includes/api/query/ApiQueryDeletedrevs.php', + 'ApiQueryExternalLinks' => 'includes/api/query/ApiQueryExternalLinks.php', + 'ApiQueryExtLinksUsage' => 'includes/api/query/ApiQueryExtLinksUsage.php', + 'ApiQueryImages' => 'includes/api/query/ApiQueryImages.php', + 'ApiQueryImageInfo' => 'includes/api/query/ApiQueryImageInfo.php', + 'ApiQueryInfo' => 'includes/api/query/ApiQueryInfo.php', + 'ApiQueryLangLinks' => 'includes/api/query/ApiQueryLangLinks.php', + 'ApiQueryLinks' => 'includes/api/query/ApiQueryLinks.php', + 'ApiQueryLogEvents' => 'includes/api/query/ApiQueryLogEvents.php', + 'ApiQueryRecentChanges'=> 'includes/api/query/ApiQueryRecentChanges.php', + 'ApiQueryRevisions' => 'includes/api/query/ApiQueryRevisions.php', + 'ApiQuerySearch' => 'includes/api/query/ApiQuerySearch.php', + 'ApiQueryAllmessages' => 'includes/api/query/ApiQueryAllmessages.php', + 'ApiQuerySiteinfo' => 'includes/api/query/ApiQuerySiteinfo.php', + 'ApiQueryUserInfo' => 'includes/api/query/ApiQueryUserInfo.php', + 'ApiQueryWatchlist' => 'includes/api/query/ApiQueryWatchlist.php', + + # API edit functions + 'ApiBlock' => 'includes/api/edit/ApiBlock.php', + 'ApiChangeRights' => 'includes/api/edit/ApiChangeRights.php', + 'ApiDelete' => 'includes/api/edit/ApiDelete.php', + 'ApiMove' => 'includes/api/edit/ApiMove.php', + 'ApiProtect' => 'includes/api/edit/ApiProtect.php', + 'ApiRollback' => 'includes/api/edit/ApiRollback.php', + 'ApiUnblock' => 'includes/api/edit/ApiUnblock.php', + 'ApiUndelete' => 'includes/api/edit/ApiUndelete.php' ); wfProfileIn( __METHOD__ ); diff --git a/includes/api/ApiBlock.php b/includes/api/ApiBlock.php deleted file mode 100644 index ef9ad6cc22..0000000000 --- a/includes/api/ApiBlock.php +++ /dev/null @@ -1,164 +0,0 @@ -.@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 ApiBlock extends ApiBase { - - public function __construct($main, $action) { - parent :: __construct($main, $action); - } - - 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->dieUsage('The user parameter must be set', 'nouser'); - if(is_null($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); - if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); - if(!$wgUser->isAllowed('block')) - $this->dieUsage('You don\'t have permission to block users', 'permissiondenied'); - if($params['hidename'] && !$wgUser->isAllowed('hideuser')) - $this->dieUsage('You don\'t have permission to hide user names from the block log', 'nohide'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - - $form = new IPBlockForm(''); - $form->BlockAddress = $params['user']; - $form->BlockReason = $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); - switch($retval) - { - case IPBlockForm::BLOCK_SUCCESS: - break; // We'll deal with that later - case IPBlockForm::BLOCK_RANGE_INVALID: - $this->dieUsage("Invalid IP range ``{$params['user']}''", 'invalidrange'); - case IPBlockForm::BLOCK_RANGE_DISABLED: - $this->dieUsage('Blocking IP ranges has been disabled', 'rangedisabled'); - case IPBlockForm::BLOCK_NONEXISTENT_USER: - $this->dieUsage("User ``{$params['user']}'' doesn't exist", 'nosuchuser'); - case IPBlockForm::BLOCK_IP_INVALID: - $this->dieUsage("Invaild IP address ``{$params['user']}''", 'invalidip'); - case IPBlockForm::BLOCK_EXPIRY_INVALID: - $this->dieUsage("Invalid expiry time ``{$params['expiry']}''", 'invalidexpiry'); - case IPBlockForm::BLOCK_ALREADY_BLOCKED: - $this->dieUsage("User ``{$params['user']}'' is already blocked", 'alreadyblocked'); - default: - $this->dieDebug(__METHOD__, "IPBlockForm::doBlock() returned an unknown error ($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); - } - - protected function getAllowedParams() { - return array ( - 'user' => null, - 'token' => null, - 'gettoken' => false, - 'expiry' => 'never', - 'reason' => null, - 'anononly' => false, - 'nocreate' => false, - 'autoblock' => false, - 'noemail' => false, - 'hidename' => false, - ); - } - - protected 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', - 'hidename' => 'Hide the username from the block log.' - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiChangeRights.php b/includes/api/ApiChangeRights.php deleted file mode 100644 index 4991437a58..0000000000 --- a/includes/api/ApiChangeRights.php +++ /dev/null @@ -1,170 +0,0 @@ -.@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 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 UserrightsForm($wgRequest); - $allowed = $ur->changeableGroups(); - $res = array(); - - if(is_null($params['user'])) - $this->dieUsage('The user parameter must be set', 'nouser'); - - $uName = User::getCanonicalName($params['user']); - $u = User::newFromName($uName); - if(!$u) - $this->dieUsage("Invalid username ``{$params['user']}''", 'invaliduser'); - if($u->getId() == 0) // Anon or non-existent - $this->dieUsage("User ``{$params['user']}'' doesn't exist", 'nosuchuser'); - - $curgroups = $u->getGroups(); - - if($params['listgroups']) - { - $res['user'] = $uName; - $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($uName); - $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'], $uName)) - $this->dieUsage('Invalid token', 'badtoken'); - - if(!$wgUser->isAllowed('userrights')) - $this->dieUsage('You don\'t have permission to change users\' rights', 'permissiondenied'); - - // First let's remove redundant groups and check permissions while we're at it - if(is_null($params['addto'])) - $params['addto'] = array(); - $addto = array(); - foreach($params['addto'] as $g) - { - if(!in_array($g, $allowed['add'])) - $this->dieUsage("You don't have permission to add to group ``$g''", 'cantadd'); - if(!in_array($g, $curgroups)) - $addto[] = $g; - } - - if(is_null($params['rmfrom'])) - $params['rmfrom'] = array(); - $rmfrom = array(); - foreach($params['rmfrom'] as $g) - { - if(!in_array($g, $allowed['remove'])) - $this->dieUsage("You don't have permission to remove from group ``$g''", 'cantremove'); - if(in_array($g, $curgroups)) - $rmfrom[] = $g; - } - $dbw = wfGetDb(DB_MASTER); - $dbw->begin(); - $ur->doSaveUserGroups($u, $rmfrom, $addto, $params['reason']); - $dbw->commit(); - $res['user'] = $uName; - $res['addedto'] = $addto; - $res['removedfrom'] = $rmfrom; - $res['reason'] = $params['reason']; - - $this->getResult()->setIndexedTagName($res['addedto'], 'group'); - $this->getResult()->setIndexedTagName($res['removedfrom'], 'group'); - $this->getResult()->addValue(null, $this->getModuleName(), $res); - } - - protected 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' => '' - ); - } - - protected 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)' - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiDelete.php b/includes/api/ApiDelete.php deleted file mode 100644 index 6ca9f953ea..0000000000 --- a/includes/api/ApiDelete.php +++ /dev/null @@ -1,172 +0,0 @@ -.@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 ApiDelete extends ApiBase { - - public function __construct($main, $action) { - parent :: __construct($main, $action); - } - - /** - * 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 DELETE_SUCCESS on success, DELETE_* on failure - */ - - const DELETE_SUCCESS = 0; - const DELETE_PERM = 1; - const DELETE_BLOCKED = 2; - const DELETE_READONLY = 3; - const DELETE_BADTOKEN = 4; - const DELETE_BADARTICLE = 5; - - public static function delete(&$article, $token, &$reason = NULL) - { - global $wgUser; - - // Check permissions first - if(!$article->mTitle->userCan('delete')) - return self::DELETE_PERM; - if($wgUser->isBlocked()) - return self::DELETE_BLOCKED; - if(wfReadOnly()) - return self::DELETE_READONLY; - - // Check token - if(!$wgUser->matchEditToken($token)) - return self::DELETE_BADTOKEN; - - // Auto-generate a summary, if necessary - if(is_null($reason)) - { - $reason = $article->generateReason($hasHistory); - if($reason === false) - return self::DELETE_BADARTICLE; - } - - // Luckily, Article.php provides a reusable delete function that does the hard work for us - if($article->doDeleteArticle($reason)) - return self::DELETE_SUCCESS; - return self::DELETE_BADARTICLE; - } - - public function execute() { - global $wgUser; - $this->getMain()->requestWriteMode(); - $params = $this->extractRequestParams(); - - $titleObj = NULL; - if(!isset($params['title'])) - $this->dieUsage('The title parameter must be set', 'notitle'); - if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); - - // delete() also checks for these, but we wanna save some work - if(!$wgUser->isAllowed('delete')) - $this->dieUsage('You don\'t have permission to delete pages', 'permissiondenied'); - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - - $titleObj = Title::newFromText($params['title']); - if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); - if(!$titleObj->exists()) - $this->dieUsage("``{$params['title']}'' doesn't exist", 'missingtitle'); - - $articleObj = new Article($titleObj); - $reason = (isset($params['reason']) ? $params['reason'] : NULL); - $dbw = wfGetDb(DB_MASTER); - $dbw->begin(); - $retval = self::delete(&$articleObj, $params['token'], &$reason); - - switch($retval) - { - case self::DELETE_SUCCESS: - break; // We'll deal with that later - case self::DELETE_PERM: // If we get PERM, BLOCKED or READONLY that's weird, but it's possible - $this->dieUsage('You don\'t have permission to delete', 'permissiondenied'); - case self::DELETE_BLOCKED: - $this->dieUsage('You have been blocked from editing', 'blocked'); - case self::DELETE_READONLY: - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - case self::DELETE_BADTOKEN: - $this->dieUsage('Invalid token', 'badtoken'); - case self::DELETE_BADARTICLE: - $this->dieUsage("The article ``{$params['title']}'' doesn't exist or has already been deleted", 'missingtitle'); - default: - // delete() has apparently invented a new error, which is extremely weird - $this->dieDebug(__METHOD__, "delete() returned an unknown error ($retval)"); - } - // $retval has to be self::DELETE_SUCCESS if we get here - $dbw->commit(); - $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason); - $this->getResult()->addValue(null, $this->getModuleName(), $r); - } - - protected function getAllowedParams() { - return array ( - 'title' => null, - 'token' => null, - 'reason' => null, - ); - } - - protected 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.' - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiMove.php b/includes/api/ApiMove.php deleted file mode 100644 index 2fc8fb106d..0000000000 --- a/includes/api/ApiMove.php +++ /dev/null @@ -1,181 +0,0 @@ -.@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->dieUsage('The from parameter must be set', 'nofrom'); - if(!isset($params['to'])) - $this->dieUsage('The to parameter must be set', 'noto'); - if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); - if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); - - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - if($params['noredirect'] && !$wgUser->isAllowed('suppressredirect')) - $this->dieUsage("You don't have permission to suppress redirect creation", 'nosuppress'); - - $fromTitle = Title::newFromText($params['from']); - if(!$fromTitle) - $this->dieUsage("Bad title ``{$params['from']}''", 'invalidtitle'); - if(!$fromTitle->exists()) - $this->dieUsage("``{$params['from']}'' doesn't exist", 'missingtitle'); - $fromTalk = $fromTitle->getTalkPage(); - - - $toTitle = Title::newFromText($params['to']); - if(!$toTitle) - $this->dieUsage("Bad title ``{$params['to']}''", 'invalidtitle'); - $toTalk = $toTitle->getTalkPage(); - - $dbw = wfGetDB(DB_MASTER); - $dbw->begin(); - $retval = $fromTitle->moveTo($toTitle, true, $params['reason'], !$params['noredirect']); - if($retval !== true) - switch($retval) - { - // case 'badtitletext': Can't happen - // case 'badarticleerror': Can't happen - case 'selfmove': - $this->dieUsage("Can't move ``{$params['from']}'' to itself", 'selfmove'); - case 'immobile_namespace': - if($fromTitle->isMovable()) - $this->dieUsage("Pages in the ``{$fromTitle->getNsText()}'' namespace can't be moved", 'immobilenamespace-from'); - $this->dieUsage("Pages in the ``{$toTitle->getNsText()}'' namespace can't be moved", 'immobilenamespace-to'); - case 'articleexists': - $this->dieUsage("``{$toTitle->getPrefixedText()}'' already exists and is not a redirect to ``{$fromTitle->getPrefixedText()}''", 'targetexists'); - case 'protectedpage': - $this->dieUsage("You don't have permission to move ``{$fromTitle->getPrefixedText()}'' to ``{$toTitle->getPrefixedText()}''", 'permissiondenied'); - default: - throw new MWException( "Title::moveTo: Unknown return value ``{$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 - switch($retval) - { - case 'immobile_namespace': - if($fromTalk->isMovable()) - { - $r['talkmove-error-code'] = 'immobilenamespace-from'; - $r['talkmove-error-info'] = "Pages in the ``{$fromTalk->getNsText()}'' namespace can't be moved"; - } - else - { - $r['talkmove-error-code'] = 'immobilenamespace-to'; - $r['talkmove-error-info'] = "Pages in the ``{$toTalk->getNsText()}'' namespace can't be moved"; - } - break; - case 'articleexists': - $r['talkmove-error-code'] = 'targetexists'; - $r['talkmove-error-info'] = "``{$toTalk->getPrefixedText()}'' already exists and is not a redirect to ``{$fromTalk->getPrefixedText()}''"; - break; - case 'protectedpage': - $r['talkmove-error-code'] = 'permissiondenied'; - $r['talkmove-error-info'] = "You don't have permission to move ``{$fromTalk->getPrefixedText()}'' to ``{$toTalk->getPrefixedText()}''"; - default: - $r['talkmove-error-code'] = 'unknownerror'; - $r['talkmove-error-info'] = "Unknown error ``$retval''"; - } - } - $dbw->commit(); // Make sure all changes are really written to the DB - $this->getResult()->addValue(null, $this->getModuleName(), $r); - } - - protected function getAllowedParams() { - return array ( - 'from' => null, - 'to' => null, - 'token' => null, - 'reason' => null, - 'movetalk' => false, - 'noredirect' => false - ); - } - - protected 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' - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiProtect.php b/includes/api/ApiProtect.php deleted file mode 100644 index 91fa57d55e..0000000000 --- a/includes/api/ApiProtect.php +++ /dev/null @@ -1,142 +0,0 @@ -.@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->dieUsage('The title parameter must be set', 'notitle'); - if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); - if(!isset($params['protections']) || empty($params['protections'])) - $this->dieUsage('The protections parameter must be set', 'noprotections'); - - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); - - $titleObj = Title::newFromText($params['title']); - if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); - if(!$titleObj->exists()) - $this->dieUsage("``{$params['title']}'' doesn't exist", 'missingtitle'); - if(!$titleObj->userCan('protect')) - $this->dieUsage('You don\'t have permission to change protection levels', 'permissiondenied'); - $articleObj = new Article($titleObj); - - if(in_array($params['expiry'], array('infinite', 'indefinite', 'never'))) - $expiry = Block::infinity(); - else - { - $expiry = strtotime($params['expiry']); - if($expiry < 0 || $expiry == false) - $this->dieUsage('Invalid expiry time', 'invalidexpiry'); - - $expiry = wfTimestamp(TS_MW, $expiry); - if($expiry < wfTimestampNow()) - $this->dieUsage('Expiry time is in the past', 'pastexpiry'); - } - - $protections = array(); - foreach($params['protections'] as $prot) - { - $p = explode('=', $prot); - $protections[$p[0]] = ($p[1] == 'all' ? '' : $p[1]); - } - - $dbw = wfGetDb(DB_MASTER); - $dbw->begin(); - $ok = $articleObj->updateRestrictions($protections, $params['reason'], $params['cascade'], $expiry); - if(!$ok) - // This is very weird. Maybe the article was deleted or the user was blocked/desysopped in the meantime? - $this->dieUsage('Unknown error', 'unknownerror'); - $dbw->commit(); - $res = array('title' => $titleObj->getPrefixedText(), 'reason' => $params['reason'], 'expiry' => $expiry); - if($params['cascade']) - $res['cascade'] = ''; - $res['protections'] = $protections; - $this->getResult()->addValue(null, $this->getModuleName(), $res); - } - - protected function getAllowedParams() { - return array ( - 'title' => null, - 'token' => null, - 'protections' => array( - ApiBase :: PARAM_ISMULTI => true - ), - 'expiry' => 'infinite', - 'reason' => '', - 'cascade' => false - ); - } - - protected 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)' - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php deleted file mode 100644 index 40485adf1c..0000000000 --- a/includes/api/ApiQuery.php +++ /dev/null @@ -1,501 +0,0 @@ -@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'); -} - -/** - * This is the main query class. It behaves similar to ApiMain: based on the parameters given, - * it will create a list of titles to work on (an instance of the ApiPageSet object) - * instantiate and execute various property/list/meta modules, - * and assemble all resulting data into a single ApiResult object. - * - * In the generator mode, a generator will be first executed to populate a second ApiPageSet object, - * and that object will be used for all subsequent modules. - * - * @addtogroup API - */ -class ApiQuery extends ApiBase { - - private $mPropModuleNames, $mListModuleNames, $mMetaModuleNames; - private $mPageSet; - private $params, $redirect; - - private $mQueryPropModules = array ( - 'info' => 'ApiQueryInfo', - 'revisions' => 'ApiQueryRevisions', - 'links' => 'ApiQueryLinks', - 'langlinks' => 'ApiQueryLangLinks', - 'images' => 'ApiQueryImages', - 'imageinfo' => 'ApiQueryImageInfo', - 'templates' => 'ApiQueryLinks', - 'categories' => 'ApiQueryCategories', - 'extlinks' => 'ApiQueryExternalLinks', - ); - - private $mQueryListModules = array ( - 'allpages' => 'ApiQueryAllpages', - 'alllinks' => 'ApiQueryAllLinks', - 'allusers' => 'ApiQueryAllUsers', - 'backlinks' => 'ApiQueryBacklinks', - 'blocks' => 'ApiQueryBlocks', - 'categorymembers' => 'ApiQueryCategoryMembers', - 'deletedrevs' => 'ApiQueryDeletedrevs', - 'embeddedin' => 'ApiQueryBacklinks', - 'imageusage' => 'ApiQueryBacklinks', - 'logevents' => 'ApiQueryLogEvents', - 'recentchanges' => 'ApiQueryRecentChanges', - 'search' => 'ApiQuerySearch', - 'usercontribs' => 'ApiQueryContributions', - 'watchlist' => 'ApiQueryWatchlist', - 'exturlusage' => 'ApiQueryExtLinksUsage', - ); - - private $mQueryMetaModules = array ( - 'siteinfo' => 'ApiQuerySiteinfo', - 'userinfo' => 'ApiQueryUserInfo', - 'allmessages' => 'ApiQueryAllmessages', - ); - - private $mSlaveDB = null; - private $mNamedDB = array(); - - public function __construct($main, $action) { - parent :: __construct($main, $action); - - // Allow custom modules to be added in LocalSettings.php - global $wgApiQueryPropModules, $wgApiQueryListModules, $wgApiQueryMetaModules; - self :: appendUserModules($this->mQueryPropModules, $wgApiQueryPropModules); - self :: appendUserModules($this->mQueryListModules, $wgApiQueryListModules); - self :: appendUserModules($this->mQueryMetaModules, $wgApiQueryMetaModules); - - $this->mPropModuleNames = array_keys($this->mQueryPropModules); - $this->mListModuleNames = array_keys($this->mQueryListModules); - $this->mMetaModuleNames = array_keys($this->mQueryMetaModules); - - // Allow the entire list of modules at first, - // but during module instantiation check if it can be used as a generator. - $this->mAllowedGenerators = array_merge($this->mListModuleNames, $this->mPropModuleNames); - } - - /** - * Helper function to append any add-in modules to the list - */ - private static function appendUserModules(&$modules, $newModules) { - if (is_array( $newModules )) { - foreach ( $newModules as $moduleName => $moduleClass) { - $modules[$moduleName] = $moduleClass; - } - } - } - - /** - * Gets a default slave database connection object - */ - public function getDB() { - if (!isset ($this->mSlaveDB)) { - $this->profileDBIn(); - $this->mSlaveDB = wfGetDB(DB_SLAVE); - $this->profileDBOut(); - } - return $this->mSlaveDB; - } - - /** - * Get the query database connection with the given name. - * If no such connection has been requested before, it will be created. - * Subsequent calls with the same $name will return the same connection - * as the first, regardless of $db or $groups new values. - */ - public function getNamedDB($name, $db, $groups) { - if (!array_key_exists($name, $this->mNamedDB)) { - $this->profileDBIn(); - $this->mNamedDB[$name] = wfGetDB($db, $groups); - $this->profileDBOut(); - } - return $this->mNamedDB[$name]; - } - - /** - * Gets the set of pages the user has requested (or generated) - */ - public function getPageSet() { - return $this->mPageSet; - } - - /** - * Query execution happens in the following steps: - * #1 Create a PageSet object with any pages requested by the user - * #2 If using generator, execute it to get a new PageSet object - * #3 Instantiate all requested modules. - * This way the PageSet object will know what shared data is required, - * and minimize DB calls. - * #4 Output all normalization and redirect resolution information - * #5 Execute all requested modules - */ - public function execute() { - - $this->params = $this->extractRequestParams(); - $this->redirects = $this->params['redirects']; - - // - // Create PageSet - // - $this->mPageSet = new ApiPageSet($this, $this->redirects); - - // - // Instantiate requested modules - // - $modules = array (); - $this->InstantiateModules($modules, 'prop', $this->mQueryPropModules); - $this->InstantiateModules($modules, 'list', $this->mQueryListModules); - $this->InstantiateModules($modules, 'meta', $this->mQueryMetaModules); - - // - // If given, execute generator to substitute user supplied data with generated data. - // - if (isset ($this->params['generator'])) { - $this->executeGeneratorModule($this->params['generator'], $modules); - } else { - // Append custom fields and populate page/revision information - $this->addCustomFldsToPageSet($modules, $this->mPageSet); - $this->mPageSet->execute(); - } - - // - // Record page information (title, namespace, if exists, etc) - // - $this->outputGeneralPageInfo(); - - // - // Execute all requested modules. - // - foreach ($modules as $module) { - $module->profileIn(); - $module->execute(); - $module->profileOut(); - } - } - - /** - * Query modules may optimize data requests through the $this->getPageSet() object - * by adding extra fields from the page table. - * This function will gather all the extra request fields from the modules. - */ - private function addCustomFldsToPageSet($modules, $pageSet) { - // Query all requested modules. - foreach ($modules as $module) { - $module->requestExtraData($pageSet); - } - } - - /** - * Create instances of all modules requested by the client - */ - private function InstantiateModules(&$modules, $param, $moduleList) { - $list = $this->params[$param]; - if (isset ($list)) - foreach ($list as $moduleName) - $modules[] = new $moduleList[$moduleName] ($this, $moduleName); - } - - /** - * Appends an element for each page in the current pageSet with the most general - * information (id, title), plus any title normalizations and missing title/pageids/revids. - */ - private function outputGeneralPageInfo() { - - $pageSet = $this->getPageSet(); - $result = $this->getResult(); - - // Title normalizations - $normValues = array (); - foreach ($pageSet->getNormalizedTitles() as $rawTitleStr => $titleStr) { - $normValues[] = array ( - 'from' => $rawTitleStr, - 'to' => $titleStr - ); - } - - if (!empty ($normValues)) { - $result->setIndexedTagName($normValues, 'n'); - $result->addValue('query', 'normalized', $normValues); - } - - // Interwiki titles - $intrwValues = array (); - foreach ($pageSet->getInterwikiTitles() as $rawTitleStr => $interwikiStr) { - $intrwValues[] = array ( - 'title' => $rawTitleStr, - 'iw' => $interwikiStr - ); - } - - if (!empty ($intrwValues)) { - $result->setIndexedTagName($intrwValues, 'i'); - $result->addValue('query', 'interwiki', $intrwValues); - } - - // Show redirect information - $redirValues = array (); - foreach ($pageSet->getRedirectTitles() as $titleStrFrom => $titleStrTo) { - $redirValues[] = array ( - 'from' => $titleStrFrom, - 'to' => $titleStrTo - ); - } - - if (!empty ($redirValues)) { - $result->setIndexedTagName($redirValues, 'r'); - $result->addValue('query', 'redirects', $redirValues); - } - - // - // Missing revision elements - // - $missingRevIDs = $pageSet->getMissingRevisionIDs(); - if (!empty ($missingRevIDs)) { - $revids = array (); - foreach ($missingRevIDs as $revid) { - $revids[$revid] = array ( - 'revid' => $revid - ); - } - $result->setIndexedTagName($revids, 'rev'); - $result->addValue('query', 'badrevids', $revids); - } - - // - // Page elements - // - $pages = array (); - - // Report any missing titles - foreach ($pageSet->getMissingTitles() as $fakeId => $title) { - $vals = array(); - ApiQueryBase :: addTitleInfo($vals, $title); - $vals['missing'] = ''; - $pages[$fakeId] = $vals; - } - - // Report any missing page ids - foreach ($pageSet->getMissingPageIDs() as $pageid) { - $pages[$pageid] = array ( - 'pageid' => $pageid, - 'missing' => '' - ); - } - - // Output general page information for found titles - foreach ($pageSet->getGoodTitles() as $pageid => $title) { - $vals = array(); - $vals['pageid'] = $pageid; - ApiQueryBase :: addTitleInfo($vals, $title); - $pages[$pageid] = $vals; - } - - if (!empty ($pages)) { - - if ($this->params['indexpageids']) { - $pageIDs = array_keys($pages); - // json treats all map keys as strings - converting to match - $pageIDs = array_map('strval', $pageIDs); - $result->setIndexedTagName($pageIDs, 'id'); - $result->addValue('query', 'pageids', $pageIDs); - } - - $result->setIndexedTagName($pages, 'page'); - $result->addValue('query', 'pages', $pages); - } - } - - /** - * For generator mode, execute generator, and use its output as new pageSet - */ - protected function executeGeneratorModule($generatorName, $modules) { - - // Find class that implements requested generator - if (isset ($this->mQueryListModules[$generatorName])) { - $className = $this->mQueryListModules[$generatorName]; - } elseif (isset ($this->mQueryPropModules[$generatorName])) { - $className = $this->mQueryPropModules[$generatorName]; - } else { - ApiBase :: dieDebug(__METHOD__, "Unknown generator=$generatorName"); - } - - // Generator results - $resultPageSet = new ApiPageSet($this, $this->redirects); - - // Create and execute the generator - $generator = new $className ($this, $generatorName); - if (!$generator instanceof ApiQueryGeneratorBase) - $this->dieUsage("Module $generatorName cannot be used as a generator", "badgenerator"); - - $generator->setGeneratorMode(); - - // Add any additional fields modules may need - $generator->requestExtraData($this->mPageSet); - $this->addCustomFldsToPageSet($modules, $resultPageSet); - - // Populate page information with the original user input - $this->mPageSet->execute(); - - // populate resultPageSet with the generator output - $generator->profileIn(); - $generator->executeGenerator($resultPageSet); - $resultPageSet->finishPageSetGeneration(); - $generator->profileOut(); - - // Swap the resulting pageset back in - $this->mPageSet = $resultPageSet; - } - - /** - * Returns the list of allowed parameters for this module. - * Qurey module also lists all ApiPageSet parameters as its own. - */ - protected function getAllowedParams() { - return array ( - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => $this->mPropModuleNames - ), - 'list' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => $this->mListModuleNames - ), - 'meta' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => $this->mMetaModuleNames - ), - 'generator' => array ( - ApiBase :: PARAM_TYPE => $this->mAllowedGenerators - ), - 'redirects' => false, - 'indexpageids' => false, - ); - } - - /** - * Override the parent to generate help messages for all available query modules. - */ - public function makeHelpMsg() { - - $msg = ''; - - // Make sure the internal object is empty - // (just in case a sub-module decides to optimize during instantiation) - $this->mPageSet = null; - $this->mAllowedGenerators = array(); // Will be repopulated - - $astriks = str_repeat('--- ', 8); - $msg .= "\n$astriks Query: Prop $astriks\n\n"; - $msg .= $this->makeHelpMsgHelper($this->mQueryPropModules, 'prop'); - $msg .= "\n$astriks Query: List $astriks\n\n"; - $msg .= $this->makeHelpMsgHelper($this->mQueryListModules, 'list'); - $msg .= "\n$astriks Query: Meta $astriks\n\n"; - $msg .= $this->makeHelpMsgHelper($this->mQueryMetaModules, 'meta'); - - // Perform the base call last because the $this->mAllowedGenerators - // will be updated inside makeHelpMsgHelper() - // Use parent to make default message for the query module - $msg = parent :: makeHelpMsg() . $msg; - - return $msg; - } - - /** - * For all modules in $moduleList, generate help messages and join them together - */ - private function makeHelpMsgHelper($moduleList, $paramName) { - - $moduleDscriptions = array (); - - foreach ($moduleList as $moduleName => $moduleClass) { - $module = new $moduleClass ($this, $moduleName, null); - - $msg = ApiMain::makeHelpMsgHeader($module, $paramName); - $msg2 = $module->makeHelpMsg(); - if ($msg2 !== false) - $msg .= $msg2; - if ($module instanceof ApiQueryGeneratorBase) { - $this->mAllowedGenerators[] = $moduleName; - $msg .= "Generator:\n This module may be used as a generator\n"; - } - $moduleDscriptions[] = $msg; - } - - return implode("\n", $moduleDscriptions); - } - - /** - * Override to add extra parameters from PageSet - */ - public function makeHelpMsgParameters() { - $psModule = new ApiPageSet($this); - return $psModule->makeHelpMsgParameters() . parent :: makeHelpMsgParameters(); - } - - // @todo should work correctly - public function shouldCheckMaxlag() { - return true; - } - - protected function getParamDescription() { - return array ( - 'prop' => 'Which properties to get for the titles/revisions/pageids', - 'list' => 'Which lists to get', - 'meta' => 'Which meta data to get about the site', - 'generator' => 'Use the output of a list as the input for other prop/list/meta items', - 'redirects' => 'Automatically resolve redirects', - 'indexpageids' => 'Include an additional pageids section listing all returned page IDs.' - ); - } - - protected 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.', - 'All data modifications will first have to use query to acquire a token to prevent abuse from malicious sites.' - ); - } - - protected function getExamples() { - return array ( - 'api.php?action=query&prop=revisions&meta=siteinfo&titles=Main%20Page&rvprop=user|comment' - ); - } - - public function getVersion() { - $psModule = new ApiPageSet($this); - $vers = array (); - $vers[] = __CLASS__ . ': $Id$'; - $vers[] = $psModule->getVersion(); - return $vers; - } -} - diff --git a/includes/api/ApiQueryAllLinks.php b/includes/api/ApiQueryAllLinks.php deleted file mode 100644 index a0c8766e9a..0000000000 --- a/includes/api/ApiQueryAllLinks.php +++ /dev/null @@ -1,179 +0,0 @@ -@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'); -} - -/** - * Query module to enumerate links from all pages together. - * - * @addtogroup API - */ -class ApiQueryAllLinks extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'al'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - $db = $this->getDB(); - $params = $this->extractRequestParams(); - - $prop = array_flip($params['prop']); - $fld_ids = isset($prop['ids']); - $fld_title = isset($prop['title']); - - if ($params['unique']) { - if (!is_null($resultPageSet)) - $this->dieUsage($this->getModuleName() . ' cannot be used as a generator in unique links mode', 'params'); - if ($fld_ids) - $this->dieUsage($this->getModuleName() . ' cannot return corresponding page ids in unique links mode', 'params'); - $this->addOption('DISTINCT'); - } - - $this->addTables('pagelinks'); - $this->addWhereFld('pl_namespace', $params['namespace']); - - if (!is_null($params['from'])) - $this->addWhere('pl_title>=' . $db->addQuotes(ApiQueryBase :: titleToKey($params['from']))); - if (isset ($params['prefix'])) - $this->addWhere("pl_title LIKE '" . $db->escapeLike(ApiQueryBase :: titleToKey($params['prefix'])) . "%'"); - - if (is_null($resultPageSet)) { - $this->addFields(array ( - 'pl_namespace', - 'pl_title' - )); - $this->addFieldsIf('pl_from', $fld_ids); - } else { - $this->addFields('pl_from'); - $pageids = array(); - } - - $this->addOption('USE INDEX', 'pl_namespace'); - $limit = $params['limit']; - $this->addOption('LIMIT', $limit+1); - $this->addOption('ORDER BY', 'pl_namespace, pl_title'); - - $res = $this->select(__METHOD__); - - $data = array (); - $count = 0; - 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... - // TODO: Security issue - if the user has no right to view next title, it will still be shown - $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->pl_title)); - break; - } - - if (is_null($resultPageSet)) { - $vals = array(); - if ($fld_ids) - $vals['fromid'] = intval($row->pl_from); - if ($fld_title) { - $title = Title :: makeTitle($row->pl_namespace, $row->pl_title); - $vals['ns'] = intval($title->getNamespace()); - $vals['title'] = $title->getPrefixedText(); - } - $data[] = $vals; - } else { - $pageids[] = $row->pl_from; - } - } - $db->freeResult($res); - - if (is_null($resultPageSet)) { - $result = $this->getResult(); - $result->setIndexedTagName($data, 'l'); - $result->addValue('query', $this->getModuleName(), $data); - } else { - $resultPageSet->populateFromPageIDs($pageids); - } - } - - protected function getAllowedParams() { - return array ( - 'from' => null, - 'prefix' => null, - 'unique' => false, - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_DFLT => 'title', - ApiBase :: PARAM_TYPE => array ( - 'ids', - 'title' - ) - ), - 'namespace' => array ( - ApiBase :: PARAM_DFLT => 0, - 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 - ) - ); - } - - protected function getParamDescription() { - return array ( - 'from' => 'The page title to start enumerating from.', - 'prefix' => 'Search for all page titles that begin with this value.', - 'unique' => 'Only show unique links. Cannot be used with generator or prop=ids', - 'prop' => 'What pieces of information to include', - 'namespace' => 'The namespace to enumerate.', - 'limit' => 'How many total links to return.' - ); - } - - protected function getDescription() { - return 'Enumerate all links that point to a given namespace'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=alllinks&alunique&alfrom=B', - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php deleted file mode 100644 index 7d554919d0..0000000000 --- a/includes/api/ApiQueryAllUsers.php +++ /dev/null @@ -1,211 +0,0 @@ -@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'); -} - -/** - * Query module to enumerate all registered users. - * - * @addtogroup API - */ -class ApiQueryAllUsers extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'au'); - } - - public function execute() { - $db = $this->getDB(); - $params = $this->extractRequestParams(); - - $prop = $params['prop']; - if (!is_null($prop)) { - $prop = array_flip($prop); - $fld_editcount = isset($prop['editcount']); - $fld_groups = isset($prop['groups']); - $fld_registration = isset($prop['registration']); - } else { - $fld_editcount = $fld_groups = $fld_registration = false; - } - - $limit = $params['limit']; - $tables = $db->tableName('user'); - - if( !is_null( $params['from'] ) ) - $this->addWhere( 'user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) ); - - if( isset( $params['prefix'] ) ) - $this->addWhere( 'user_name LIKE "' . $db->escapeLike( self::keyToTitle( $params['prefix'] ) ) . '%"' ); - - if (!is_null($params['group'])) { - // Filter only users that belong to a given group - $tblName = $db->tableName('user_groups'); - $tables = "$tables INNER JOIN $tblName ug1 ON ug1.ug_user=user_id"; - $this->addWhereFld('ug1.ug_group', $params['group']); - } - - if ($fld_groups) { - // Show the groups the given users belong to - // request more than needed to avoid not getting all rows that belong to one user - $groupCount = count(User::getAllGroups()); - $sqlLimit = $limit+$groupCount+1; - - $tblName = $db->tableName('user_groups'); - $tables = "$tables LEFT JOIN $tblName ug2 ON ug2.ug_user=user_id"; - $this->addFields('ug2.ug_group ug_group2'); - } else { - $sqlLimit = $limit+1; - } - - if ($fld_registration) - $this->addFields('user_registration'); - - $this->addOption('LIMIT', $sqlLimit); - $this->addTables($tables); - - $this->addFields('user_name'); - $this->addFieldsIf('user_editcount', $fld_editcount); - - $this->addOption('ORDER BY', 'user_name'); - - $res = $this->select(__METHOD__); - - $data = array (); - $count = 0; - $lastUserData = false; - $lastUser = false; - $result = $this->getResult(); - - // - // This loop keeps track of the last entry. - // For each new row, if the new row is for different user then the last, the last entry is added to results. - // Otherwise, the group of the new row is appended to the last entry. - // The setContinue... is more complex because of this, and takes into account the higher sql limit - // to make sure all rows that belong to the same user are received. - // - while (true) { - - $row = $db->fetchObject($res); - $count++; - - if (!$row || $lastUser != $row->user_name) { - // Save the last pass's user data - if (is_array($lastUserData)) - $data[] = $lastUserData; - - // No more rows left - if (!$row) - break; - - if ($count > $limit) { - // We've reached the one extra which shows that there are additional pages to be had. Stop here... - $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->user_name)); - break; - } - - // Record new user's data - $lastUser = $row->user_name; - $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); - - } - - if ($sqlLimit == $count) { - // BUG! database contains group name that User::getAllGroups() does not return - // TODO: should handle this more gracefully - ApiBase :: dieDebug(__METHOD__, - 'MediaWiki configuration error: the database contains more user groups than known to User::getAllGroups() function'); - } - - // Add user's group info - if ($fld_groups && !is_null($row->ug_group2)) { - $lastUserData['groups'][] = $row->ug_group2; - $result->setIndexedTagName($lastUserData['groups'], 'g'); - } - } - - $db->freeResult($res); - - $result->setIndexedTagName($data, 'u'); - $result->addValue('query', $this->getModuleName(), $data); - } - - protected function getAllowedParams() { - return array ( - 'from' => null, - 'prefix' => null, - 'group' => array( - ApiBase :: PARAM_TYPE => User::getAllGroups() - ), - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'editcount', - 'groups', - 'registration', - ) - ), - '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 - ) - ); - } - - protected function getParamDescription() { - return array ( - 'from' => 'The user name to start enumerating from.', - 'prefix' => 'Search for all page titles that begin with this value.', - 'group' => 'Limit users to a given group name', - 'prop' => array( - 'What pieces of information to include.', - '`groups` property uses more server resources and may return fewer results than the limit.'), - 'limit' => 'How many total user names to return.', - ); - } - - protected function getDescription() { - return 'Enumerate all registered users'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=allusers&aufrom=Y', - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryAllmessages.php b/includes/api/ApiQueryAllmessages.php deleted file mode 100644 index 9fe74e662b..0000000000 --- a/includes/api/ApiQueryAllmessages.php +++ /dev/null @@ -1,120 +0,0 @@ -@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(); - - //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( null, $this->getModuleName(), $messages_out ); - } - - protected function getAllowedParams() { - return array ( - 'messages' => array ( - ApiBase :: PARAM_DFLT => '*', - ), - 'filter' => array(), - ); - } - - protected function getParamDescription() { - return array ( - 'messages' => 'Which messages to output. "*" means all messages', - 'filter' => 'Return only messages that contains specified string', - ); - } - - protected 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', - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryAllpages.php b/includes/api/ApiQueryAllpages.php deleted file mode 100644 index 8f7daecc24..0000000000 --- a/includes/api/ApiQueryAllpages.php +++ /dev/null @@ -1,234 +0,0 @@ -@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'); -} - -/** - * Query module to enumerate all available pages. - * - * @addtogroup API - */ -class ApiQueryAllpages extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'ap'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - if ($resultPageSet->isResolvingRedirects()) - $this->dieUsage('Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator', 'params'); - - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - $db = $this->getDB(); - - $params = $this->extractRequestParams(); - - // Page filters - if (!$this->addWhereIf('page_is_redirect = 1', $params['filterredir'] === 'redirects')) - $this->addWhereIf('page_is_redirect = 0', $params['filterredir'] === 'nonredirects'); - $this->addWhereFld('page_namespace', $params['namespace']); - if (!is_null($params['from'])) - $this->addWhere('page_title>=' . $db->addQuotes(ApiQueryBase :: titleToKey($params['from']))); - if (isset ($params['prefix'])) - $this->addWhere("page_title LIKE '" . $db->escapeLike(ApiQueryBase :: titleToKey($params['prefix'])) . "%'"); - - $forceNameTitleIndex = true; - if (isset ($params['minsize'])) { - $this->addWhere('page_len>=' . intval($params['minsize'])); - $forceNameTitleIndex = false; - } - - if (isset ($params['maxsize'])) { - $this->addWhere('page_len<=' . intval($params['maxsize'])); - $forceNameTitleIndex = false; - } - - // Page protection filtering - if (isset ($params['prtype'])) { - $this->addTables('page_restrictions'); - $this->addWhere('page_id=pr_page'); - $this->addWhere('pr_expiry>' . $db->addQuotes($db->timestamp())); - $this->addWhereFld('pr_type', $params['prtype']); - - $prlevel = $params['prlevel']; - if (!is_null($prlevel) && $prlevel != '' && $prlevel != '*') - $this->addWhereFld('pr_level', $prlevel); - - $this->addOption('DISTINCT'); - - $forceNameTitleIndex = false; - - } else if (isset ($params['prlevel'])) { - $this->dieUsage('prlevel may not be used without prtype', 'params'); - } - - $this->addTables('page'); - if ($forceNameTitleIndex) - $this->addOption('USE INDEX', 'name_title'); - - - if (is_null($resultPageSet)) { - $this->addFields(array ( - 'page_id', - 'page_namespace', - 'page_title' - )); - } else { - $this->addFields($resultPageSet->getPageTableFields()); - } - - $limit = $params['limit']; - $this->addOption('LIMIT', $limit+1); - $this->addOption('ORDER BY', 'page_namespace, page_title' . - ($params['dir'] == 'ZtoA' ? ' DESC' : '')); - - $res = $this->select(__METHOD__); - - $data = array (); - $count = 0; - 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... - // TODO: Security issue - if the user has no right to view next title, it will still be shown - $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->page_title)); - break; - } - - if (is_null($resultPageSet)) { - $title = Title :: makeTitle($row->page_namespace, $row->page_title); - $data[] = array( - 'pageid' => intval($row->page_id), - 'ns' => intval($title->getNamespace()), - 'title' => $title->getPrefixedText()); - } else { - $resultPageSet->processDbRow($row); - } - } - $db->freeResult($res); - - if (is_null($resultPageSet)) { - $result = $this->getResult(); - $result->setIndexedTagName($data, 'p'); - $result->addValue('query', $this->getModuleName(), $data); - } - } - - protected function getAllowedParams() { - global $wgRestrictionTypes, $wgRestrictionLevels; - - return array ( - 'from' => null, - 'prefix' => null, - 'namespace' => array ( - ApiBase :: PARAM_DFLT => 0, - ApiBase :: PARAM_TYPE => 'namespace', - ), - 'filterredir' => array ( - ApiBase :: PARAM_DFLT => 'all', - ApiBase :: PARAM_TYPE => array ( - 'all', - 'redirects', - 'nonredirects' - ) - ), - 'minsize' => array ( - ApiBase :: PARAM_TYPE => 'integer', - ), - 'maxsize' => array ( - ApiBase :: PARAM_TYPE => 'integer', - ), - '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, - ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, - ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 - ), - 'dir' => array ( - ApiBase :: PARAM_DFLT => 'AtoZ', - ApiBase :: PARAM_TYPE => array ( - 'AtoZ', - 'ZtoA' - ) - ) - ); - } - - protected 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)', - 'limit' => 'How many total pages to return.' - ); - } - - protected function getDescription() { - return 'Enumerate all pages sequentially in a given namespace'; - } - - protected function getExamples() { - return array ( - 'Simple Use', - ' Show a list of pages starting at the letter "B"', - ' api.php?action=query&list=allpages&apfrom=B', - 'Using as Generator', - ' Show info about 4 pages starting at the letter "T"', - ' api.php?action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info', - ' Show content of first 2 non-redirect pages begining at "Re"', - ' api.php?action=query&generator=allpages&gaplimit=2&gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryBacklinks.php b/includes/api/ApiQueryBacklinks.php deleted file mode 100644 index bdd72acb6b..0000000000 --- a/includes/api/ApiQueryBacklinks.php +++ /dev/null @@ -1,393 +0,0 @@ -@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"); -} - -/** - * This is three-in-one module to query: - * * backlinks - links pointing to the given page, - * * embeddedin - what pages transclude the given page within themselves, - * * imageusage - what pages use the given image - * - * @addtogroup API - */ -class ApiQueryBacklinks extends ApiQueryGeneratorBase { - - private $params, $rootTitle, $contRedirs, $contLevel, $contTitle, $contID; - - // output element name, database column field prefix, database table - private $backlinksSettings = array ( - 'backlinks' => array ( - 'code' => 'bl', - 'prefix' => 'pl', - 'linktbl' => 'pagelinks' - ), - 'embeddedin' => array ( - 'code' => 'ei', - 'prefix' => 'tl', - 'linktbl' => 'templatelinks' - ), - 'imageusage' => array ( - 'code' => 'iu', - 'prefix' => 'il', - 'linktbl' => 'imagelinks' - ) - ); - - public function __construct($query, $moduleName) { - $code = $prefix = $linktbl = null; - extract($this->backlinksSettings[$moduleName]); - - parent :: __construct($query, $moduleName, $code); - $this->bl_ns = $prefix . '_namespace'; - $this->bl_from = $prefix . '_from'; - $this->bl_tables = array ( - $linktbl, - 'page' - ); - $this->bl_code = $code; - - $this->hasNS = $moduleName !== 'imageusage'; - if ($this->hasNS) { - $this->bl_title = $prefix . '_title'; - $this->bl_sort = "{$this->bl_ns}, {$this->bl_title}, {$this->bl_from}"; - $this->bl_fields = array ( - $this->bl_ns, - $this->bl_title - ); - } else { - $this->bl_title = $prefix . '_to'; - $this->bl_sort = "{$this->bl_title}, {$this->bl_from}"; - $this->bl_fields = array ( - $this->bl_title - ); - } - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - $this->params = $this->extractRequestParams(); - - $redirect = $this->params['redirect']; - if ($redirect) - $this->dieDebug('Redirect has not been implemented', 'notimplemented'); - - $this->processContinue(); - - $this->addFields($this->bl_fields); - if (is_null($resultPageSet)) - $this->addFields(array ( - 'page_id', - 'page_namespace', - 'page_title' - )); - else - $this->addFields($resultPageSet->getPageTableFields()); // will include page_id - - $this->addTables($this->bl_tables); - $this->addWhere($this->bl_from . '=page_id'); - - if ($this->hasNS) - $this->addWhereFld($this->bl_ns, $this->rootTitle->getNamespace()); - $this->addWhereFld($this->bl_title, $this->rootTitle->getDBkey()); - $this->addWhereFld('page_namespace', $this->params['namespace']); - - if($this->params['filterredir'] == 'redirects') - $this->addWhereFld('page_is_redirect', 1); - if($this->params['filterredir'] == 'nonredirects') - $this->addWhereFld('page_is_redirect', 0); - - $limit = $this->params['limit']; - $this->addOption('LIMIT', $limit +1); - $this->addOption('ORDER BY', $this->bl_sort); - - $db = $this->getDB(); - if (!is_null($this->params['continue'])) { - $plfrm = intval($this->contID); - if ($this->contLevel == 0) { - // For the first level, there is only one target title, so no need for complex filtering - $this->addWhere($this->bl_from . '>=' . $plfrm); - } else { - $ns = $this->contTitle->getNamespace(); - $t = $db->addQuotes($this->contTitle->getDBkey()); - $whereWithoutNS = "{$this->bl_title}>$t OR ({$this->bl_title}=$t AND {$this->bl_from}>=$plfrm))"; - - if ($this->hasNS) - $this->addWhere("{$this->bl_ns}>$ns OR ({$this->bl_ns}=$ns AND ($whereWithoutNS)"); - else - $this->addWhere($whereWithoutNS); - } - } - - $res = $this->select(__METHOD__); - - $count = 0; - $data = array (); - 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... - if ($redirect) { - $ns = $row-> { $this->bl_ns }; - $t = $row-> { $this->bl_title }; - $continue = $this->getContinueRedirStr(false, 0, $ns, $t, $row->page_id); - } else - $continue = $this->getContinueStr($row->page_id); - // TODO: Security issue - if the user has no right to view next title, it will still be shown - $this->setContinueEnumParameter('continue', $continue); - break; - } - - if (is_null($resultPageSet)) { - $vals = $this->extractRowInfo($row); - if ($vals) - $data[] = $vals; - } else { - $resultPageSet->processDbRow($row); - } - } - $db->freeResult($res); - - if (is_null($resultPageSet)) { - $result = $this->getResult(); - $result->setIndexedTagName($data, $this->bl_code); - $result->addValue('query', $this->getModuleName(), $data); - } - } - - private function extractRowInfo($row) { - - $vals = array(); - $vals['pageid'] = intval($row->page_id); - ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle($row->page_namespace, $row->page_title)); - - return $vals; - } - - protected function processContinue() { - $pageSet = $this->getPageSet(); - $count = $pageSet->getTitleCount(); - - if (!is_null($this->params['continue'])) { - $this->parseContinueParam(); - - // Skip all completed links - - } else { - $title = $this->params['title']; - if (!is_null($title)) { - $this->rootTitle = Title :: newFromText($title); - } else { // This case is obsolete. Will support this for a while - if ($count !== 1) - $this->dieUsage("The {$this->getModuleName()} query requires one title to start", 'bad_title_count'); - $this->rootTitle = current($pageSet->getTitles()); // only one title there - $this->setWarning('Using titles parameter is obsolete for this list. Use ' . $this->encodeParamName('title') . ' instead.'); - } - } - - // only image titles are allowed for the root - if (!$this->hasNS && $this->rootTitle->getNamespace() !== NS_IMAGE) - $this->dieUsage("The title for {$this->getModuleName()} query must be an image", 'bad_image_title'); - } - - protected function parseContinueParam() { - $continueList = explode('|', $this->params['continue']); - if ($this->params['redirect']) { - // - // expected redirect-mode parameter: - // ns|db_key|step|level|ns|db_key|id - // ns+db_key -- the root title - // step = 1 or 2 - which step to continue from - 1-titles, 2-redirects - // level -- how many levels to follow before starting enumerating. - // if level > 0 -- ns+title to continue from, otherwise skip these - // id = last page_id to continue from - // - if (count($continueList) > 4) { - $rootNs = intval($continueList[0]); - if (($rootNs !== 0 || $continueList[0] === '0') && !empty ($continueList[1])) { - $this->rootTitle = Title :: makeTitleSafe($rootNs, $continueList[1]); - if ($this->rootTitle) { - - $step = intval($continueList[2]); - if ($step === 1 || $step === 2) { - $this->contRedirs = ($step === 2); - - $level = intval($continueList[3]); - if ($level !== 0 || $continueList[3] === '0') { - $this->contLevel = $level; - - if ($level === 0) { - if (count($continueList) === 5) { - $contID = intval($continueList[4]); - if ($contID !== 0 || $continueList[4] === '0') { - $this->contID = $contID; - return; // done - } - } - } else { - if (count($continueList) === 7) { - $contNs = intval($continueList[4]); - if (($contNs !== 0 || $continueList[4] === '0') && !empty ($continueList[5])) { - $this->contTitle = Title :: makeTitleSafe($contNs, $continueList[5]); - - $contID = intval($continueList[6]); - if ($contID !== 0 || $continueList[6] === '0') { - $this->contID = $contID; - return; // done - } - } - } - } - } - } - } - } - } - } else { - // - // expected non-redirect-mode parameter: - // ns|db_key|id - // ns+db_key -- the root title - // id = last page_id to continue from - // - if (count($continueList) === 3) { - $rootNs = intval($continueList[0]); - if (($rootNs !== 0 || $continueList[0] === '0') && !empty ($continueList[1])) { - $this->rootTitle = Title :: makeTitleSafe($rootNs, $continueList[1]); - if ($this->rootTitle) { - - $contID = intval($continueList[2]); - if ($contID !== 0) { - $this->contID = $contID; - return; // done - } - } - } - } - } - - $this->dieUsage("Invalid continue param. You should pass the original value returned by the previous query", "_badcontinue"); - } - - protected function getContinueStr($lastPageID) { - return $this->rootTitle->getNamespace() . - '|' . $this->rootTitle->getDBkey() . - '|' . $lastPageID; - } - - protected function getContinueRedirStr($isRedirPhase, $level, $ns, $title, $lastPageID) { - return $this->rootTitle->getNamespace() . - '|' . $this->rootTitle->getDBkey() . - '|' . ($isRedirPhase ? 1 : 2) . - '|' . $level . - ($level > 0 ? ('|' . $ns . '|' . $title) : '') . - '|' . $lastPageID; - } - - protected function getAllowedParams() { - - return array ( - 'title' => null, - 'continue' => null, - 'namespace' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => 'namespace' - ), - 'filterredir' => array( - ApiBase :: PARAM_DFLT => 'all', - ApiBase :: PARAM_TYPE => array( - 'all', - 'redirects', - 'nonredirects' - ) - ), - 'redirect' => false, - '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 - ) - ); - } - - protected 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.', - 'namespace' => 'The namespace to enumerate.', - 'filterredir' => 'How to filter for redirects', - 'redirect' => 'If linking page is a redirect, find all pages that link to that redirect (not implemented)', - 'limit' => 'How many total pages to return.' - ); - } - - protected function getDescription() { - switch ($this->getModuleName()) { - case 'backlinks' : - return 'Find all pages that link to the given page'; - case 'embeddedin' : - return 'Find all pages that embed (transclude) the given title'; - case 'imageusage' : - return 'Find all pages that use the given image title.'; - default : - ApiBase :: dieDebug(__METHOD__, 'Unknown module name'); - } - } - - protected function getExamples() { - static $examples = array ( - 'backlinks' => array ( - "api.php?action=query&list=backlinks&bltitle=Main%20Page", - "api.php?action=query&generator=backlinks&gbltitle=Main%20Page&prop=info" - ), - 'embeddedin' => array ( - "api.php?action=query&list=embeddedin&eititle=Template:Stub", - "api.php?action=query&generator=embeddedin&geititle=Template:Stub&prop=info" - ), - 'imageusage' => array ( - "api.php?action=query&list=imageusage&iutitle=Image:Albert%20Einstein%20Head.jpg", - "api.php?action=query&generator=imageusage&giutitle=Image:Albert%20Einstein%20Head.jpg&prop=info" - ) - ); - - return $examples[$this->getModuleName()]; - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php deleted file mode 100644 index 69492dbe97..0000000000 --- a/includes/api/ApiQueryBase.php +++ /dev/null @@ -1,265 +0,0 @@ -@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'); -} - -/** - * This is a base class for all Query modules. - * It provides some common functionality such as constructing various SQL queries. - * - * @addtogroup API - */ -abstract class ApiQueryBase extends ApiBase { - - private $mQueryModule, $mDb, $tables, $where, $fields, $options; - - public function __construct($query, $moduleName, $paramPrefix = '') { - parent :: __construct($query->getMain(), $moduleName, $paramPrefix); - $this->mQueryModule = $query; - $this->mDb = null; - $this->resetQueryParams(); - } - - protected function resetQueryParams() { - $this->tables = array (); - $this->where = array (); - $this->fields = array (); - $this->options = array (); - } - - protected function addTables($tables, $alias = null) { - if (is_array($tables)) { - if (!is_null($alias)) - ApiBase :: dieDebug(__METHOD__, 'Multiple table aliases not supported'); - $this->tables = array_merge($this->tables, $tables); - } else { - if (!is_null($alias)) - $tables = $this->getDB()->tableName($tables) . ' ' . $alias; - $this->tables[] = $tables; - } - } - - protected function addFields($value) { - if (is_array($value)) - $this->fields = array_merge($this->fields, $value); - else - $this->fields[] = $value; - } - - protected function addFieldsIf($value, $condition) { - if ($condition) { - $this->addFields($value); - return true; - } - return false; - } - - protected function addWhere($value) { - if (is_array($value)) - $this->where = array_merge($this->where, $value); - else - $this->where[] = $value; - } - - protected function addWhereIf($value, $condition) { - if ($condition) { - $this->addWhere($value); - return true; - } - return false; - } - - protected function addWhereFld($field, $value) { - if (!is_null($value)) - $this->where[$field] = $value; - } - - protected function addWhereRange($field, $dir, $start, $end) { - $isDirNewer = ($dir === 'newer'); - $after = ($isDirNewer ? '>=' : '<='); - $before = ($isDirNewer ? '<=' : '>='); - $db = $this->getDB(); - - if (!is_null($start)) - $this->addWhere($field . $after . $db->addQuotes($start)); - - if (!is_null($end)) - $this->addWhere($field . $before . $db->addQuotes($end)); - - $this->addOption('ORDER BY', $field . ($isDirNewer ? '' : ' DESC')); - } - - protected function addOption($name, $value = null) { - if (is_null($value)) - $this->options[] = $name; - else - $this->options[$name] = $value; - } - - protected function select($method) { - - // getDB has its own profileDBIn/Out calls - $db = $this->getDB(); - - $this->profileDBIn(); - $res = $db->select($this->tables, $this->fields, $this->where, $method, $this->options); - $this->profileDBOut(); - - return $res; - } - - public static function addTitleInfo(&$arr, $title, $prefix='') { - $arr[$prefix . 'ns'] = intval($title->getNamespace()); - $arr[$prefix . 'title'] = $title->getPrefixedText(); - } - - /** - * Override this method to request extra fields from the pageSet - * using $pageSet->requestField('fieldName') - */ - public function requestExtraData($pageSet) { - } - - /** - * Get the main Query module - */ - public function getQuery() { - return $this->mQueryModule; - } - - /** - * Add sub-element under the page element with the given pageId. - */ - protected function addPageSubItems($pageId, $data) { - $result = $this->getResult(); - $result->setIndexedTagName($data, $this->getModulePrefix()); - $result->addValue(array ('query', 'pages', intval($pageId)), - $this->getModuleName(), - $data); - } - - protected function setContinueEnumParameter($paramName, $paramValue) { - - $paramName = $this->encodeParamName($paramName); - $msg = array( $paramName => $paramValue ); - -// This is an alternative continue format as a part of the URL string -// ApiResult :: setContent($msg, $paramName . '=' . urlencode($paramValue)); - - $this->getResult()->addValue('query-continue', $this->getModuleName(), $msg); - } - - /** - * Get the Query database connection (readonly) - */ - protected function getDB() { - if (is_null($this->mDb)) - $this->mDb = $this->getQuery()->getDB(); - return $this->mDb; - } - - /** - * Selects the query database connection with the given name. - * If no such connection has been requested before, it will be created. - * Subsequent calls with the same $name will return the same connection - * as the first, regardless of $db or $groups new values. - */ - public function selectNamedDB($name, $db, $groups) { - $this->mDb = $this->getQuery()->getNamedDB($name, $db, $groups); - } - - /** - * Get the PageSet object to work on - * @return ApiPageSet data - */ - protected function getPageSet() { - return $this->getQuery()->getPageSet(); - } - - /** - * This is a very simplistic utility function - * to convert a non-namespaced title string to a db key. - * It will replace all ' ' with '_' - */ - public static function titleToKey($title) { - return str_replace(' ', '_', $title); - } - - public static function keyToTitle($key) { - return str_replace('_', ' ', $key); - } - - public function getTokenFlag($tokenArr, $action) { - if (in_array($action, $tokenArr)) { - global $wgUser; - if ($wgUser->isAllowed($action)) - return true; - else - $this->dieUsage("Action '$action' is not allowed for the current user", 'permissiondenied'); - } - return false; - } - - public static function getBaseVersion() { - return __CLASS__ . ': $Id$'; - } -} - -/** - * @addtogroup API - */ -abstract class ApiQueryGeneratorBase extends ApiQueryBase { - - private $mIsGenerator; - - public function __construct($query, $moduleName, $paramPrefix = '') { - parent :: __construct($query, $moduleName, $paramPrefix); - $this->mIsGenerator = false; - } - - public function setGeneratorMode() { - $this->mIsGenerator = true; - } - - /** - * Overrides base class to prepend 'g' to every generator parameter - */ - public function encodeParamName($paramName) { - if ($this->mIsGenerator) - return 'g' . parent :: encodeParamName($paramName); - else - return parent :: encodeParamName($paramName); - } - - /** - * Execute this module as a generator - * @param $resultPageSet PageSet: All output should be appended to this object - */ - public abstract function executeGenerator($resultPageSet); -} - diff --git a/includes/api/ApiQueryBlocks.php b/includes/api/ApiQueryBlocks.php deleted file mode 100644 index 8f5536888a..0000000000 --- a/includes/api/ApiQueryBlocks.php +++ /dev/null @@ -1,241 +0,0 @@ -.@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) - { - $block['user'] = $row->ipb_address; - $block['userid'] = $row->ipb_user; - } - if($fld_by) - { - $block['by'] = $row->user_name; - $block['byuserid'] = $row->ipb_by; - } - if($fld_timestamp) - $block['timestamp'] = wfTimestamp(TS_ISO_8601, $row->ipb_timestamp); - if($fld_expiry) - $block['expiry'] = Block::decodeExpiry($row->ipb_expiry, TS_ISO_8601); - 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); - } - - protected 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 - ) - ); - } - - protected 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', - ); - } - - protected function getDescription() { - return 'List all blocked users and IP addresses.'; - } - - protected function getExamples() { - return array ( - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryCategories.php b/includes/api/ApiQueryCategories.php deleted file mode 100644 index 2283a8b978..0000000000 --- a/includes/api/ApiQueryCategories.php +++ /dev/null @@ -1,157 +0,0 @@ -@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 module to enumerate categories the set of pages belong to. - * - * @addtogroup API - */ -class ApiQueryCategories extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'cl'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - if ($this->getPageSet()->getGoodTitleCount() == 0) - return; // nothing to do - - $params = $this->extractRequestParams(); - $prop = $params['prop']; - - $this->addFields(array ( - 'cl_from', - 'cl_to' - )); - - $fld_sortkey = false; - if (!is_null($prop)) { - foreach($prop as $p) { - switch ($p) { - case 'sortkey': - $this->addFields('cl_sortkey'); - $fld_sortkey = true; - break; - default : - ApiBase :: dieDebug(__METHOD__, "Unknown prop=$p"); - } - } - } - - $this->addTables('categorylinks'); - $this->addWhereFld('cl_from', array_keys($this->getPageSet()->getGoodTitles())); - $this->addOption('ORDER BY', "cl_from, cl_to"); - - $db = $this->getDB(); - $res = $this->select(__METHOD__); - - if (is_null($resultPageSet)) { - - $data = array(); - $lastId = 0; // database has no ID 0 - while ($row = $db->fetchObject($res)) { - if ($lastId != $row->cl_from) { - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - $data = array(); - } - $lastId = $row->cl_from; - } - - $title = Title :: makeTitle(NS_CATEGORY, $row->cl_to); - - $vals = array(); - ApiQueryBase :: addTitleInfo($vals, $title); - if ($fld_sortkey) - $vals['sortkey'] = $row->cl_sortkey; - - $data[] = $vals; - } - - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - } - - } else { - - $titles = array(); - while ($row = $db->fetchObject($res)) { - $titles[] = Title :: makeTitle(NS_CATEGORY, $row->cl_to); - } - $resultPageSet->populateFromTitles($titles); - } - - $db->freeResult($res); - } - - protected function getAllowedParams() { - return array ( - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'sortkey', - ) - ) - ); - } - - protected function getParamDescription() { - return array ( - 'prop' => 'Which additional properties to get for each category.', - ); - } - - protected function getDescription() { - return 'List all categories the page(s) belong to'; - } - - protected function getExamples() { - return array ( - "Get a list of categories [[Albert Einstein]] belongs to:", - " api.php?action=query&prop=categories&titles=Albert%20Einstein", - "Get information about all categories used in the [[Albert Einstein]]:", - " api.php?action=query&generator=categories&titles=Albert%20Einstein&prop=info" - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryCategoryMembers.php b/includes/api/ApiQueryCategoryMembers.php deleted file mode 100644 index 487fea8b16..0000000000 --- a/includes/api/ApiQueryCategoryMembers.php +++ /dev/null @@ -1,246 +0,0 @@ -@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 module to enumerate pages that belong to a category. - * - * @addtogroup API - */ -class ApiQueryCategoryMembers extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'cm'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - $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'); - - $prop = array_flip($params['prop']); - $fld_ids = isset($prop['ids']); - $fld_title = isset($prop['title']); - $fld_sortkey = isset($prop['sortkey']); - $fld_timestamp = isset($prop['timestamp']); - - if (is_null($resultPageSet)) { - $this->addFields(array('cl_from', 'cl_sortkey', 'page_namespace', 'page_title')); - $this->addFieldsIf('page_id', $fld_ids); - } else { - $this->addFields($resultPageSet->getPageTableFields()); // will include page_ id, ns, title - $this->addFields(array('cl_from', 'cl_sortkey')); - } - - $this->addFieldsIf('cl_timestamp', $fld_timestamp); - $this->addTables(array('page','categorylinks')); // must be in this order for 'USE INDEX' - // Not needed after bug 10280 is applied to servers - if($params['sort'] == 'timestamp') - { - $this->addOption('USE INDEX', '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' . ($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']); - - $limit = $params['limit']; - $this->addOption('LIMIT', $limit +1); - - $db = $this->getDB(); - - $data = array (); - $count = 0; - $lastSortKey = null; - $res = $this->select(__METHOD__); - 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... - // TODO: Security issue - if the user has no right to view next title, it will still be shown - $this->setContinueEnumParameter('continue', $this->getContinueStr($row, $lastSortKey)); - break; - } - - $lastSortKey = $row->cl_sortkey; // detect duplicate sortkeys - - if (is_null($resultPageSet)) { - $vals = array(); - if ($fld_ids) - $vals['pageid'] = intval($row->page_id); - if ($fld_title) { - $title = Title :: makeTitle($row->page_namespace, $row->page_title); - $vals['ns'] = intval($title->getNamespace()); - $vals['title'] = $title->getPrefixedText(); - } - if ($fld_sortkey) - $vals['sortkey'] = $row->cl_sortkey; - if ($fld_timestamp) - $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->cl_timestamp); - $data[] = $vals; - } else { - $resultPageSet->processDbRow($row); - } - } - $db->freeResult($res); - - if (is_null($resultPageSet)) { - $this->getResult()->setIndexedTagName($data, 'cm'); - $this->getResult()->addValue('query', $this->getModuleName(), $data); - } - } - - private function getContinueStr($row, $lastSortKey) { - $ret = $row->cl_sortkey . '|'; - if ($row->cl_sortkey == $lastSortKey) // duplicate sort key, add cl_from - $ret .= $row->cl_from; - return $ret; - } - - /** - * Add DB WHERE clause to continue previous query based on 'continue' parameter - */ - private function setContinuation($continue) { - if (is_null($continue)) - return; // This is not a continuation request - - $continueList = explode('|', $continue); - $hasError = count($continueList) != 2; - $from = 0; - if (!$hasError && strlen($continueList[1]) > 0) { - $from = intval($continueList[1]); - $hasError = ($from == 0); - } - - if ($hasError) - $this->dieUsage("Invalid continue param. You should pass the original value returned by the previous query", "badcontinue"); - - $encSortKey = $this->getDB()->addQuotes($continueList[0]); - $encFrom = $this->getDB()->addQuotes($from); - - if ($from != 0) { - // Duplicate sort key continue - $this->addWhere( "cl_sortkey>$encSortKey OR (cl_sortkey=$encSortKey AND cl_from>=$encFrom)" ); - } else { - $this->addWhere( "cl_sortkey>=$encSortKey" ); - } - } - - protected function getAllowedParams() { - return array ( - 'category' => null, - 'prop' => array ( - ApiBase :: PARAM_DFLT => 'ids|title', - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'ids', - 'title', - 'sortkey', - 'timestamp', - ) - ), - 'namespace' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => 'namespace', - ), - 'continue' => null, - 'limit' => array ( - ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_DFLT => 10, - ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, - ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 - ), - 'sort' => array( - ApiBase :: PARAM_DFLT => 'sortkey', - ApiBase :: PARAM_TYPE => array( - 'sortkey', - 'timestamp' - ) - ), - 'dir' => array( - ApiBase :: PARAM_DFLT => 'asc', - ApiBase :: PARAM_TYPE => array( - 'asc', - 'desc' - ) - ) - ); - } - - protected function getParamDescription() { - return array ( - 'category' => 'Which category to enumerate (required)', - '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', - 'continue' => 'For large categories, give the value retured from previous query', - 'limit' => 'The maximum number of pages to return.', - ); - } - - protected 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", - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php deleted file mode 100644 index 57e7fc0ad8..0000000000 --- a/includes/api/ApiQueryDeletedrevs.php +++ /dev/null @@ -1,230 +0,0 @@ -.@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(); - $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 limits and stricter restrictions - if(!$wgUser->isAllowed('undelete')) - $this->dieUsage('You don\'t have permission to view deleted revision content', 'permissiondenied'); - $userMax = ApiBase :: LIMIT_SML1; - $botMax = ApiBase :: LIMIT_SML2; - $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); - } - - protected 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 - ) - ); - } - - protected 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' - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiQueryExtLinksUsage.php b/includes/api/ApiQueryExtLinksUsage.php deleted file mode 100644 index 2e47a5750c..0000000000 --- a/includes/api/ApiQueryExtLinksUsage.php +++ /dev/null @@ -1,200 +0,0 @@ -@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'); -} - -/** - * @addtogroup API - */ -class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'eu'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - $params = $this->extractRequestParams(); - - $protocol = $params['protocol']; - $query = $params['query']; - if (is_null($query)) - $this->dieUsage('Missing required query parameter', 'params'); - - // Find the right prefix - global $wgUrlProtocols; - foreach ($wgUrlProtocols as $p) { - if( substr( $p, 0, strlen( $protocol ) ) === $protocol ) { - $protocol = $p; - break; - } - } - - $likeQuery = LinkFilter::makeLike($query , $protocol); - if (!$likeQuery) - $this->dieUsage('Invalid query', 'bad_query'); - $likeQuery = substr($likeQuery, 0, strpos($likeQuery,'%')+1); - - $this->addTables(array('page','externallinks')); // must be in this order for 'USE INDEX' - $this->addOption('USE INDEX', 'el_index'); - - $db = $this->getDB(); - $this->addWhere('page_id=el_from'); - $this->addWhere('el_index LIKE ' . $db->addQuotes( $likeQuery )); - $this->addWhereFld('page_namespace', $params['namespace']); - - $prop = array_flip($params['prop']); - $fld_ids = isset($prop['ids']); - $fld_title = isset($prop['title']); - $fld_url = isset($prop['url']); - - if (is_null($resultPageSet)) { - $this->addFields(array ( - 'page_id', - 'page_namespace', - 'page_title' - )); - $this->addFieldsIf('el_to', $fld_url); - } else { - $this->addFields($resultPageSet->getPageTableFields()); - } - - $limit = $params['limit']; - $offset = $params['offset']; - $this->addOption('LIMIT', $limit +1); - if (isset ($offset)) - $this->addOption('OFFSET', $offset); - - $res = $this->select(__METHOD__); - - $data = array (); - $count = 0; - 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... - $this->setContinueEnumParameter('offset', $offset+$limit+1); - break; - } - - if (is_null($resultPageSet)) { - $vals = array(); - if ($fld_ids) - $vals['pageid'] = intval($row->page_id); - if ($fld_title) { - $title = Title :: makeTitle($row->page_namespace, $row->page_title); - $vals['ns'] = intval($title->getNamespace()); - $vals['title'] = $title->getPrefixedText(); - } - if ($fld_url) - $vals['url'] = $row->el_to; - $data[] = $vals; - } else { - $resultPageSet->processDbRow($row); - } - } - $db->freeResult($res); - - if (is_null($resultPageSet)) { - $result = $this->getResult(); - $result->setIndexedTagName($data, $this->getModulePrefix()); - $result->addValue('query', $this->getModuleName(), $data); - } - } - - protected function getAllowedParams() { - global $wgUrlProtocols; - $protocols = array(); - foreach ($wgUrlProtocols as $p) { - $protocols[] = substr($p, 0, strpos($p,':')); - } - - return array ( - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_DFLT => 'ids|title|url', - ApiBase :: PARAM_TYPE => array ( - 'ids', - 'title', - 'url' - ) - ), - 'offset' => array ( - ApiBase :: PARAM_TYPE => 'integer' - ), - 'protocol' => array ( - ApiBase :: PARAM_TYPE => $protocols, - ApiBase :: PARAM_DFLT => 'http', - ), - 'query' => null, - '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 - ) - ); - } - - protected function getParamDescription() { - return array ( - 'prop' => 'What pieces of information to include', - 'offset' => 'Used for paging. Use the value returned for "continue"', - 'protocol' => 'Protocol of the url', - 'query' => 'Search string without protocol. See [[Special:LinkSearch]]', - 'namespace' => 'The page namespace(s) to enumerate.', - 'limit' => 'How many entries to return.' - ); - } - - protected function getDescription() { - return 'Enumerate pages that contain a given URL'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=exturlusage&euquery=www.mediawiki.org' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryExternalLinks.php b/includes/api/ApiQueryExternalLinks.php deleted file mode 100644 index ad4634e14b..0000000000 --- a/includes/api/ApiQueryExternalLinks.php +++ /dev/null @@ -1,93 +0,0 @@ -@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 module to list all external URLs found on a given set of pages. - * - * @addtogroup API - */ -class ApiQueryExternalLinks extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'el'); - } - - public function execute() { - - $this->addFields(array ( - 'el_from', - 'el_to' - )); - - $this->addTables('externallinks'); - $this->addWhereFld('el_from', array_keys($this->getPageSet()->getGoodTitles())); - - $db = $this->getDB(); - $res = $this->select(__METHOD__); - - $data = array(); - $lastId = 0; // database has no ID 0 - while ($row = $db->fetchObject($res)) { - if ($lastId != $row->el_from) { - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - $data = array(); - } - $lastId = $row->el_from; - } - - $entry = array(); - ApiResult :: setContent($entry, $row->el_to); - $data[] = $entry; - } - - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - } - - $db->freeResult($res); - } - - protected function getDescription() { - return 'Returns all external urls (not interwikies) from the given page(s)'; - } - - protected function getExamples() { - return array ( - "Get a list of external links on the [[Main Page]]:", - " api.php?action=query&prop=extlinks&titles=Main%20Page", - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryImageInfo.php b/includes/api/ApiQueryImageInfo.php deleted file mode 100644 index 9d1026387c..0000000000 --- a/includes/api/ApiQueryImageInfo.php +++ /dev/null @@ -1,164 +0,0 @@ -@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 get image information and upload history. - * - * @addtogroup API - */ -class ApiQueryImageInfo extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'ii'); - } - - 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']); - $fld_metadata = isset($prop['metadata']); - - $pageIds = $this->getPageSet()->getAllTitlesByNamespace(); - if (!empty($pageIds[NS_IMAGE])) { - foreach ($pageIds[NS_IMAGE] as $dbKey => $pageId) { - - $title = Title :: makeTitle(NS_IMAGE, $dbKey); - $img = wfFindFile($title); - - $data = array(); - if ( !$img ) { - $repository = ''; - } 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); - - if ($fld_metadata) { - $metadata = unserialize($row["{$prefix}_metadata"]); - $vals['metadata'] = $metadata ? $metadata : null; - $this->getResult()->setIndexedTagName_recursive($vals['metadata'], 'meta'); - } - - $data[] = $vals; - - if (!$history) // Stop after the first line. - break; - - $isCur = false; - } - - $img->resetHistory(); - } - - $this->getResult()->addValue(array ('query', 'pages', intval($pageId)), - 'imagerepository', - $repository); - if (!empty($data)) - $this->addPageSubItems($pageId, $data); - } - } - } - - protected function getAllowedParams() { - return array ( - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_DFLT => 'timestamp|user', - ApiBase :: PARAM_TYPE => array ( - 'timestamp', - 'user', - 'comment', - 'url', - 'size', - 'sha1', - 'metadata' - ) - ), - 'history' => false, - ); - } - - protected function getParamDescription() { - return array ( - 'prop' => 'What image information to get.', - 'history' => 'Include upload history', - ); - } - - protected function getDescription() { - return array ( - 'Returns image information and upload history' - ); - } - - 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', - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryImages.php b/includes/api/ApiQueryImages.php deleted file mode 100644 index 10a5885834..0000000000 --- a/includes/api/ApiQueryImages.php +++ /dev/null @@ -1,118 +0,0 @@ -@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"); -} - -/** - * This query adds subelement to all pages with the list of images embedded into those pages. - * - * @addtogroup API - */ -class ApiQueryImages extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'im'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - if ($this->getPageSet()->getGoodTitleCount() == 0) - return; // nothing to do - - $this->addFields(array ( - 'il_from', - 'il_to' - )); - - $this->addTables('imagelinks'); - $this->addWhereFld('il_from', array_keys($this->getPageSet()->getGoodTitles())); - $this->addOption('ORDER BY', "il_from, il_to"); - - $db = $this->getDB(); - $res = $this->select(__METHOD__); - - if (is_null($resultPageSet)) { - - $data = array(); - $lastId = 0; // database has no ID 0 - while ($row = $db->fetchObject($res)) { - if ($lastId != $row->il_from) { - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - $data = array(); - } - $lastId = $row->il_from; - } - - $vals = array(); - ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle(NS_IMAGE, $row->il_to)); - $data[] = $vals; - } - - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - } - - } else { - - $titles = array(); - while ($row = $db->fetchObject($res)) { - $titles[] = Title :: makeTitle(NS_IMAGE, $row->il_to); - } - $resultPageSet->populateFromTitles($titles); - } - - $db->freeResult($res); - } - - protected function getDescription() { - return 'Returns all images contained on the given page(s)'; - } - - protected function getExamples() { - return array ( - "Get a list of images used in the [[Main Page]]:", - " api.php?action=query&prop=images&titles=Main%20Page", - "Get information about all images used in the [[Main Page]]:", - " api.php?action=query&generator=images&titles=Main%20Page&prop=info" - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php deleted file mode 100644 index 39a6c80ea4..0000000000 --- a/includes/api/ApiQueryInfo.php +++ /dev/null @@ -1,226 +0,0 @@ -@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 module to show basic page information. - * - * @addtogroup API - */ -class ApiQueryInfo extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'in'); - } - - public function requestExtraData($pageSet) { - $pageSet->requestField('page_restrictions'); - $pageSet->requestField('page_is_redirect'); - $pageSet->requestField('page_is_new'); - $pageSet->requestField('page_counter'); - $pageSet->requestField('page_touched'); - $pageSet->requestField('page_latest'); - $pageSet->requestField('page_len'); - } - - public function execute() { - - global $wgUser; - - $params = $this->extractRequestParams(); - $fld_protection = false; - if(!is_null($params['prop'])) { - $prop = array_flip($params['prop']); - $fld_protection = isset($prop['protection']); - } - if(!is_null($params['token'])) { - $token = $params['token']; - $tok_edit = $this->getTokenFlag($token, 'edit'); - $tok_delete = $this->getTokenFlag($token, 'delete'); - $tok_protect = $this->getTokenFlag($token, 'protect'); - $tok_move = $this->getTokenFlag($token, 'move'); - } - - $pageSet = $this->getPageSet(); - $titles = $pageSet->getGoodTitles(); - $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'); - $pageTouched = $pageSet->getCustomField('page_touched'); - $pageLatest = $pageSet->getCustomField('page_latest'); - $pageLength = $pageSet->getCustomField('page_len'); - - if ($fld_protection && count($titles) > 0) { - $this->addTables('page_restrictions'); - $this->addFields(array('pr_page', 'pr_type', 'pr_level', 'pr_expiry')); - $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 ) - ); - } - $db->freeResult($res); - } - - foreach ( $titles as $pageid => $title ) { - $pageInfo = array ( - 'touched' => wfTimestamp(TS_ISO_8601, $pageTouched[$pageid]), - 'lastrevid' => intval($pageLatest[$pageid]), - 'counter' => intval($pageCounter[$pageid]), - 'length' => intval($pageLength[$pageid]), - ); - - if ($pageIsRedir[$pageid]) - $pageInfo['redirect'] = ''; - - if ($pageIsNew[$pageid]) - $pageInfo['new'] = ''; - - if (!is_null($token)) { - // Currently all tokens are generated the same way, but it might change - if ($tok_edit) - $pageInfo['edittoken'] = $wgUser->editToken(); - if ($tok_delete) - $pageInfo['deletetoken'] = $wgUser->editToken(); - if ($tok_protect) - $pageInfo['protecttoken'] = $wgUser->editToken(); - if ($tok_move) - $pageInfo['movetoken'] = $wgUser->editToken(); - } - - if($fld_protection) { - if (isset($protections[$pageid])) { - $pageInfo['protection'] = $protections[$pageid]; - $result->setIndexedTagName($pageInfo['protection'], 'pr'); - } else { - # 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(); - } - } - } - - $result->addValue(array ( - 'query', - 'pages' - ), $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) - { - $missing = $pageSet->getMissingTitles(); - $res = &$result->getData(); - foreach($missing as $pageid => $title) - $res['query']['pages'][$pageid]['edittoken'] = $wgUser->editToken(); - } - } - - protected function getAllowedParams() { - return array ( - 'prop' => array ( - ApiBase :: PARAM_DFLT => NULL, - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'protection' - )), - 'token' => array ( - ApiBase :: PARAM_DFLT => NULL, - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'edit', - 'delete', - 'protect', - 'move', - )), - ); - } - - protected function getParamDescription() { - return array ( - 'prop' => array ( - 'Which additional properties to get:', - ' "protection" - List the protection level of each page' - ), - 'token' => 'Request a token to perform a data-modifying action on a page', - ); - } - - - protected function getDescription() { - return 'Get basic page information such as namespace, title, last touched date, ...'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&prop=info&titles=Main%20Page', - 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryLangLinks.php b/includes/api/ApiQueryLangLinks.php deleted file mode 100644 index 99457aee9c..0000000000 --- a/includes/api/ApiQueryLangLinks.php +++ /dev/null @@ -1,94 +0,0 @@ -@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 module to list all langlinks (links to correspanding foreign language pages). - * - * @addtogroup API - */ -class ApiQueryLangLinks extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'll'); - } - - public function execute() { - $this->addFields(array ( - 'll_from', - 'll_lang', - 'll_title' - )); - - $this->addTables('langlinks'); - $this->addWhereFld('ll_from', array_keys($this->getPageSet()->getGoodTitles())); - $this->addOption('ORDER BY', "ll_from, ll_lang"); - $res = $this->select(__METHOD__); - - $data = array(); - $lastId = 0; // database has no ID 0 - $db = $this->getDB(); - while ($row = $db->fetchObject($res)) { - - if ($lastId != $row->ll_from) { - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - $data = array(); - } - $lastId = $row->ll_from; - } - - $entry = array('lang'=>$row->ll_lang); - ApiResult :: setContent($entry, $row->ll_title); - $data[] = $entry; - } - - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - } - - $db->freeResult($res); - } - - protected function getDescription() { - return 'Returns all interlanguage links from the given page(s)'; - } - - protected function getExamples() { - return array ( - "Get interlanguage links from the [[Main Page]]:", - " api.php?action=query&prop=langlinks&titles=Main%20Page&redirects", - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryLinks.php b/includes/api/ApiQueryLinks.php deleted file mode 100644 index e3a402769b..0000000000 --- a/includes/api/ApiQueryLinks.php +++ /dev/null @@ -1,162 +0,0 @@ -@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 module to list all wiki links on a given set of pages. - * - * @addtogroup API - */ -class ApiQueryLinks extends ApiQueryGeneratorBase { - - const LINKS = 'links'; - const TEMPLATES = 'templates'; - - private $table, $prefix, $description; - - public function __construct($query, $moduleName) { - - switch ($moduleName) { - case self::LINKS : - $this->table = 'pagelinks'; - $this->prefix = 'pl'; - $this->description = 'link'; - break; - case self::TEMPLATES : - $this->table = 'templatelinks'; - $this->prefix = 'tl'; - $this->description = 'template'; - break; - default : - ApiBase :: dieDebug(__METHOD__, 'Unknown module name'); - } - - parent :: __construct($query, $moduleName, $this->prefix); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - if ($this->getPageSet()->getGoodTitleCount() == 0) - return; // nothing to do - - $params = $this->extractRequestParams(); - - $this->addFields(array ( - $this->prefix . '_from pl_from', - $this->prefix . '_namespace pl_namespace', - $this->prefix . '_title pl_title' - )); - - $this->addTables($this->table); - $this->addWhereFld($this->prefix . '_from', array_keys($this->getPageSet()->getGoodTitles())); - $this->addWhereFld($this->prefix . '_namespace', $params['namespace']); - $this->addOption('ORDER BY', str_replace('pl_', $this->prefix . '_', 'pl_from, pl_namespace, pl_title')); - - $db = $this->getDB(); - $res = $this->select(__METHOD__); - - if (is_null($resultPageSet)) { - - $data = array(); - $lastId = 0; // database has no ID 0 - while ($row = $db->fetchObject($res)) { - if ($lastId != $row->pl_from) { - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - $data = array(); - } - $lastId = $row->pl_from; - } - - $vals = array(); - ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle($row->pl_namespace, $row->pl_title)); - $data[] = $vals; - } - - if($lastId != 0) { - $this->addPageSubItems($lastId, $data); - } - - } else { - - $titles = array(); - while ($row = $db->fetchObject($res)) { - $titles[] = Title :: makeTitle($row->pl_namespace, $row->pl_title); - } - $resultPageSet->populateFromTitles($titles); - } - - $db->freeResult($res); - } - - protected function getAllowedParams() - { - return array( - 'namespace' => array( - ApiBase :: PARAM_TYPE => 'namespace', - ApiBase :: PARAM_ISMULTI => true - ) - ); - } - - protected function getParamDescription() - { - return array( - 'namespace' => "Show {$this->description}s in this namespace(s) only" - ); - } - - protected function getDescription() { - return "Returns all {$this->description}s from the given page(s)"; - } - - protected function getExamples() { - return array ( - "Get {$this->description}s from the [[Main Page]]:", - " api.php?action=query&prop={$this->getModuleName()}&titles=Main%20Page", - "Get information about the {$this->description} pages in the [[Main Page]]:", - " api.php?action=query&generator={$this->getModuleName()}&titles=Main%20Page&prop=info", - "Get {$this->description}s from the Main Page in the User and Template namespaces:", - " api.php?action=query&prop={$this->getModuleName()}&titles=Main%20Page&{$this->prefix}namespace=2|10" - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php deleted file mode 100644 index 87eaeb2249..0000000000 --- a/includes/api/ApiQueryLogEvents.php +++ /dev/null @@ -1,272 +0,0 @@ -@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'); -} - -/** - * Query action to List the log events, with optional filtering by various parameters. - * - * @addtogroup API - */ -class ApiQueryLogEvents extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'le'); - } - - public function execute() { - $params = $this->extractRequestParams(); - $db = $this->getDB(); - - $prop = $params['prop']; - $this->fld_ids = in_array('ids', $prop); - $this->fld_title = in_array('title', $prop); - $this->fld_type = in_array('type', $prop); - $this->fld_user = in_array('user', $prop); - $this->fld_timestamp = in_array('timestamp', $prop); - $this->fld_comment = in_array('comment', $prop); - $this->fld_details = in_array('details', $prop); - - list($tbl_logging, $tbl_page, $tbl_user) = $db->tableNamesN('logging', 'page', 'user'); - - $this->addOption('STRAIGHT_JOIN'); - $this->addTables("$tbl_logging LEFT OUTER JOIN $tbl_page ON " . - "log_namespace=page_namespace AND log_title=page_title " . - "INNER JOIN $tbl_user ON user_id=log_user"); - - $this->addFields(array ( - 'log_type', - 'log_action', - 'log_timestamp', - )); - - // FIXME: Fake out log_id for now until the column is live on Wikimedia - // $this->addFieldsIf('log_id', $this->fld_ids); - $this->addFieldsIf('page_id', $this->fld_ids); - $this->addFieldsIf('log_user', $this->fld_user); - $this->addFieldsIf('user_name', $this->fld_user); - $this->addFieldsIf('log_namespace', $this->fld_title); - $this->addFieldsIf('log_title', $this->fld_title); - $this->addFieldsIf('log_comment', $this->fld_comment); - $this->addFieldsIf('log_params', $this->fld_details); - - - $this->addWhereFld('log_deleted', 0); - $this->addWhereFld('log_type', $params['type']); - $this->addWhereRange('log_timestamp', $params['dir'], $params['start'], $params['end']); - - $limit = $params['limit']; - $this->addOption('LIMIT', $limit +1); - - $user = $params['user']; - if (!is_null($user)) { - $userid = $db->selectField('user', 'user_id', array ( - 'user_name' => $user - )); - if (!$userid) - $this->dieUsage("User name $user not found", 'param_user'); - $this->addWhereFld('log_user', $userid); - } - - $title = $params['title']; - if (!is_null($title)) { - $titleObj = Title :: newFromText($title); - if (is_null($titleObj)) - $this->dieUsage("Bad title value '$title'", 'param_title'); - $this->addWhereFld('log_namespace', $titleObj->getNamespace()); - $this->addWhereFld('log_title', $titleObj->getDBkey()); - } - - $data = array (); - $count = 0; - $res = $this->select(__METHOD__); - 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... - $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->log_timestamp)); - break; - } - - $vals = $this->extractRowInfo($row); - if($vals) - $data[] = $vals; - } - $db->freeResult($res); - - $this->getResult()->setIndexedTagName($data, 'item'); - $this->getResult()->addValue('query', $this->getModuleName(), $data); - } - - private function extractRowInfo($row) { - $vals = array(); - - if ($this->fld_ids) { - // FIXME: Fake out log_id for now until the column is live on Wikimedia - // $vals['logid'] = intval($row->log_id); - $vals['logid'] = 0; - $vals['pageid'] = intval($row->page_id); - } - - if ($this->fld_title) { - $title = Title :: makeTitle($row->log_namespace, $row->log_title); - ApiQueryBase :: addTitleInfo($vals, $title); - } - - if ($this->fld_type) { - $vals['type'] = $row->log_type; - $vals['action'] = $row->log_action; - } - - if ($this->fld_details && $row->log_params !== '') { - $params = explode("\n", $row->log_params); - switch ($row->log_type) { - case 'move': - if (isset ($params[0])) { - $title = Title :: newFromText($params[0]); - if ($title) { - $vals2 = array(); - ApiQueryBase :: addTitleInfo($vals2, $title, "new_"); - $vals[$row->log_type] = $vals2; - $params = null; - } - } - break; - case 'patrol': - $vals2 = array(); - list( $vals2['cur'], $vals2['prev'], $vals2['auto'] ) = $params; - $vals[$row->log_type] = $vals2; - $params = null; - break; - case 'rights': - $vals2 = array(); - list( $vals2['old'], $vals2['new'] ) = $params; - $vals[$row->log_type] = $vals2; - $params = null; - break; - case 'block': - $vals2 = array(); - list( $vals2['duration'], $vals2['flags'] ) = $params; - $vals[$row->log_type] = $vals2; - $params = null; - break; - } - - if (isset($params)) { - $this->getResult()->setIndexedTagName($params, 'param'); - $vals = array_merge($vals, $params); - } - } - - if ($this->fld_user) { - $vals['user'] = $row->user_name; - if(!$row->log_user) - $vals['anon'] = ''; - } - if ($this->fld_timestamp) { - $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->log_timestamp); - } - if ($this->fld_comment && !empty ($row->log_comment)) { - $vals['comment'] = $row->log_comment; - } - - return $vals; - } - - - protected function getAllowedParams() { - global $wgLogTypes; - return array ( - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_DFLT => 'ids|title|type|user|timestamp|comment|details', - ApiBase :: PARAM_TYPE => array ( - 'ids', - 'title', - 'type', - 'user', - 'timestamp', - 'comment', - 'details', - ) - ), - 'type' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => $wgLogTypes - ), - 'start' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'end' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'dir' => array ( - ApiBase :: PARAM_DFLT => 'older', - ApiBase :: PARAM_TYPE => array ( - 'newer', - 'older' - ) - ), - 'user' => null, - 'title' => null, - 'limit' => array ( - ApiBase :: PARAM_DFLT => 10, - ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, - ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 - ) - ); - } - - protected function getParamDescription() { - return array ( - 'type' => 'Filter log entries to only this type(s)', - 'start' => 'The timestamp to start enumerating from.', - 'end' => 'The timestamp to end enumerating.', - 'dir' => 'In which direction to enumerate.', - 'user' => 'Filter entries to those made by the given user.', - 'title' => 'Filter entries to those related to a page.', - 'limit' => 'How many total event entries to return.' - ); - } - - protected function getDescription() { - return 'Get events from logs.'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=logevents' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php deleted file mode 100644 index a80b6c7718..0000000000 --- a/includes/api/ApiQueryRecentChanges.php +++ /dev/null @@ -1,354 +0,0 @@ -@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 enumerate the recent changes that were done to the wiki. - * Various filters are supported. - * - * @addtogroup API - */ -class ApiQueryRecentChanges extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'rc'); - } - - private $fld_comment = false, $fld_user = false, $fld_flags = false, - $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() { - /* 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); - - /* 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'])); - } - - /* Add the fields we're concerned with to out query. */ - $this->addFields(array ( - 'rc_timestamp', - 'rc_namespace', - 'rc_title', - 'rc_type', - 'rc_moved_to_ns', - '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']); - $this->fld_timestamp = isset ($prop['timestamp']); - $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); - $this->addFieldsIf('rc_last_oldid', $this->fld_ids); - $this->addFieldsIf('rc_comment', $this->fld_comment); - $this->addFieldsIf('rc_user', $this->fld_user); - $this->addFieldsIf('rc_user_text', $this->fld_user); - $this->addFieldsIf('rc_minor', $this->fld_flags); - $this->addFieldsIf('rc_bot', $this->fld_flags); - $this->addFieldsIf('rc_new', $this->fld_flags); - $this->addFieldsIf('rc_old_len', $this->fld_sizes); - $this->addFieldsIf('rc_new_len', $this->fld_sizes); - } - - /* 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... - $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp)); - 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 (); - - $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); - $vals['revid'] = intval($row->rc_this_oldid); - $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'] = ''; - if ($row->rc_new) - $vals['new'] = ''; - if ($row->rc_minor) - $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() { - return array ( - 'start' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'end' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'dir' => array ( - ApiBase :: PARAM_DFLT => 'older', - ApiBase :: PARAM_TYPE => array ( - 'newer', - 'older' - ) - ), - 'namespace' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => 'namespace' - ), - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_DFLT => 'title|timestamp|ids', - ApiBase :: PARAM_TYPE => array ( - 'user', - 'comment', - 'flags', - 'timestamp', - 'title', - 'ids', - 'sizes' - ) - ), - 'show' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'minor', - '!minor', - 'bot', - '!bot', - 'anon', - '!anon' - ) - ), - '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 - ), - 'type' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'edit', - 'new', - 'log' - ) - ) - ); - } - - protected function getParamDescription() { - return array ( - 'start' => 'The timestamp to start enumerating from.', - 'end' => 'The timestamp to end enumerating.', - 'dir' => 'In which direction to enumerate.', - 'namespace' => 'Filter log entries to only this namespace(s)', - 'prop' => 'Include additional pieces of information', - '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' - ), - 'type' => 'Which types of changes to show.', - 'limit' => 'How many total pages to return.' - ); - } - - protected function getDescription() { - return 'Enumerate recent changes'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=recentchanges' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php deleted file mode 100644 index d5a108d4c8..0000000000 --- a/includes/api/ApiQueryRevisions.php +++ /dev/null @@ -1,383 +0,0 @@ -@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 enumerate revisions of a given page, or show top revisions of multiple pages. - * Various pieces of information may be shown - flags, comments, and the actual wiki markup of the rev. - * In the enumeration mode, ranges of revisions may be requested and filtered. - * - * @addtogroup API - */ -class ApiQueryRevisions extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'rv'); - } - - private $fld_ids = false, $fld_flags = false, $fld_timestamp = false, $fld_size = false, - $fld_comment = false, $fld_user = false, $fld_content = false; - - public function execute() { - $limit = $startid = $endid = $start = $end = $dir = $prop = $user = $excludeuser = $token = null; - extract($this->extractRequestParams()); - - // 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 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(); - $revCount = $pageSet->getRevisionCount(); - - // Optimization -- nothing to do - if ($revCount === 0 && $pageCount === 0) - return; - - if ($revCount > 0 && $enumRevMode) - $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->addTables('revision'); - $this->addWhere('rev_deleted=0'); - - $prop = array_flip($prop); - - // These field are needed regardless of the client requesting them - $this->addFields('rev_id'); - $this->addFields('rev_page'); - - // Optional fields - $this->fld_ids = isset ($prop['ids']); - // $this->addFieldsIf('rev_text_id', $this->fld_ids); // should this be exposed? - $this->fld_flags = $this->addFieldsIf('rev_minor_edit', isset ($prop['flags'])); - $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'])); - 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 - foreach ($pageSet->getGoodTitles() as $title) { - if( !$title->userCanRead() ) - $this->dieUsage( - 'The current user is not allowed to read ' . $title->getPrefixedText(), - 'accessdenied'); - } - - $this->addTables('text'); - $this->addWhere('rev_text_id=old_id'); - $this->addFields('old_id'); - $this->addFields('old_text'); - $this->addFields('old_flags'); - - $this->fld_content = true; - - $this->expandTemplates = $expandtemplates; - } - - $userMax = ( $this->fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1 ); - $botMax = ( $this->fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2 ); - - if ($enumRevMode) { - - // 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'); - - if (!is_null($endid) && !is_null($end)) - $this->dieUsage('end and endid cannot be used together', 'badparams'); - - if(!is_null($user) && !is_null( $excludeuser)) - $this->dieUsage('user and excludeuser cannot be used together', 'badparams'); - - // This code makes an assumption that sorting by rev_id and rev_timestamp produces - // the same result. This way users may request revisions starting at a given time, - // but to page through results use the rev_id returned after each page. - // Switching to rev_id removes the potential problem of having more than - // 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) && is_null($endid)) - $this->addWhereRange('rev_timestamp', $dir, $start, $end); - else - $this->addWhereRange('rev_id', $dir, $startid, $endid); - - // must manually initialize unset limit - if (is_null($limit)) - $limit = 10; - $this->validateLimit('limit', $limit, 1, $userMax, $botMax); - - // There is only one ID, use it - $this->addWhereFld('rev_page', current(array_keys($pageSet->getGoodTitles()))); - - if(!is_null($user)) { - $this->addWhereFld('rev_user_text', $user); - } elseif (!is_null( $excludeuser)) { - $this->addWhere('rev_user_text != ' . $this->getDB()->addQuotes($excludeuser)); - } - } - elseif ($revCount > 0) { - $this->validateLimit('rev_count', $revCount, 1, $userMax, $botMax); - - // Get all revision IDs - $this->addWhereFld('rev_id', array_keys($pageSet->getRevisionIDs())); - - // assumption testing -- we should never get more then $revCount rows. - $limit = $revCount; - } - elseif ($pageCount > 0) { - // When working in multi-page non-enumeration mode, - // limit to the latest revision only - $this->addTables('page'); - $this->addWhere('page_id=rev_page'); - $this->addWhere('page_latest=rev_id'); - $this->validateLimit('page_count', $pageCount, 1, $userMax, $botMax); - - // Get all page IDs - $this->addWhereFld('page_id', array_keys($pageSet->getGoodTitles())); - - // assumption testing -- we should never get more then $pageCount rows. - $limit = $pageCount; - } else - ApiBase :: dieDebug(__METHOD__, 'param validation?'); - - $this->addOption('LIMIT', $limit +1); - - $data = array (); - $count = 0; - $res = $this->select(__METHOD__); - - $db = $this->getDB(); - 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... - if (!$enumRevMode) - ApiBase :: dieDebug(__METHOD__, 'Got more rows then expected'); // bug report - $this->setContinueEnumParameter('startid', intval($row->rev_id)); - break; - } - - $this->getResult()->addValue( - array ( - 'query', - 'pages', - intval($row->rev_page), - 'revisions'), - null, - $this->extractRowInfo($row)); - } - $db->freeResult($res); - - // Ensure that all revisions are shown as '' elements - $result = $this->getResult(); - if ($result->getIsRawMode()) { - $data =& $result->getData(); - foreach ($data['query']['pages'] as & $page) { - if (is_array($page) && array_key_exists('revisions', $page)) { - $result->setIndexedTagName($page['revisions'], 'rev'); - } - } - } - } - - private function extractRowInfo($row) { - - $vals = array (); - - if ($this->fld_ids) { - $vals['revid'] = intval($row->rev_id); - // $vals['oldid'] = intval($row->rev_text_id); // todo: should this be exposed? - } - - if ($this->fld_flags && $row->rev_minor_edit) - $vals['minor'] = ''; - - if ($this->fld_user) { - $vals['user'] = $row->rev_user_text; - if (!$row->rev_user) - $vals['anon'] = ''; - } - - if ($this->fld_timestamp) { - $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rev_timestamp); - } - - if ($this->fld_size && !is_null($row->rev_len)) { - $vals['size'] = intval($row->rev_len); - } - - if ($this->fld_comment && !empty ($row->rev_comment)) { - $vals['comment'] = $row->rev_comment; - } - - 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() { - return array ( - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_DFLT => 'ids|timestamp|flags|comment|user', - ApiBase :: PARAM_TYPE => array ( - 'ids', - 'flags', - 'timestamp', - 'user', - 'size', - 'comment', - 'content', - ) - ), - 'limit' => array ( - ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, - ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 - ), - 'startid' => array ( - ApiBase :: PARAM_TYPE => 'integer' - ), - 'endid' => array ( - ApiBase :: PARAM_TYPE => 'integer' - ), - 'start' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'end' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'dir' => array ( - ApiBase :: PARAM_DFLT => 'older', - ApiBase :: PARAM_TYPE => array ( - 'newer', - 'older' - ) - ), - 'user' => array( - ApiBase :: PARAM_TYPE => 'user' - ), - 'excludeuser' => array( - ApiBase :: PARAM_TYPE => 'user' - ), - - 'expandtemplates' => false, - 'token' => array( - ApiBase :: PARAM_TYPE => array( - 'rollback' - ), - ApiBase :: PARAM_ISMULTI => true - ), - ); - } - - protected function getParamDescription() { - return array ( - 'prop' => 'Which properties to get for each revision.', - 'limit' => 'limit how many revisions will be returned (enum)', - 'startid' => 'from which revision id to start enumeration (enum)', - 'endid' => 'stop revision enumeration on this revid (enum)', - 'start' => 'from which revision timestamp to start enumeration (enum)', - 'end' => 'enumerate up to this timestamp (enum)', - 'dir' => 'direction of enumeration - towards "newer" or "older" revisions (enum)', - 'user' => 'only include revisions made by user', - 'excludeuser' => 'exclude revisions made by user', - 'expandtemplates' => 'expand templates in revision content', - 'token' => 'Which tokens to obtain for each revision', - ); - } - - protected function getDescription() { - return array ( - 'Get revision information.', - 'This module may be used in several ways:', - ' 1) Get data about a set of pages (last revision), by setting titles or pageids parameter.', - ' 2) Get revisions for one given page, by using titles/pageids with start/end/limit params.', - ' 3) Get data about a set of revisions by setting their IDs with revids parameter.', - 'All parameters marked as (enum) may only be used with a single page (#2).' - ); - } - - protected function getExamples() { - return array ( - 'Get data with content for the last revision of titles "API" and "Main Page":', - ' api.php?action=query&prop=revisions&titles=API|Main%20Page&rvprop=timestamp|user|comment|content', - 'Get last 5 revisions of the "Main Page":', - ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment', - 'Get first 5 revisions of the "Main Page":', - ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer', - 'Get first 5 revisions of the "Main Page" made after 2006-05-01:', - ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer&rvstart=20060501000000', - 'Get first 5 revisions of the "Main Page" that were not made made by anonymous user "127.0.0.1"', - ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvexcludeuser=127.0.0.1', - 'Get first 5 revisions of the "Main Page" that were made by the user "MediaWiki default"', - ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvuser=MediaWiki%20default', - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQuerySearch.php b/includes/api/ApiQuerySearch.php deleted file mode 100644 index 0352a55d18..0000000000 --- a/includes/api/ApiQuerySearch.php +++ /dev/null @@ -1,151 +0,0 @@ -@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'); -} - -/** - * Query module to perform full text search within wiki titles and content - * - * @addtogroup API - */ -class ApiQuerySearch extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'sr'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private function run($resultPageSet = null) { - - $params = $this->extractRequestParams(); - - $limit = $params['limit']; - $query = $params['search']; - if (is_null($query) || empty($query)) - $this->dieUsage("empty search string is not allowed", 'param-search'); - - $search = SearchEngine::create(); - $search->setLimitOffset( $limit+1, $params['offset'] ); - $search->setNamespaces( $params['namespace'] ); - $search->showRedirects = $params['redirects']; - - if ($params['what'] == 'text') - $matches = $search->searchText( $query ); - else - $matches = $search->searchTitle( $query ); - - $data = array (); - $count = 0; - while( $result = $matches->next() ) { - if (++ $count > $limit) { - // We've reached the one extra which shows that there are additional items to be had. Stop here... - $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); - break; - } - - $title = $result->getTitle(); - if (is_null($resultPageSet)) { - $data[] = array( - 'ns' => intval($title->getNamespace()), - 'title' => $title->getPrefixedText()); - } else { - $data[] = $title; - } - } - - if (is_null($resultPageSet)) { - $result = $this->getResult(); - $result->setIndexedTagName($data, 'p'); - $result->addValue('query', $this->getModuleName(), $data); - } else { - $resultPageSet->populateFromTitles($data); - } - } - - protected function getAllowedParams() { - return array ( - 'search' => null, - 'namespace' => array ( - ApiBase :: PARAM_DFLT => 0, - ApiBase :: PARAM_TYPE => 'namespace', - ApiBase :: PARAM_ISMULTI => true, - ), - 'what' => array ( - ApiBase :: PARAM_DFLT => 'title', - ApiBase :: PARAM_TYPE => array ( - 'title', - 'text', - ) - ), - 'redirects' => false, - 'offset' => 0, - 'limit' => array ( - ApiBase :: PARAM_DFLT => 10, - ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, - ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 - ) - ); - } - - protected function getParamDescription() { - return array ( - 'search' => 'Search for all page titles (or content) that has this value.', - 'namespace' => 'The namespace(s) to enumerate.', - 'what' => 'Search inside the text or titles.', - 'redirects' => 'Include redirect pages in the search.', - 'offset' => 'Use this value to continue paging (return by query)', - 'limit' => 'How many total pages to return.' - ); - } - - protected function getDescription() { - return 'Perform a full text search'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=search&srsearch=meaning', - 'api.php?action=query&list=search&srwhat=text&srsearch=meaning', - 'api.php?action=query&generator=search&gsrsearch=meaning&prop=info', - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php deleted file mode 100644 index 1bd34cd453..0000000000 --- a/includes/api/ApiQuerySiteinfo.php +++ /dev/null @@ -1,238 +0,0 @@ -@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 meta information about the wiki site. - * - * @addtogroup API - */ -class ApiQuerySiteinfo extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'si'); - } - - public function execute() { - - $params = $this->extractRequestParams(); - - foreach ($params['prop'] as $p) { - switch ($p) { - default : - ApiBase :: dieDebug(__METHOD__, "Unknown prop=$p"); - case 'general' : - $this->appendGeneralInfo($p); - break; - case 'namespaces' : - $this->appendNamespaces($p); - break; - case 'interwikimap' : - $filteriw = isset($params['filteriw']) ? $params['filteriw'] : false; - $this->appendInterwikiMap($p, $filteriw); - break; - case 'dbrepllag' : - $this->appendDbReplLagInfo($p, $params['showalldb']); - break; - case 'statistics' : - $this->appendStatistics($p); - break; - } - } - } - - protected function appendGeneralInfo($property) { - global $wgSitename, $wgVersion, $wgCapitalLinks, $wgRightsCode, $wgRightsText, $wgLanguageCode, $IP; - - $data = array (); - $mainPage = Title :: newFromText(wfMsgForContent('mainpage')); - $data['mainpage'] = $mainPage->getText(); - $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; - $data['rights'] = $wgRightsText; - $data['lang'] = $wgLanguageCode; - - $this->getResult()->addValue('query', $property, $data); - } - - protected function appendNamespaces($property) { - global $wgContLang; - - $data = array (); - foreach ($wgContLang->getFormattedNamespaces() as $ns => $title) { - $data[$ns] = array ( - 'id' => $ns - ); - ApiResult :: setContent($data[$ns], $title); - } - - $this->getResult()->setIndexedTagName($data, 'ns'); - $this->getResult()->addValue('query', $property, $data); - } - - protected function appendInterwikiMap($property, $filter) { - - $this->resetQueryParams(); - $this->addTables('interwiki'); - $this->addFields(array('iw_prefix', 'iw_local', 'iw_url')); - - if($filter === 'local') { - $this->addWhere('iw_local = 1'); - } elseif($filter === '!local') { - $this->addWhere('iw_local = 0'); - } elseif($filter !== false) { - ApiBase :: dieDebug(__METHOD__, "Unknown filter=$filter"); - } - - $this->addOption('ORDER BY', 'iw_prefix'); - - $db = $this->getDB(); - $res = $this->select(__METHOD__); - - $data = array(); - while($row = $db->fetchObject($res)) - { - $val['prefix'] = $row->iw_prefix; - if ($row->iw_local == '1') - $val['local'] = ''; -// $val['trans'] = intval($row->iw_trans); // should this be exposed? - $val['url'] = $row->iw_url; - - $data[] = $val; - } - $db->freeResult($res); - - $this->getResult()->setIndexedTagName($data, 'iw'); - $this->getResult()->addValue('query', $property, $data); - } - - protected function appendDbReplLagInfo($property, $includeAll) { - global $wgLoadBalancer, $wgShowHostnames; - - $data = array(); - - if ($includeAll) { - if (!$wgShowHostnames) - $this->dieUsage('Cannot view all servers info unless $wgShowHostnames is true', 'includeAllDenied'); - - global $wgDBservers; - $lags = $wgLoadBalancer->getLagTimes(); - foreach( $lags as $i => $lag ) { - $data[] = array ( - 'host' => $wgDBservers[$i]['host'], - 'lag' => $lag); - } - } else { - list( $host, $lag ) = $wgLoadBalancer->getMaxLag(); - $data[] = array ( - 'host' => $wgShowHostnames ? $host : '', - 'lag' => $lag); - } - - $result = $this->getResult(); - $result->setIndexedTagName($data, 'db'); - $result->addValue('query', $property, $data); - } - - protected function appendStatistics($property) { - $data = array (); - $data['pages'] = intval(SiteStats::pages()); - $data['articles'] = intval(SiteStats::articles()); - $data['views'] = intval(SiteStats::views()); - $data['edits'] = intval(SiteStats::edits()); - $data['images'] = intval(SiteStats::images()); - $data['users'] = intval(SiteStats::users()); - $data['admins'] = intval(SiteStats::admins()); - $data['jobs'] = intval(SiteStats::jobs()); - $this->getResult()->addValue('query', $property, $data); - } - - protected function getAllowedParams() { - return array ( - - 'prop' => array ( - ApiBase :: PARAM_DFLT => 'general', - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'general', - 'namespaces', - 'interwikimap', - 'dbrepllag', - 'statistics', - )), - - 'filteriw' => array ( - ApiBase :: PARAM_TYPE => array ( - 'local', - '!local', - )), - - 'showalldb' => false, - ); - } - - protected function getParamDescription() { - return array ( - 'prop' => array ( - 'Which sysinfo properties to get:', - ' "general" - Overall system information', - ' "namespaces" - List of registered namespaces (localized)', - ' "statistics" - Returns site statistics', - ' "interwikimap" - Returns interwiki map (optionally filtered)', - ' "dbrepllag" - Returns database server with the highest replication lag', - ), - 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map', - 'showalldb' => 'List all database servers, not just the one lagging the most', - ); - } - - protected 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=interwikimap&sifilteriw=local', - 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb', - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php deleted file mode 100644 index 6c3d356c8c..0000000000 --- a/includes/api/ApiQueryUserContributions.php +++ /dev/null @@ -1,276 +0,0 @@ -@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'); -} - -/** - * This query action adds a list of a specified user's contributions to the output. - * - * @addtogroup API - */ -class ApiQueryContributions extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'uc'); - } - - private $params, $username; - private $fld_ids = false, $fld_title = false, $fld_timestamp = false, - $fld_comment = false, $fld_flags = false; - - public function execute() { - - // Parse some parameters - $this->params = $this->extractRequestParams(); - - $prop = array_flip($this->params['prop']); - $this->fld_ids = isset($prop['ids']); - $this->fld_title = isset($prop['title']); - $this->fld_comment = isset($prop['comment']); - $this->fld_flags = isset($prop['flags']); - $this->fld_timestamp = isset($prop['timestamp']); - - // TODO: if the query is going only against the revision table, should this be done? - $this->selectNamedDB('contributions', DB_SLAVE, 'contributions'); - $db = $this->getDB(); - - // Prepare query - $this->prepareUsername(); - $this->prepareQuery(); - - //Do the actual query. - $res = $this->select( __METHOD__ ); - - //Initialise some variables - $data = array (); - $count = 0; - $limit = $this->params['limit']; - - //Fetch each row - 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... - $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rev_timestamp)); - break; - } - - $vals = $this->extractRowInfo($row); - if ($vals) - $data[] = $vals; - } - - //Free the database record so the connection can get on with other stuff - $db->freeResult($res); - - //And send the whole shebang out as output. - $this->getResult()->setIndexedTagName($data, 'item'); - $this->getResult()->addValue('query', $this->getModuleName(), $data); - } - - /** - * Validate the 'user' parameter and set the value to compare - * against `revision`.`rev_user_text` - */ - private function prepareUsername() { - $user = $this->params['user']; - if( $user ) { - $name = User::isIP( $user ) - ? $user - : User::getCanonicalName( $user, 'valid' ); - if( $name === false ) { - $this->dieUsage( "User name {$user} is not valid", 'param_user' ); - } else { - $this->username = $name; - } - } else { - $this->dieUsage( 'User parameter may not be empty', 'param_user' ); - } - } - - /** - * Prepares the query and returns the limit of rows requested - */ - private function prepareQuery() { - - //We're after the revision table, and the corresponding page row for - //anything we retrieve. - list ($tbl_page, $tbl_revision) = $this->getDB()->tableNamesN('page', 'revision'); - $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 ); - - // ... 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']; - if (!is_null($show)) { - $show = array_flip($show); - if (isset ($show['minor']) && isset ($show['!minor'])) - $this->dieUsage("Incorrect parameter - mutually exclusive values may not be supplied", 'show'); - - $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 - $this->addFields(array( - 'rev_timestamp', - 'page_namespace', - 'page_title', - )); - - $this->addFieldsIf('rev_page', $this->fld_ids); - $this->addFieldsIf('rev_id', $this->fld_ids); - // $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); - } - - /** - * Extract fields from the database row and append them to a result array - */ - private function extractRowInfo($row) { - - $vals = array(); - - if ($this->fld_ids) { - $vals['pageid'] = intval($row->rev_page); - $vals['revid'] = intval($row->rev_id); - // $vals['textid'] = intval($row->rev_text_id); // todo: Should this field be exposed? - } - - if ($this->fld_title) - ApiQueryBase :: addTitleInfo($vals, - Title :: makeTitle($row->page_namespace, $row->page_title)); - - if ($this->fld_timestamp) - $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rev_timestamp); - - if ($this->fld_flags) { - if ($row->page_is_new) - $vals['new'] = ''; - if ($row->rev_minor_edit) - $vals['minor'] = ''; - } - - if ($this->fld_comment && !empty ($row->rev_comment)) - $vals['comment'] = $row->rev_comment; - - return $vals; - } - - protected function getAllowedParams() { - return array ( - '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 - ), - 'start' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'end' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'user' => array ( - ApiBase :: PARAM_TYPE => 'user' - ), - 'dir' => array ( - ApiBase :: PARAM_DFLT => 'older', - ApiBase :: PARAM_TYPE => array ( - 'newer', - 'older' - ) - ), - 'namespace' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => 'namespace' - ), - 'prop' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_DFLT => 'ids|title|timestamp|flags|comment', - ApiBase :: PARAM_TYPE => array ( - 'ids', - 'title', - 'timestamp', - 'comment', - 'flags' - ) - ), - 'show' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'minor', - '!minor', - ) - ), - ); - } - - protected function getParamDescription() { - return array ( - 'limit' => 'The maximum number of contributions to return.', - 'start' => 'The start timestamp to return from.', - 'end' => 'The end timestamp to return to.', - 'user' => 'The user to retrieve contributions for.', - 'dir' => 'The direction to search (older or newer).', - 'namespace' => 'Only list contributions in these namespaces', - 'prop' => 'Include additional pieces of information', - 'show' => 'Show only items that meet this criteria, e.g. non minor edits only: show=!minor', - ); - } - - protected function getDescription() { - return 'Get all edits by a user'; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=usercontribs&ucuser=YurikBot' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php deleted file mode 100644 index b653c47411..0000000000 --- a/includes/api/ApiQueryUserInfo.php +++ /dev/null @@ -1,125 +0,0 @@ -@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'); -} - -/** - * Query module to get information about the currently logged-in user - * - * @addtogroup API - */ -class ApiQueryUserInfo extends ApiQueryBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'ui'); - } - - public function execute() { - - global $wgUser; - - $params = $this->extractRequestParams(); - $result = $this->getResult(); - - $vals = array(); - $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 (isset($prop['options'])) { - $vals['options'] = (is_null($wgUser->mOptions) ? User::getDefaultOptions() : $wgUser->mOptions); - } - } - - $result->addValue(null, $this->getModuleName(), $vals); - } - - protected function getAllowedParams() { - return array ( - 'prop' => array ( - ApiBase :: PARAM_DFLT => NULL, - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => array ( - 'blockinfo', - 'hasmsg', - 'groups', - 'rights', - 'options' - )) - ); - } - - protected 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', - ' options - lists all preferences the current user has set' - ) - ); - } - - protected function getDescription() { - return 'Get information about the current user'; - } - - protected function getExamples() { - 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$'; - } -} - diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php deleted file mode 100644 index e5f2d03e73..0000000000 --- a/includes/api/ApiQueryWatchlist.php +++ /dev/null @@ -1,299 +0,0 @@ -@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'); -} - -/** - * This query action allows clients to retrieve a list of recently modified pages - * that are part of the logged-in user's watchlist. - * - * @addtogroup API - */ -class ApiQueryWatchlist extends ApiQueryGeneratorBase { - - public function __construct($query, $moduleName) { - parent :: __construct($query, $moduleName, 'wl'); - } - - public function execute() { - $this->run(); - } - - public function executeGenerator($resultPageSet) { - $this->run($resultPageSet); - } - - private $fld_ids = false, $fld_title = false, $fld_patrol = false, $fld_flags = false, - $fld_timestamp = false, $fld_user = false, $fld_comment = false, $fld_sizes = false; - - private function run($resultPageSet = null) { - global $wgUser, $wgDBtype; - - $this->selectNamedDB('watchlist', DB_SLAVE, 'watchlist'); - - if (!$wgUser->isLoggedIn()) - $this->dieUsage('You must be logged-in to have a watchlist', 'notloggedin'); - - $allrev = $start = $end = $namespace = $dir = $limit = $prop = null; - extract($this->extractRequestParams()); - - if (!is_null($prop) && is_null($resultPageSet)) { - - $prop = array_flip($prop); - - $this->fld_ids = isset($prop['ids']); - $this->fld_title = isset($prop['title']); - $this->fld_flags = isset($prop['flags']); - $this->fld_user = isset($prop['user']); - $this->fld_comment = isset($prop['comment']); - $this->fld_timestamp = isset($prop['timestamp']); - $this->fld_sizes = isset($prop['sizes']); - $this->fld_patrol = isset($prop['patrol']); - - if ($this->fld_patrol) { - global $wgUseRCPatrol, $wgUser; - if (!$wgUseRCPatrol || !$wgUser->isAllowed('patrol')) - $this->dieUsage('patrol property is not available', 'patrol'); - } - } - - if (is_null($resultPageSet)) { - $this->addFields(array ( - 'rc_cur_id', - 'rc_this_oldid', - 'rc_namespace', - 'rc_title', - 'rc_timestamp' - )); - - $this->addFieldsIf('rc_new', $this->fld_flags); - $this->addFieldsIf('rc_minor', $this->fld_flags); - $this->addFieldsIf('rc_user', $this->fld_user); - $this->addFieldsIf('rc_user_text', $this->fld_user); - $this->addFieldsIf('rc_comment', $this->fld_comment); - $this->addFieldsIf('rc_patrolled', $this->fld_patrol); - $this->addFieldsIf('rc_old_len', $this->fld_sizes); - $this->addFieldsIf('rc_new_len', $this->fld_sizes); - } - elseif ($allrev) { - $this->addFields(array ( - 'rc_this_oldid', - 'rc_namespace', - 'rc_title', - 'rc_timestamp' - )); - } else { - $this->addFields(array ( - 'rc_cur_id', - 'rc_namespace', - 'rc_title', - 'rc_timestamp' - )); - } - - $this->addTables(array ( - 'watchlist', - 'page', - 'recentchanges' - )); - - $userId = $wgUser->getID(); - $this->addWhere(array ( - 'wl_namespace = rc_namespace', - 'wl_title = rc_title', - 'rc_cur_id = page_id', - 'wl_user' => $userId, - 'rc_deleted' => 0, - )); - - $this->addWhereRange('rc_timestamp', $dir, $start, $end); - $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 - $this->addWhereIf("rc_timestamp > ''", !isset ($start) && !isset ($end) && $wgDBtype == 'mysql'); - - $this->addOption('LIMIT', $limit +1); - - $data = array (); - $count = 0; - $res = $this->select(__METHOD__); - - $db = $this->getDB(); - 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... - $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp)); - break; - } - - if (is_null($resultPageSet)) { - $vals = $this->extractRowInfo($row); - if ($vals) - $data[] = $vals; - } else { - if ($allrev) { - $data[] = intval($row->rc_this_oldid); - } else { - $data[] = intval($row->rc_cur_id); - } - } - } - - $db->freeResult($res); - - if (is_null($resultPageSet)) { - $this->getResult()->setIndexedTagName($data, 'item'); - $this->getResult()->addValue('query', $this->getModuleName(), $data); - } - elseif ($allrev) { - $resultPageSet->populateFromRevisionIDs($data); - } else { - $resultPageSet->populateFromPageIDs($data); - } - } - - private function extractRowInfo($row) { - - $vals = array (); - - if ($this->fld_ids) { - $vals['pageid'] = intval($row->rc_cur_id); - $vals['revid'] = intval($row->rc_this_oldid); - } - - if ($this->fld_title) - ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle($row->rc_namespace, $row->rc_title)); - - if ($this->fld_user) { - $vals['user'] = $row->rc_user_text; - if (!$row->rc_user) - $vals['anon'] = ''; - } - - if ($this->fld_flags) { - if ($row->rc_new) - $vals['new'] = ''; - if ($row->rc_minor) - $vals['minor'] = ''; - } - - if ($this->fld_patrol && isset($row->rc_patrolled)) - $vals['patrolled'] = ''; - - if ($this->fld_timestamp) - $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); - - $this->addFieldsIf('rc_new_len', $this->fld_sizes); - - if ($this->fld_sizes) { - $vals['oldlen'] = intval($row->rc_old_len); - $vals['newlen'] = intval($row->rc_new_len); - } - - if ($this->fld_comment && !empty ($row->rc_comment)) - $vals['comment'] = $row->rc_comment; - - return $vals; - } - - protected function getAllowedParams() { - return array ( - 'allrev' => false, - 'start' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'end' => array ( - ApiBase :: PARAM_TYPE => 'timestamp' - ), - 'namespace' => array ( - ApiBase :: PARAM_ISMULTI => true, - ApiBase :: PARAM_TYPE => 'namespace' - ), - 'dir' => array ( - ApiBase :: PARAM_DFLT => 'older', - ApiBase :: PARAM_TYPE => array ( - 'newer', - 'older' - ) - ), - 'limit' => array ( - ApiBase :: PARAM_DFLT => 10, - ApiBase :: PARAM_TYPE => 'limit', - ApiBase :: PARAM_MIN => 1, - ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, - ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 - ), - 'prop' => array ( - APIBase :: PARAM_ISMULTI => true, - APIBase :: PARAM_DFLT => 'ids|title|flags', - APIBase :: PARAM_TYPE => array ( - 'ids', - 'title', - 'flags', - 'user', - 'comment', - 'timestamp', - 'patrol', - 'sizes', - ) - ) - ); - } - - protected function getParamDescription() { - return array ( - 'allrev' => 'Include multiple revisions of the same page within given timeframe.', - 'start' => 'The timestamp to start enumerating from.', - 'end' => 'The timestamp to end enumerating.', - '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).' - ); - } - - protected function getDescription() { - return ''; - } - - protected function getExamples() { - return array ( - 'api.php?action=query&list=watchlist', - 'api.php?action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment', - 'api.php?action=query&list=watchlist&wlallrev&wlprop=ids|title|timestamp|user|comment', - 'api.php?action=query&generator=watchlist&prop=info', - 'api.php?action=query&generator=watchlist&gwlallrev&prop=revisions&rvprop=timestamp|user' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} - diff --git a/includes/api/ApiRollback.php b/includes/api/ApiRollback.php deleted file mode 100644 index 1c7606eced..0000000000 --- a/includes/api/ApiRollback.php +++ /dev/null @@ -1,156 +0,0 @@ -.@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->dieUsage('The title parameter must be set', 'notitle'); - if(!isset($params['user'])) - $this->dieUsage('The user parameter must be set', 'nouser'); - if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); - - // doRollback() also checks for these, but we wanna save some work - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - - $titleObj = Title::newFromText($params['title']); - if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); - if(!$titleObj->userCan('rollback')) - $this->dieUsage('You don\'t have permission to rollback', 'permissiondenied'); - - $username = User::getCanonicalName($params['user']); - if(!$username) - $this->dieUsage("Invalid username ``{$params['user']}''", 'invaliduser'); - - $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); - - switch($retval) - { - case Article::SUCCESS: - break; // We'll deal with that later - case Article::PERM_DENIED: - $this->dieUsage("You don't have permission to rollback", 'permissiondenied'); - case Article::BLOCKED: // If we get BLOCKED or PERM_DENIED that's very weird, but it's possible - $this->dieUsage('You have been blocked from editing', 'blocked'); - case Article::READONLY: - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - case Article::BAD_TOKEN: - $this->dieUsage('Invalid token', 'badtoken'); - case Article::BAD_TITLE: - $this->dieUsage("``{$params['title']}'' doesn't exist", 'missingtitle'); - case Article::ALREADYROLLED: - $current = $details['current']; - $currentID = $current->getId(); - $this->dieUsage("The edit(s) you tried to rollback is/are already rolled back." . - "The current revision ID is ``$currentID''", 'alreadyrolled'); - case Article::ONLY_AUTHOR: - $this->dieUsage("User ``$username'' is the only author of the page", 'onlyauthor'); - case Article::RATE_LIMITED: - $this->dieUsage("You can't rollback too many articles in too short a time. Please wait a little while and try again", 'ratelimited'); - default: - // rollback() has apparently invented a new error, which is extremely weird - $this->dieDebug(__METHOD__, "rollback() returned an unknown error ($retval)"); - } - // $retval has to be Article::SUCCESS if we get here - $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); - } - - protected function getAllowedParams() { - return array ( - 'title' => null, - 'user' => null, - 'token' => null, - 'summary' => null, - 'markbot' => false - ); - } - - protected 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' - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiUnblock.php b/includes/api/ApiUnblock.php deleted file mode 100644 index bf5f256097..0000000000 --- a/includes/api/ApiUnblock.php +++ /dev/null @@ -1,130 +0,0 @@ -.@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 ApiUnblock extends ApiBase { - - public function __construct($main, $action) { - parent :: __construct($main, $action); - } - - 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->dieUsage('Either the id or the user parameter must be set', 'notarget'); - if(!is_null($params['id']) && !is_null($params['user'])) - $this->dieUsage('The id and user parameters can\'t be used together', 'idanduser'); - if(is_null($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); - if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); - if(!$wgUser->isAllowed('block')) - $this->dieUsage('You don\'t have permission to unblock users', 'permissiondenied'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - - $id = $params['id']; - $user = $params['user']; - $reason = $params['reason']; - $dbw = wfGetDb(DB_MASTER); - $dbw->begin(); - $retval = IPUnblockForm::doUnblock(&$id, &$user, &$reason, &$range); - - switch($retval) - { - case IPUnblockForm::UNBLOCK_SUCCESS: - break; // We'll deal with that later - case IPUnblockForm::UNBLOCK_NO_SUCH_ID: - $this->dieUsage("There is no block with ID ``$id''", 'nosuchid'); - case IPUnblockForm::UNBLOCK_USER_NOT_BLOCKED: - $this->dieUsage("User ``$user'' is not blocked", 'notblocked'); - case IPUnblockForm::UNBLOCK_BLOCKED_AS_RANGE: - $this->dieUsage("IP address ``$user'' was blocked as part of range ``$range''. You can't unblock the IP invidually, but you can unblock the range as a whole.", 'blockedasrange'); - case IPUnblockForm::UNBLOCK_UNKNOWNERR: - $this->dieUsage("Unknown error", 'unknownerr'); - default: - $this->dieDebug(__METHOD__, "IPBlockForm::doBlock() returned an unknown error ($retval)"); - } - $dbw->commit(); - - $res['id'] = $id; - $res['user'] = $user; - $res['reason'] = $reason; - $this->getResult()->addValue(null, $this->getModuleName(), $res); - } - - protected function getAllowedParams() { - return array ( - 'id' => null, - 'user' => null, - 'token' => null, - 'gettoken' => false, - 'reason' => null, - ); - } - - protected function getParamDescription() { - return array ( - 'id' => 'ID of the block you want to unblock (obtained through list=blocks). Cannot be user 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)', - ); - } - - protected 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$'; - } -} diff --git a/includes/api/ApiUndelete.php b/includes/api/ApiUndelete.php deleted file mode 100644 index 56ce3c6668..0000000000 --- a/includes/api/ApiUndelete.php +++ /dev/null @@ -1,129 +0,0 @@ -.@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->dieUsage('The title parameter must be set', 'notitle'); - if(!isset($params['token'])) - $this->dieUsage('The token parameter must be set', 'notoken'); - - if(!$wgUser->isAllowed('undelete')) - $this->dieUsage('You don\'t have permission to restore deleted revisions', 'permissiondenied'); - if($wgUser->isBlocked()) - $this->dieUsage('You have been blocked from editing', 'blocked'); - if(wfReadOnly()) - $this->dieUsage('The wiki is in read-only mode', 'readonly'); - if(!$wgUser->matchEditToken($params['token'])) - $this->dieUsage('Invalid token', 'badtoken'); - - $titleObj = Title::newFromText($params['title']); - if(!$titleObj) - $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); - - // 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)) - switch($retval) - { - case PageArchive::UNDELETE_NOTHINGRESTORED: - $this->dieUsage('No revisions could be restored', 'norevs'); - case PageArchive::UNDELETE_NOTAVAIL: - $this->dieUsage('Not all requested revisions could be found', 'revsnotfound'); - case PageArchive::UNDELETE_UNKNOWNERR: - $this->dieUsage('Undeletion failed with unknown error', 'unknownerror'); - } - $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); - } - - protected function getAllowedParams() { - return array ( - 'title' => null, - 'token' => null, - 'reason' => "", - 'timestamps' => array( - ApiBase :: PARAM_ISMULTI => true - ) - ); - } - - protected 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.' - ); - } - - protected 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×tamps=20070703220045|20070702194856' - ); - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/edit/ApiBlock.php b/includes/api/edit/ApiBlock.php new file mode 100644 index 0000000000..2779204ef2 --- /dev/null +++ b/includes/api/edit/ApiBlock.php @@ -0,0 +1,164 @@ +.@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 ApiBlock extends ApiBase { + + public function __construct($main, $action) { + parent :: __construct($main, $action); + } + + 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->dieUsage('The user parameter must be set', 'nouser'); + if(is_null($params['token'])) + $this->dieUsage('The token parameter must be set', 'notoken'); + if(!$wgUser->matchEditToken($params['token'])) + $this->dieUsage('Invalid token', 'badtoken'); + if(!$wgUser->isAllowed('block')) + $this->dieUsage('You don\'t have permission to block users', 'permissiondenied'); + if($params['hidename'] && !$wgUser->isAllowed('hideuser')) + $this->dieUsage('You don\'t have permission to hide user names from the block log', 'nohide'); + if(wfReadOnly()) + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + + $form = new IPBlockForm(''); + $form->BlockAddress = $params['user']; + $form->BlockReason = $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); + switch($retval) + { + case IPBlockForm::BLOCK_SUCCESS: + break; // We'll deal with that later + case IPBlockForm::BLOCK_RANGE_INVALID: + $this->dieUsage("Invalid IP range ``{$params['user']}''", 'invalidrange'); + case IPBlockForm::BLOCK_RANGE_DISABLED: + $this->dieUsage('Blocking IP ranges has been disabled', 'rangedisabled'); + case IPBlockForm::BLOCK_NONEXISTENT_USER: + $this->dieUsage("User ``{$params['user']}'' doesn't exist", 'nosuchuser'); + case IPBlockForm::BLOCK_IP_INVALID: + $this->dieUsage("Invaild IP address ``{$params['user']}''", 'invalidip'); + case IPBlockForm::BLOCK_EXPIRY_INVALID: + $this->dieUsage("Invalid expiry time ``{$params['expiry']}''", 'invalidexpiry'); + case IPBlockForm::BLOCK_ALREADY_BLOCKED: + $this->dieUsage("User ``{$params['user']}'' is already blocked", 'alreadyblocked'); + default: + $this->dieDebug(__METHOD__, "IPBlockForm::doBlock() returned an unknown error ($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); + } + + protected function getAllowedParams() { + return array ( + 'user' => null, + 'token' => null, + 'gettoken' => false, + 'expiry' => 'never', + 'reason' => null, + 'anononly' => false, + 'nocreate' => false, + 'autoblock' => false, + 'noemail' => false, + 'hidename' => false, + ); + } + + protected 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', + 'hidename' => 'Hide the username from the block log.' + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/edit/ApiChangeRights.php b/includes/api/edit/ApiChangeRights.php new file mode 100644 index 0000000000..bf19e93697 --- /dev/null +++ b/includes/api/edit/ApiChangeRights.php @@ -0,0 +1,170 @@ +.@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 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 UserrightsForm($wgRequest); + $allowed = $ur->changeableGroups(); + $res = array(); + + if(is_null($params['user'])) + $this->dieUsage('The user parameter must be set', 'nouser'); + + $uName = User::getCanonicalName($params['user']); + $u = User::newFromName($uName); + if(!$u) + $this->dieUsage("Invalid username ``{$params['user']}''", 'invaliduser'); + if($u->getId() == 0) // Anon or non-existent + $this->dieUsage("User ``{$params['user']}'' doesn't exist", 'nosuchuser'); + + $curgroups = $u->getGroups(); + + if($params['listgroups']) + { + $res['user'] = $uName; + $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($uName); + $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'], $uName)) + $this->dieUsage('Invalid token', 'badtoken'); + + if(!$wgUser->isAllowed('userrights')) + $this->dieUsage('You don\'t have permission to change users\' rights', 'permissiondenied'); + + // First let's remove redundant groups and check permissions while we're at it + if(is_null($params['addto'])) + $params['addto'] = array(); + $addto = array(); + foreach($params['addto'] as $g) + { + if(!in_array($g, $allowed['add'])) + $this->dieUsage("You don't have permission to add to group ``$g''", 'cantadd'); + if(!in_array($g, $curgroups)) + $addto[] = $g; + } + + if(is_null($params['rmfrom'])) + $params['rmfrom'] = array(); + $rmfrom = array(); + foreach($params['rmfrom'] as $g) + { + if(!in_array($g, $allowed['remove'])) + $this->dieUsage("You don't have permission to remove from group ``$g''", 'cantremove'); + if(in_array($g, $curgroups)) + $rmfrom[] = $g; + } + $dbw = wfGetDb(DB_MASTER); + $dbw->begin(); + $ur->doSaveUserGroups($u, $rmfrom, $addto, $params['reason']); + $dbw->commit(); + $res['user'] = $uName; + $res['addedto'] = $addto; + $res['removedfrom'] = $rmfrom; + $res['reason'] = $params['reason']; + + $this->getResult()->setIndexedTagName($res['addedto'], 'group'); + $this->getResult()->setIndexedTagName($res['removedfrom'], 'group'); + $this->getResult()->addValue(null, $this->getModuleName(), $res); + } + + protected 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' => '' + ); + } + + protected 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)' + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/edit/ApiDelete.php b/includes/api/edit/ApiDelete.php new file mode 100644 index 0000000000..b094d1a188 --- /dev/null +++ b/includes/api/edit/ApiDelete.php @@ -0,0 +1,172 @@ +.@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 ApiDelete extends ApiBase { + + public function __construct($main, $action) { + parent :: __construct($main, $action); + } + + /** + * 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 DELETE_SUCCESS on success, DELETE_* on failure + */ + + const DELETE_SUCCESS = 0; + const DELETE_PERM = 1; + const DELETE_BLOCKED = 2; + const DELETE_READONLY = 3; + const DELETE_BADTOKEN = 4; + const DELETE_BADARTICLE = 5; + + public static function delete(&$article, $token, &$reason = NULL) + { + global $wgUser; + + // Check permissions first + if(!$article->mTitle->userCan('delete')) + return self::DELETE_PERM; + if($wgUser->isBlocked()) + return self::DELETE_BLOCKED; + if(wfReadOnly()) + return self::DELETE_READONLY; + + // Check token + if(!$wgUser->matchEditToken($token)) + return self::DELETE_BADTOKEN; + + // Auto-generate a summary, if necessary + if(is_null($reason)) + { + $reason = $article->generateReason($hasHistory); + if($reason === false) + return self::DELETE_BADARTICLE; + } + + // Luckily, Article.php provides a reusable delete function that does the hard work for us + if($article->doDeleteArticle($reason)) + return self::DELETE_SUCCESS; + return self::DELETE_BADARTICLE; + } + + public function execute() { + global $wgUser; + $this->getMain()->requestWriteMode(); + $params = $this->extractRequestParams(); + + $titleObj = NULL; + if(!isset($params['title'])) + $this->dieUsage('The title parameter must be set', 'notitle'); + if(!isset($params['token'])) + $this->dieUsage('The token parameter must be set', 'notoken'); + + // delete() also checks for these, but we wanna save some work + if(!$wgUser->isAllowed('delete')) + $this->dieUsage('You don\'t have permission to delete pages', 'permissiondenied'); + if($wgUser->isBlocked()) + $this->dieUsage('You have been blocked from editing', 'blocked'); + if(wfReadOnly()) + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + + $titleObj = Title::newFromText($params['title']); + if(!$titleObj) + $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); + if(!$titleObj->exists()) + $this->dieUsage("``{$params['title']}'' doesn't exist", 'missingtitle'); + + $articleObj = new Article($titleObj); + $reason = (isset($params['reason']) ? $params['reason'] : NULL); + $dbw = wfGetDb(DB_MASTER); + $dbw->begin(); + $retval = self::delete(&$articleObj, $params['token'], &$reason); + + switch($retval) + { + case self::DELETE_SUCCESS: + break; // We'll deal with that later + case self::DELETE_PERM: // If we get PERM, BLOCKED or READONLY that's weird, but it's possible + $this->dieUsage('You don\'t have permission to delete', 'permissiondenied'); + case self::DELETE_BLOCKED: + $this->dieUsage('You have been blocked from editing', 'blocked'); + case self::DELETE_READONLY: + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + case self::DELETE_BADTOKEN: + $this->dieUsage('Invalid token', 'badtoken'); + case self::DELETE_BADARTICLE: + $this->dieUsage("The article ``{$params['title']}'' doesn't exist or has already been deleted", 'missingtitle'); + default: + // delete() has apparently invented a new error, which is extremely weird + $this->dieDebug(__METHOD__, "delete() returned an unknown error ($retval)"); + } + // $retval has to be self::DELETE_SUCCESS if we get here + $dbw->commit(); + $r = array('title' => $titleObj->getPrefixedText(), 'reason' => $reason); + $this->getResult()->addValue(null, $this->getModuleName(), $r); + } + + protected function getAllowedParams() { + return array ( + 'title' => null, + 'token' => null, + 'reason' => null, + ); + } + + protected 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.' + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/edit/ApiMove.php b/includes/api/edit/ApiMove.php new file mode 100644 index 0000000000..5cd5dd96fa --- /dev/null +++ b/includes/api/edit/ApiMove.php @@ -0,0 +1,181 @@ +.@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->dieUsage('The from parameter must be set', 'nofrom'); + if(!isset($params['to'])) + $this->dieUsage('The to parameter must be set', 'noto'); + if(!isset($params['token'])) + $this->dieUsage('The token parameter must be set', 'notoken'); + if(!$wgUser->matchEditToken($params['token'])) + $this->dieUsage('Invalid token', 'badtoken'); + + if($wgUser->isBlocked()) + $this->dieUsage('You have been blocked from editing', 'blocked'); + if(wfReadOnly()) + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + if($params['noredirect'] && !$wgUser->isAllowed('suppressredirect')) + $this->dieUsage("You don't have permission to suppress redirect creation", 'nosuppress'); + + $fromTitle = Title::newFromText($params['from']); + if(!$fromTitle) + $this->dieUsage("Bad title ``{$params['from']}''", 'invalidtitle'); + if(!$fromTitle->exists()) + $this->dieUsage("``{$params['from']}'' doesn't exist", 'missingtitle'); + $fromTalk = $fromTitle->getTalkPage(); + + + $toTitle = Title::newFromText($params['to']); + if(!$toTitle) + $this->dieUsage("Bad title ``{$params['to']}''", 'invalidtitle'); + $toTalk = $toTitle->getTalkPage(); + + $dbw = wfGetDB(DB_MASTER); + $dbw->begin(); + $retval = $fromTitle->moveTo($toTitle, true, $params['reason'], !$params['noredirect']); + if($retval !== true) + switch($retval) + { + // case 'badtitletext': Can't happen + // case 'badarticleerror': Can't happen + case 'selfmove': + $this->dieUsage("Can't move ``{$params['from']}'' to itself", 'selfmove'); + case 'immobile_namespace': + if($fromTitle->isMovable()) + $this->dieUsage("Pages in the ``{$fromTitle->getNsText()}'' namespace can't be moved", 'immobilenamespace-from'); + $this->dieUsage("Pages in the ``{$toTitle->getNsText()}'' namespace can't be moved", 'immobilenamespace-to'); + case 'articleexists': + $this->dieUsage("``{$toTitle->getPrefixedText()}'' already exists and is not a redirect to ``{$fromTitle->getPrefixedText()}''", 'targetexists'); + case 'protectedpage': + $this->dieUsage("You don't have permission to move ``{$fromTitle->getPrefixedText()}'' to ``{$toTitle->getPrefixedText()}''", 'permissiondenied'); + default: + throw new MWException( "Title::moveTo: Unknown return value ``{$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 + switch($retval) + { + case 'immobile_namespace': + if($fromTalk->isMovable()) + { + $r['talkmove-error-code'] = 'immobilenamespace-from'; + $r['talkmove-error-info'] = "Pages in the ``{$fromTalk->getNsText()}'' namespace can't be moved"; + } + else + { + $r['talkmove-error-code'] = 'immobilenamespace-to'; + $r['talkmove-error-info'] = "Pages in the ``{$toTalk->getNsText()}'' namespace can't be moved"; + } + break; + case 'articleexists': + $r['talkmove-error-code'] = 'targetexists'; + $r['talkmove-error-info'] = "``{$toTalk->getPrefixedText()}'' already exists and is not a redirect to ``{$fromTalk->getPrefixedText()}''"; + break; + case 'protectedpage': + $r['talkmove-error-code'] = 'permissiondenied'; + $r['talkmove-error-info'] = "You don't have permission to move ``{$fromTalk->getPrefixedText()}'' to ``{$toTalk->getPrefixedText()}''"; + default: + $r['talkmove-error-code'] = 'unknownerror'; + $r['talkmove-error-info'] = "Unknown error ``$retval''"; + } + } + $dbw->commit(); // Make sure all changes are really written to the DB + $this->getResult()->addValue(null, $this->getModuleName(), $r); + } + + protected function getAllowedParams() { + return array ( + 'from' => null, + 'to' => null, + 'token' => null, + 'reason' => null, + 'movetalk' => false, + 'noredirect' => false + ); + } + + protected 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' + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/edit/ApiProtect.php b/includes/api/edit/ApiProtect.php new file mode 100644 index 0000000000..aa40b937fa --- /dev/null +++ b/includes/api/edit/ApiProtect.php @@ -0,0 +1,142 @@ +.@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->dieUsage('The title parameter must be set', 'notitle'); + if(!isset($params['token'])) + $this->dieUsage('The token parameter must be set', 'notoken'); + if(!isset($params['protections']) || empty($params['protections'])) + $this->dieUsage('The protections parameter must be set', 'noprotections'); + + if($wgUser->isBlocked()) + $this->dieUsage('You have been blocked from editing', 'blocked'); + if(wfReadOnly()) + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + if(!$wgUser->matchEditToken($params['token'])) + $this->dieUsage('Invalid token', 'badtoken'); + + $titleObj = Title::newFromText($params['title']); + if(!$titleObj) + $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); + if(!$titleObj->exists()) + $this->dieUsage("``{$params['title']}'' doesn't exist", 'missingtitle'); + if(!$titleObj->userCan('protect')) + $this->dieUsage('You don\'t have permission to change protection levels', 'permissiondenied'); + $articleObj = new Article($titleObj); + + if(in_array($params['expiry'], array('infinite', 'indefinite', 'never'))) + $expiry = Block::infinity(); + else + { + $expiry = strtotime($params['expiry']); + if($expiry < 0 || $expiry == false) + $this->dieUsage('Invalid expiry time', 'invalidexpiry'); + + $expiry = wfTimestamp(TS_MW, $expiry); + if($expiry < wfTimestampNow()) + $this->dieUsage('Expiry time is in the past', 'pastexpiry'); + } + + $protections = array(); + foreach($params['protections'] as $prot) + { + $p = explode('=', $prot); + $protections[$p[0]] = ($p[1] == 'all' ? '' : $p[1]); + } + + $dbw = wfGetDb(DB_MASTER); + $dbw->begin(); + $ok = $articleObj->updateRestrictions($protections, $params['reason'], $params['cascade'], $expiry); + if(!$ok) + // This is very weird. Maybe the article was deleted or the user was blocked/desysopped in the meantime? + $this->dieUsage('Unknown error', 'unknownerror'); + $dbw->commit(); + $res = array('title' => $titleObj->getPrefixedText(), 'reason' => $params['reason'], 'expiry' => $expiry); + if($params['cascade']) + $res['cascade'] = ''; + $res['protections'] = $protections; + $this->getResult()->addValue(null, $this->getModuleName(), $res); + } + + protected function getAllowedParams() { + return array ( + 'title' => null, + 'token' => null, + 'protections' => array( + ApiBase :: PARAM_ISMULTI => true + ), + 'expiry' => 'infinite', + 'reason' => '', + 'cascade' => false + ); + } + + protected 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)' + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/edit/ApiRollback.php b/includes/api/edit/ApiRollback.php new file mode 100644 index 0000000000..10999ff757 --- /dev/null +++ b/includes/api/edit/ApiRollback.php @@ -0,0 +1,156 @@ +.@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->dieUsage('The title parameter must be set', 'notitle'); + if(!isset($params['user'])) + $this->dieUsage('The user parameter must be set', 'nouser'); + if(!isset($params['token'])) + $this->dieUsage('The token parameter must be set', 'notoken'); + + // doRollback() also checks for these, but we wanna save some work + if($wgUser->isBlocked()) + $this->dieUsage('You have been blocked from editing', 'blocked'); + if(wfReadOnly()) + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + + $titleObj = Title::newFromText($params['title']); + if(!$titleObj) + $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); + if(!$titleObj->userCan('rollback')) + $this->dieUsage('You don\'t have permission to rollback', 'permissiondenied'); + + $username = User::getCanonicalName($params['user']); + if(!$username) + $this->dieUsage("Invalid username ``{$params['user']}''", 'invaliduser'); + + $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); + + switch($retval) + { + case Article::SUCCESS: + break; // We'll deal with that later + case Article::PERM_DENIED: + $this->dieUsage("You don't have permission to rollback", 'permissiondenied'); + case Article::BLOCKED: // If we get BLOCKED or PERM_DENIED that's very weird, but it's possible + $this->dieUsage('You have been blocked from editing', 'blocked'); + case Article::READONLY: + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + case Article::BAD_TOKEN: + $this->dieUsage('Invalid token', 'badtoken'); + case Article::BAD_TITLE: + $this->dieUsage("``{$params['title']}'' doesn't exist", 'missingtitle'); + case Article::ALREADYROLLED: + $current = $details['current']; + $currentID = $current->getId(); + $this->dieUsage("The edit(s) you tried to rollback is/are already rolled back." . + "The current revision ID is ``$currentID''", 'alreadyrolled'); + case Article::ONLY_AUTHOR: + $this->dieUsage("User ``$username'' is the only author of the page", 'onlyauthor'); + case Article::RATE_LIMITED: + $this->dieUsage("You can't rollback too many articles in too short a time. Please wait a little while and try again", 'ratelimited'); + default: + // rollback() has apparently invented a new error, which is extremely weird + $this->dieDebug(__METHOD__, "rollback() returned an unknown error ($retval)"); + } + // $retval has to be Article::SUCCESS if we get here + $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); + } + + protected function getAllowedParams() { + return array ( + 'title' => null, + 'user' => null, + 'token' => null, + 'summary' => null, + 'markbot' => false + ); + } + + protected 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' + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/edit/ApiUnblock.php b/includes/api/edit/ApiUnblock.php new file mode 100644 index 0000000000..c003699ec5 --- /dev/null +++ b/includes/api/edit/ApiUnblock.php @@ -0,0 +1,130 @@ +.@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 ApiUnblock extends ApiBase { + + public function __construct($main, $action) { + parent :: __construct($main, $action); + } + + 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->dieUsage('Either the id or the user parameter must be set', 'notarget'); + if(!is_null($params['id']) && !is_null($params['user'])) + $this->dieUsage('The id and user parameters can\'t be used together', 'idanduser'); + if(is_null($params['token'])) + $this->dieUsage('The token parameter must be set', 'notoken'); + if(!$wgUser->matchEditToken($params['token'])) + $this->dieUsage('Invalid token', 'badtoken'); + if(!$wgUser->isAllowed('block')) + $this->dieUsage('You don\'t have permission to unblock users', 'permissiondenied'); + if(wfReadOnly()) + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + + $id = $params['id']; + $user = $params['user']; + $reason = $params['reason']; + $dbw = wfGetDb(DB_MASTER); + $dbw->begin(); + $retval = IPUnblockForm::doUnblock(&$id, &$user, &$reason, &$range); + + switch($retval) + { + case IPUnblockForm::UNBLOCK_SUCCESS: + break; // We'll deal with that later + case IPUnblockForm::UNBLOCK_NO_SUCH_ID: + $this->dieUsage("There is no block with ID ``$id''", 'nosuchid'); + case IPUnblockForm::UNBLOCK_USER_NOT_BLOCKED: + $this->dieUsage("User ``$user'' is not blocked", 'notblocked'); + case IPUnblockForm::UNBLOCK_BLOCKED_AS_RANGE: + $this->dieUsage("IP address ``$user'' was blocked as part of range ``$range''. You can't unblock the IP invidually, but you can unblock the range as a whole.", 'blockedasrange'); + case IPUnblockForm::UNBLOCK_UNKNOWNERR: + $this->dieUsage("Unknown error", 'unknownerr'); + default: + $this->dieDebug(__METHOD__, "IPBlockForm::doBlock() returned an unknown error ($retval)"); + } + $dbw->commit(); + + $res['id'] = $id; + $res['user'] = $user; + $res['reason'] = $reason; + $this->getResult()->addValue(null, $this->getModuleName(), $res); + } + + protected function getAllowedParams() { + return array ( + 'id' => null, + 'user' => null, + 'token' => null, + 'gettoken' => false, + 'reason' => null, + ); + } + + protected function getParamDescription() { + return array ( + 'id' => 'ID of the block you want to unblock (obtained through list=blocks). Cannot be user 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)', + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/edit/ApiUndelete.php b/includes/api/edit/ApiUndelete.php new file mode 100644 index 0000000000..db569340c2 --- /dev/null +++ b/includes/api/edit/ApiUndelete.php @@ -0,0 +1,129 @@ +.@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->dieUsage('The title parameter must be set', 'notitle'); + if(!isset($params['token'])) + $this->dieUsage('The token parameter must be set', 'notoken'); + + if(!$wgUser->isAllowed('undelete')) + $this->dieUsage('You don\'t have permission to restore deleted revisions', 'permissiondenied'); + if($wgUser->isBlocked()) + $this->dieUsage('You have been blocked from editing', 'blocked'); + if(wfReadOnly()) + $this->dieUsage('The wiki is in read-only mode', 'readonly'); + if(!$wgUser->matchEditToken($params['token'])) + $this->dieUsage('Invalid token', 'badtoken'); + + $titleObj = Title::newFromText($params['title']); + if(!$titleObj) + $this->dieUsage("Bad title ``{$params['title']}''", 'invalidtitle'); + + // 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)) + switch($retval) + { + case PageArchive::UNDELETE_NOTHINGRESTORED: + $this->dieUsage('No revisions could be restored', 'norevs'); + case PageArchive::UNDELETE_NOTAVAIL: + $this->dieUsage('Not all requested revisions could be found', 'revsnotfound'); + case PageArchive::UNDELETE_UNKNOWNERR: + $this->dieUsage('Undeletion failed with unknown error', 'unknownerror'); + } + $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); + } + + protected function getAllowedParams() { + return array ( + 'title' => null, + 'token' => null, + 'reason' => "", + 'timestamps' => array( + ApiBase :: PARAM_ISMULTI => true + ) + ); + } + + protected 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.' + ); + } + + protected 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×tamps=20070703220045|20070702194856' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiUndelete.php 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/query/ApiQuery.php b/includes/api/query/ApiQuery.php new file mode 100644 index 0000000000..8f5d0e1b98 --- /dev/null +++ b/includes/api/query/ApiQuery.php @@ -0,0 +1,501 @@ +@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'); +} + +/** + * This is the main query class. It behaves similar to ApiMain: based on the parameters given, + * it will create a list of titles to work on (an instance of the ApiPageSet object) + * instantiate and execute various property/list/meta modules, + * and assemble all resulting data into a single ApiResult object. + * + * In the generator mode, a generator will be first executed to populate a second ApiPageSet object, + * and that object will be used for all subsequent modules. + * + * @addtogroup API + */ +class ApiQuery extends ApiBase { + + private $mPropModuleNames, $mListModuleNames, $mMetaModuleNames; + private $mPageSet; + private $params, $redirect; + + private $mQueryPropModules = array ( + 'info' => 'ApiQueryInfo', + 'revisions' => 'ApiQueryRevisions', + 'links' => 'ApiQueryLinks', + 'langlinks' => 'ApiQueryLangLinks', + 'images' => 'ApiQueryImages', + 'imageinfo' => 'ApiQueryImageInfo', + 'templates' => 'ApiQueryLinks', + 'categories' => 'ApiQueryCategories', + 'extlinks' => 'ApiQueryExternalLinks', + ); + + private $mQueryListModules = array ( + 'allpages' => 'ApiQueryAllpages', + 'alllinks' => 'ApiQueryAllLinks', + 'allusers' => 'ApiQueryAllUsers', + 'backlinks' => 'ApiQueryBacklinks', + 'blocks' => 'ApiQueryBlocks', + 'categorymembers' => 'ApiQueryCategoryMembers', + 'deletedrevs' => 'ApiQueryDeletedrevs', + 'embeddedin' => 'ApiQueryBacklinks', + 'imageusage' => 'ApiQueryBacklinks', + 'logevents' => 'ApiQueryLogEvents', + 'recentchanges' => 'ApiQueryRecentChanges', + 'search' => 'ApiQuerySearch', + 'usercontribs' => 'ApiQueryContributions', + 'watchlist' => 'ApiQueryWatchlist', + 'exturlusage' => 'ApiQueryExtLinksUsage', + ); + + private $mQueryMetaModules = array ( + 'siteinfo' => 'ApiQuerySiteinfo', + 'userinfo' => 'ApiQueryUserInfo', + 'allmessages' => 'ApiQueryAllmessages', + ); + + private $mSlaveDB = null; + private $mNamedDB = array(); + + public function __construct($main, $action) { + parent :: __construct($main, $action); + + // Allow custom modules to be added in LocalSettings.php + global $wgApiQueryPropModules, $wgApiQueryListModules, $wgApiQueryMetaModules; + self :: appendUserModules($this->mQueryPropModules, $wgApiQueryPropModules); + self :: appendUserModules($this->mQueryListModules, $wgApiQueryListModules); + self :: appendUserModules($this->mQueryMetaModules, $wgApiQueryMetaModules); + + $this->mPropModuleNames = array_keys($this->mQueryPropModules); + $this->mListModuleNames = array_keys($this->mQueryListModules); + $this->mMetaModuleNames = array_keys($this->mQueryMetaModules); + + // Allow the entire list of modules at first, + // but during module instantiation check if it can be used as a generator. + $this->mAllowedGenerators = array_merge($this->mListModuleNames, $this->mPropModuleNames); + } + + /** + * Helper function to append any add-in modules to the list + */ + private static function appendUserModules(&$modules, $newModules) { + if (is_array( $newModules )) { + foreach ( $newModules as $moduleName => $moduleClass) { + $modules[$moduleName] = $moduleClass; + } + } + } + + /** + * Gets a default slave database connection object + */ + public function getDB() { + if (!isset ($this->mSlaveDB)) { + $this->profileDBIn(); + $this->mSlaveDB = wfGetDB(DB_SLAVE); + $this->profileDBOut(); + } + return $this->mSlaveDB; + } + + /** + * Get the query database connection with the given name. + * If no such connection has been requested before, it will be created. + * Subsequent calls with the same $name will return the same connection + * as the first, regardless of $db or $groups new values. + */ + public function getNamedDB($name, $db, $groups) { + if (!array_key_exists($name, $this->mNamedDB)) { + $this->profileDBIn(); + $this->mNamedDB[$name] = wfGetDB($db, $groups); + $this->profileDBOut(); + } + return $this->mNamedDB[$name]; + } + + /** + * Gets the set of pages the user has requested (or generated) + */ + public function getPageSet() { + return $this->mPageSet; + } + + /** + * Query execution happens in the following steps: + * #1 Create a PageSet object with any pages requested by the user + * #2 If using generator, execute it to get a new PageSet object + * #3 Instantiate all requested modules. + * This way the PageSet object will know what shared data is required, + * and minimize DB calls. + * #4 Output all normalization and redirect resolution information + * #5 Execute all requested modules + */ + public function execute() { + + $this->params = $this->extractRequestParams(); + $this->redirects = $this->params['redirects']; + + // + // Create PageSet + // + $this->mPageSet = new ApiPageSet($this, $this->redirects); + + // + // Instantiate requested modules + // + $modules = array (); + $this->InstantiateModules($modules, 'prop', $this->mQueryPropModules); + $this->InstantiateModules($modules, 'list', $this->mQueryListModules); + $this->InstantiateModules($modules, 'meta', $this->mQueryMetaModules); + + // + // If given, execute generator to substitute user supplied data with generated data. + // + if (isset ($this->params['generator'])) { + $this->executeGeneratorModule($this->params['generator'], $modules); + } else { + // Append custom fields and populate page/revision information + $this->addCustomFldsToPageSet($modules, $this->mPageSet); + $this->mPageSet->execute(); + } + + // + // Record page information (title, namespace, if exists, etc) + // + $this->outputGeneralPageInfo(); + + // + // Execute all requested modules. + // + foreach ($modules as $module) { + $module->profileIn(); + $module->execute(); + $module->profileOut(); + } + } + + /** + * Query modules may optimize data requests through the $this->getPageSet() object + * by adding extra fields from the page table. + * This function will gather all the extra request fields from the modules. + */ + private function addCustomFldsToPageSet($modules, $pageSet) { + // Query all requested modules. + foreach ($modules as $module) { + $module->requestExtraData($pageSet); + } + } + + /** + * Create instances of all modules requested by the client + */ + private function InstantiateModules(&$modules, $param, $moduleList) { + $list = $this->params[$param]; + if (isset ($list)) + foreach ($list as $moduleName) + $modules[] = new $moduleList[$moduleName] ($this, $moduleName); + } + + /** + * Appends an element for each page in the current pageSet with the most general + * information (id, title), plus any title normalizations and missing title/pageids/revids. + */ + private function outputGeneralPageInfo() { + + $pageSet = $this->getPageSet(); + $result = $this->getResult(); + + // Title normalizations + $normValues = array (); + foreach ($pageSet->getNormalizedTitles() as $rawTitleStr => $titleStr) { + $normValues[] = array ( + 'from' => $rawTitleStr, + 'to' => $titleStr + ); + } + + if (!empty ($normValues)) { + $result->setIndexedTagName($normValues, 'n'); + $result->addValue('query', 'normalized', $normValues); + } + + // Interwiki titles + $intrwValues = array (); + foreach ($pageSet->getInterwikiTitles() as $rawTitleStr => $interwikiStr) { + $intrwValues[] = array ( + 'title' => $rawTitleStr, + 'iw' => $interwikiStr + ); + } + + if (!empty ($intrwValues)) { + $result->setIndexedTagName($intrwValues, 'i'); + $result->addValue('query', 'interwiki', $intrwValues); + } + + // Show redirect information + $redirValues = array (); + foreach ($pageSet->getRedirectTitles() as $titleStrFrom => $titleStrTo) { + $redirValues[] = array ( + 'from' => $titleStrFrom, + 'to' => $titleStrTo + ); + } + + if (!empty ($redirValues)) { + $result->setIndexedTagName($redirValues, 'r'); + $result->addValue('query', 'redirects', $redirValues); + } + + // + // Missing revision elements + // + $missingRevIDs = $pageSet->getMissingRevisionIDs(); + if (!empty ($missingRevIDs)) { + $revids = array (); + foreach ($missingRevIDs as $revid) { + $revids[$revid] = array ( + 'revid' => $revid + ); + } + $result->setIndexedTagName($revids, 'rev'); + $result->addValue('query', 'badrevids', $revids); + } + + // + // Page elements + // + $pages = array (); + + // Report any missing titles + foreach ($pageSet->getMissingTitles() as $fakeId => $title) { + $vals = array(); + ApiQueryBase :: addTitleInfo($vals, $title); + $vals['missing'] = ''; + $pages[$fakeId] = $vals; + } + + // Report any missing page ids + foreach ($pageSet->getMissingPageIDs() as $pageid) { + $pages[$pageid] = array ( + 'pageid' => $pageid, + 'missing' => '' + ); + } + + // Output general page information for found titles + foreach ($pageSet->getGoodTitles() as $pageid => $title) { + $vals = array(); + $vals['pageid'] = $pageid; + ApiQueryBase :: addTitleInfo($vals, $title); + $pages[$pageid] = $vals; + } + + if (!empty ($pages)) { + + if ($this->params['indexpageids']) { + $pageIDs = array_keys($pages); + // json treats all map keys as strings - converting to match + $pageIDs = array_map('strval', $pageIDs); + $result->setIndexedTagName($pageIDs, 'id'); + $result->addValue('query', 'pageids', $pageIDs); + } + + $result->setIndexedTagName($pages, 'page'); + $result->addValue('query', 'pages', $pages); + } + } + + /** + * For generator mode, execute generator, and use its output as new pageSet + */ + protected function executeGeneratorModule($generatorName, $modules) { + + // Find class that implements requested generator + if (isset ($this->mQueryListModules[$generatorName])) { + $className = $this->mQueryListModules[$generatorName]; + } elseif (isset ($this->mQueryPropModules[$generatorName])) { + $className = $this->mQueryPropModules[$generatorName]; + } else { + ApiBase :: dieDebug(__METHOD__, "Unknown generator=$generatorName"); + } + + // Generator results + $resultPageSet = new ApiPageSet($this, $this->redirects); + + // Create and execute the generator + $generator = new $className ($this, $generatorName); + if (!$generator instanceof ApiQueryGeneratorBase) + $this->dieUsage("Module $generatorName cannot be used as a generator", "badgenerator"); + + $generator->setGeneratorMode(); + + // Add any additional fields modules may need + $generator->requestExtraData($this->mPageSet); + $this->addCustomFldsToPageSet($modules, $resultPageSet); + + // Populate page information with the original user input + $this->mPageSet->execute(); + + // populate resultPageSet with the generator output + $generator->profileIn(); + $generator->executeGenerator($resultPageSet); + $resultPageSet->finishPageSetGeneration(); + $generator->profileOut(); + + // Swap the resulting pageset back in + $this->mPageSet = $resultPageSet; + } + + /** + * Returns the list of allowed parameters for this module. + * Qurey module also lists all ApiPageSet parameters as its own. + */ + protected function getAllowedParams() { + return array ( + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => $this->mPropModuleNames + ), + 'list' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => $this->mListModuleNames + ), + 'meta' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => $this->mMetaModuleNames + ), + 'generator' => array ( + ApiBase :: PARAM_TYPE => $this->mAllowedGenerators + ), + 'redirects' => false, + 'indexpageids' => false, + ); + } + + /** + * Override the parent to generate help messages for all available query modules. + */ + public function makeHelpMsg() { + + $msg = ''; + + // Make sure the internal object is empty + // (just in case a sub-module decides to optimize during instantiation) + $this->mPageSet = null; + $this->mAllowedGenerators = array(); // Will be repopulated + + $astriks = str_repeat('--- ', 8); + $msg .= "\n$astriks Query: Prop $astriks\n\n"; + $msg .= $this->makeHelpMsgHelper($this->mQueryPropModules, 'prop'); + $msg .= "\n$astriks Query: List $astriks\n\n"; + $msg .= $this->makeHelpMsgHelper($this->mQueryListModules, 'list'); + $msg .= "\n$astriks Query: Meta $astriks\n\n"; + $msg .= $this->makeHelpMsgHelper($this->mQueryMetaModules, 'meta'); + + // Perform the base call last because the $this->mAllowedGenerators + // will be updated inside makeHelpMsgHelper() + // Use parent to make default message for the query module + $msg = parent :: makeHelpMsg() . $msg; + + return $msg; + } + + /** + * For all modules in $moduleList, generate help messages and join them together + */ + private function makeHelpMsgHelper($moduleList, $paramName) { + + $moduleDscriptions = array (); + + foreach ($moduleList as $moduleName => $moduleClass) { + $module = new $moduleClass ($this, $moduleName, null); + + $msg = ApiMain::makeHelpMsgHeader($module, $paramName); + $msg2 = $module->makeHelpMsg(); + if ($msg2 !== false) + $msg .= $msg2; + if ($module instanceof ApiQueryGeneratorBase) { + $this->mAllowedGenerators[] = $moduleName; + $msg .= "Generator:\n This module may be used as a generator\n"; + } + $moduleDscriptions[] = $msg; + } + + return implode("\n", $moduleDscriptions); + } + + /** + * Override to add extra parameters from PageSet + */ + public function makeHelpMsgParameters() { + $psModule = new ApiPageSet($this); + return $psModule->makeHelpMsgParameters() . parent :: makeHelpMsgParameters(); + } + + // @todo should work correctly + public function shouldCheckMaxlag() { + return true; + } + + protected function getParamDescription() { + return array ( + 'prop' => 'Which properties to get for the titles/revisions/pageids', + 'list' => 'Which lists to get', + 'meta' => 'Which meta data to get about the site', + 'generator' => 'Use the output of a list as the input for other prop/list/meta items', + 'redirects' => 'Automatically resolve redirects', + 'indexpageids' => 'Include an additional pageids section listing all returned page IDs.' + ); + } + + protected 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.', + 'All data modifications will first have to use query to acquire a token to prevent abuse from malicious sites.' + ); + } + + protected function getExamples() { + return array ( + 'api.php?action=query&prop=revisions&meta=siteinfo&titles=Main%20Page&rvprop=user|comment' + ); + } + + public function getVersion() { + $psModule = new ApiPageSet($this); + $vers = array (); + $vers[] = __CLASS__ . ': $Id: ApiQuery.php 28051 2007-12-02 14:24:07Z catrope $'; + $vers[] = $psModule->getVersion(); + return $vers; + } +} + diff --git a/includes/api/query/ApiQueryAllLinks.php b/includes/api/query/ApiQueryAllLinks.php new file mode 100644 index 0000000000..17f24b6549 --- /dev/null +++ b/includes/api/query/ApiQueryAllLinks.php @@ -0,0 +1,179 @@ +@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'); +} + +/** + * Query module to enumerate links from all pages together. + * + * @addtogroup API + */ +class ApiQueryAllLinks extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'al'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + $db = $this->getDB(); + $params = $this->extractRequestParams(); + + $prop = array_flip($params['prop']); + $fld_ids = isset($prop['ids']); + $fld_title = isset($prop['title']); + + if ($params['unique']) { + if (!is_null($resultPageSet)) + $this->dieUsage($this->getModuleName() . ' cannot be used as a generator in unique links mode', 'params'); + if ($fld_ids) + $this->dieUsage($this->getModuleName() . ' cannot return corresponding page ids in unique links mode', 'params'); + $this->addOption('DISTINCT'); + } + + $this->addTables('pagelinks'); + $this->addWhereFld('pl_namespace', $params['namespace']); + + if (!is_null($params['from'])) + $this->addWhere('pl_title>=' . $db->addQuotes(ApiQueryBase :: titleToKey($params['from']))); + if (isset ($params['prefix'])) + $this->addWhere("pl_title LIKE '" . $db->escapeLike(ApiQueryBase :: titleToKey($params['prefix'])) . "%'"); + + if (is_null($resultPageSet)) { + $this->addFields(array ( + 'pl_namespace', + 'pl_title' + )); + $this->addFieldsIf('pl_from', $fld_ids); + } else { + $this->addFields('pl_from'); + $pageids = array(); + } + + $this->addOption('USE INDEX', 'pl_namespace'); + $limit = $params['limit']; + $this->addOption('LIMIT', $limit+1); + $this->addOption('ORDER BY', 'pl_namespace, pl_title'); + + $res = $this->select(__METHOD__); + + $data = array (); + $count = 0; + 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... + // TODO: Security issue - if the user has no right to view next title, it will still be shown + $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->pl_title)); + break; + } + + if (is_null($resultPageSet)) { + $vals = array(); + if ($fld_ids) + $vals['fromid'] = intval($row->pl_from); + if ($fld_title) { + $title = Title :: makeTitle($row->pl_namespace, $row->pl_title); + $vals['ns'] = intval($title->getNamespace()); + $vals['title'] = $title->getPrefixedText(); + } + $data[] = $vals; + } else { + $pageids[] = $row->pl_from; + } + } + $db->freeResult($res); + + if (is_null($resultPageSet)) { + $result = $this->getResult(); + $result->setIndexedTagName($data, 'l'); + $result->addValue('query', $this->getModuleName(), $data); + } else { + $resultPageSet->populateFromPageIDs($pageids); + } + } + + protected function getAllowedParams() { + return array ( + 'from' => null, + 'prefix' => null, + 'unique' => false, + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_DFLT => 'title', + ApiBase :: PARAM_TYPE => array ( + 'ids', + 'title' + ) + ), + 'namespace' => array ( + ApiBase :: PARAM_DFLT => 0, + 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 + ) + ); + } + + protected function getParamDescription() { + return array ( + 'from' => 'The page title to start enumerating from.', + 'prefix' => 'Search for all page titles that begin with this value.', + 'unique' => 'Only show unique links. Cannot be used with generator or prop=ids', + 'prop' => 'What pieces of information to include', + 'namespace' => 'The namespace to enumerate.', + 'limit' => 'How many total links to return.' + ); + } + + protected function getDescription() { + return 'Enumerate all links that point to a given namespace'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=alllinks&alunique&alfrom=B', + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryAllLinks.php 24453 2007-07-30 08:09:15Z yurik $'; + } +} diff --git a/includes/api/query/ApiQueryAllUsers.php b/includes/api/query/ApiQueryAllUsers.php new file mode 100644 index 0000000000..d853d46693 --- /dev/null +++ b/includes/api/query/ApiQueryAllUsers.php @@ -0,0 +1,211 @@ +@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'); +} + +/** + * Query module to enumerate all registered users. + * + * @addtogroup API + */ +class ApiQueryAllUsers extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'au'); + } + + public function execute() { + $db = $this->getDB(); + $params = $this->extractRequestParams(); + + $prop = $params['prop']; + if (!is_null($prop)) { + $prop = array_flip($prop); + $fld_editcount = isset($prop['editcount']); + $fld_groups = isset($prop['groups']); + $fld_registration = isset($prop['registration']); + } else { + $fld_editcount = $fld_groups = $fld_registration = false; + } + + $limit = $params['limit']; + $tables = $db->tableName('user'); + + if( !is_null( $params['from'] ) ) + $this->addWhere( 'user_name >= ' . $db->addQuotes( self::keyToTitle( $params['from'] ) ) ); + + if( isset( $params['prefix'] ) ) + $this->addWhere( 'user_name LIKE "' . $db->escapeLike( self::keyToTitle( $params['prefix'] ) ) . '%"' ); + + if (!is_null($params['group'])) { + // Filter only users that belong to a given group + $tblName = $db->tableName('user_groups'); + $tables = "$tables INNER JOIN $tblName ug1 ON ug1.ug_user=user_id"; + $this->addWhereFld('ug1.ug_group', $params['group']); + } + + if ($fld_groups) { + // Show the groups the given users belong to + // request more than needed to avoid not getting all rows that belong to one user + $groupCount = count(User::getAllGroups()); + $sqlLimit = $limit+$groupCount+1; + + $tblName = $db->tableName('user_groups'); + $tables = "$tables LEFT JOIN $tblName ug2 ON ug2.ug_user=user_id"; + $this->addFields('ug2.ug_group ug_group2'); + } else { + $sqlLimit = $limit+1; + } + + if ($fld_registration) + $this->addFields('user_registration'); + + $this->addOption('LIMIT', $sqlLimit); + $this->addTables($tables); + + $this->addFields('user_name'); + $this->addFieldsIf('user_editcount', $fld_editcount); + + $this->addOption('ORDER BY', 'user_name'); + + $res = $this->select(__METHOD__); + + $data = array (); + $count = 0; + $lastUserData = false; + $lastUser = false; + $result = $this->getResult(); + + // + // This loop keeps track of the last entry. + // For each new row, if the new row is for different user then the last, the last entry is added to results. + // Otherwise, the group of the new row is appended to the last entry. + // The setContinue... is more complex because of this, and takes into account the higher sql limit + // to make sure all rows that belong to the same user are received. + // + while (true) { + + $row = $db->fetchObject($res); + $count++; + + if (!$row || $lastUser != $row->user_name) { + // Save the last pass's user data + if (is_array($lastUserData)) + $data[] = $lastUserData; + + // No more rows left + if (!$row) + break; + + if ($count > $limit) { + // We've reached the one extra which shows that there are additional pages to be had. Stop here... + $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->user_name)); + break; + } + + // Record new user's data + $lastUser = $row->user_name; + $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); + + } + + if ($sqlLimit == $count) { + // BUG! database contains group name that User::getAllGroups() does not return + // TODO: should handle this more gracefully + ApiBase :: dieDebug(__METHOD__, + 'MediaWiki configuration error: the database contains more user groups than known to User::getAllGroups() function'); + } + + // Add user's group info + if ($fld_groups && !is_null($row->ug_group2)) { + $lastUserData['groups'][] = $row->ug_group2; + $result->setIndexedTagName($lastUserData['groups'], 'g'); + } + } + + $db->freeResult($res); + + $result->setIndexedTagName($data, 'u'); + $result->addValue('query', $this->getModuleName(), $data); + } + + protected function getAllowedParams() { + return array ( + 'from' => null, + 'prefix' => null, + 'group' => array( + ApiBase :: PARAM_TYPE => User::getAllGroups() + ), + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'editcount', + 'groups', + 'registration', + ) + ), + '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 + ) + ); + } + + protected function getParamDescription() { + return array ( + 'from' => 'The user name to start enumerating from.', + 'prefix' => 'Search for all page titles that begin with this value.', + 'group' => 'Limit users to a given group name', + 'prop' => array( + 'What pieces of information to include.', + '`groups` property uses more server resources and may return fewer results than the limit.'), + 'limit' => 'How many total user names to return.', + ); + } + + protected function getDescription() { + return 'Enumerate all registered users'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=allusers&aufrom=Y', + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryAllUsers.php 26953 2007-10-26 03:48:58Z amidaniel $'; + } +} diff --git a/includes/api/query/ApiQueryAllmessages.php b/includes/api/query/ApiQueryAllmessages.php new file mode 100644 index 0000000000..adfe5656e2 --- /dev/null +++ b/includes/api/query/ApiQueryAllmessages.php @@ -0,0 +1,120 @@ +@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(); + + //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( null, $this->getModuleName(), $messages_out ); + } + + protected function getAllowedParams() { + return array ( + 'messages' => array ( + ApiBase :: PARAM_DFLT => '*', + ), + 'filter' => array(), + ); + } + + protected function getParamDescription() { + return array ( + 'messages' => 'Which messages to output. "*" means all messages', + 'filter' => 'Return only messages that contains specified string', + ); + } + + protected 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', + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryAllmessages.php 28027 2007-12-01 17:04:13Z vasilievvv $'; + } +} diff --git a/includes/api/query/ApiQueryAllpages.php b/includes/api/query/ApiQueryAllpages.php new file mode 100644 index 0000000000..1af3d2a722 --- /dev/null +++ b/includes/api/query/ApiQueryAllpages.php @@ -0,0 +1,234 @@ +@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'); +} + +/** + * Query module to enumerate all available pages. + * + * @addtogroup API + */ +class ApiQueryAllpages extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'ap'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + if ($resultPageSet->isResolvingRedirects()) + $this->dieUsage('Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator', 'params'); + + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + $db = $this->getDB(); + + $params = $this->extractRequestParams(); + + // Page filters + if (!$this->addWhereIf('page_is_redirect = 1', $params['filterredir'] === 'redirects')) + $this->addWhereIf('page_is_redirect = 0', $params['filterredir'] === 'nonredirects'); + $this->addWhereFld('page_namespace', $params['namespace']); + if (!is_null($params['from'])) + $this->addWhere('page_title>=' . $db->addQuotes(ApiQueryBase :: titleToKey($params['from']))); + if (isset ($params['prefix'])) + $this->addWhere("page_title LIKE '" . $db->escapeLike(ApiQueryBase :: titleToKey($params['prefix'])) . "%'"); + + $forceNameTitleIndex = true; + if (isset ($params['minsize'])) { + $this->addWhere('page_len>=' . intval($params['minsize'])); + $forceNameTitleIndex = false; + } + + if (isset ($params['maxsize'])) { + $this->addWhere('page_len<=' . intval($params['maxsize'])); + $forceNameTitleIndex = false; + } + + // Page protection filtering + if (isset ($params['prtype'])) { + $this->addTables('page_restrictions'); + $this->addWhere('page_id=pr_page'); + $this->addWhere('pr_expiry>' . $db->addQuotes($db->timestamp())); + $this->addWhereFld('pr_type', $params['prtype']); + + $prlevel = $params['prlevel']; + if (!is_null($prlevel) && $prlevel != '' && $prlevel != '*') + $this->addWhereFld('pr_level', $prlevel); + + $this->addOption('DISTINCT'); + + $forceNameTitleIndex = false; + + } else if (isset ($params['prlevel'])) { + $this->dieUsage('prlevel may not be used without prtype', 'params'); + } + + $this->addTables('page'); + if ($forceNameTitleIndex) + $this->addOption('USE INDEX', 'name_title'); + + + if (is_null($resultPageSet)) { + $this->addFields(array ( + 'page_id', + 'page_namespace', + 'page_title' + )); + } else { + $this->addFields($resultPageSet->getPageTableFields()); + } + + $limit = $params['limit']; + $this->addOption('LIMIT', $limit+1); + $this->addOption('ORDER BY', 'page_namespace, page_title' . + ($params['dir'] == 'ZtoA' ? ' DESC' : '')); + + $res = $this->select(__METHOD__); + + $data = array (); + $count = 0; + 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... + // TODO: Security issue - if the user has no right to view next title, it will still be shown + $this->setContinueEnumParameter('from', ApiQueryBase :: keyToTitle($row->page_title)); + break; + } + + if (is_null($resultPageSet)) { + $title = Title :: makeTitle($row->page_namespace, $row->page_title); + $data[] = array( + 'pageid' => intval($row->page_id), + 'ns' => intval($title->getNamespace()), + 'title' => $title->getPrefixedText()); + } else { + $resultPageSet->processDbRow($row); + } + } + $db->freeResult($res); + + if (is_null($resultPageSet)) { + $result = $this->getResult(); + $result->setIndexedTagName($data, 'p'); + $result->addValue('query', $this->getModuleName(), $data); + } + } + + protected function getAllowedParams() { + global $wgRestrictionTypes, $wgRestrictionLevels; + + return array ( + 'from' => null, + 'prefix' => null, + 'namespace' => array ( + ApiBase :: PARAM_DFLT => 0, + ApiBase :: PARAM_TYPE => 'namespace', + ), + 'filterredir' => array ( + ApiBase :: PARAM_DFLT => 'all', + ApiBase :: PARAM_TYPE => array ( + 'all', + 'redirects', + 'nonredirects' + ) + ), + 'minsize' => array ( + ApiBase :: PARAM_TYPE => 'integer', + ), + 'maxsize' => array ( + ApiBase :: PARAM_TYPE => 'integer', + ), + '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, + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ), + 'dir' => array ( + ApiBase :: PARAM_DFLT => 'AtoZ', + ApiBase :: PARAM_TYPE => array ( + 'AtoZ', + 'ZtoA' + ) + ) + ); + } + + protected 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)', + 'limit' => 'How many total pages to return.' + ); + } + + protected function getDescription() { + return 'Enumerate all pages sequentially in a given namespace'; + } + + protected function getExamples() { + return array ( + 'Simple Use', + ' Show a list of pages starting at the letter "B"', + ' api.php?action=query&list=allpages&apfrom=B', + 'Using as Generator', + ' Show info about 4 pages starting at the letter "T"', + ' api.php?action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info', + ' Show content of first 2 non-redirect pages begining at "Re"', + ' api.php?action=query&generator=allpages&gaplimit=2&gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryAllpages.php 26725 2007-10-15 13:50:43Z catrope $'; + } +} + diff --git a/includes/api/query/ApiQueryBacklinks.php b/includes/api/query/ApiQueryBacklinks.php new file mode 100644 index 0000000000..ba6dccfefe --- /dev/null +++ b/includes/api/query/ApiQueryBacklinks.php @@ -0,0 +1,393 @@ +@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"); +} + +/** + * This is three-in-one module to query: + * * backlinks - links pointing to the given page, + * * embeddedin - what pages transclude the given page within themselves, + * * imageusage - what pages use the given image + * + * @addtogroup API + */ +class ApiQueryBacklinks extends ApiQueryGeneratorBase { + + private $params, $rootTitle, $contRedirs, $contLevel, $contTitle, $contID; + + // output element name, database column field prefix, database table + private $backlinksSettings = array ( + 'backlinks' => array ( + 'code' => 'bl', + 'prefix' => 'pl', + 'linktbl' => 'pagelinks' + ), + 'embeddedin' => array ( + 'code' => 'ei', + 'prefix' => 'tl', + 'linktbl' => 'templatelinks' + ), + 'imageusage' => array ( + 'code' => 'iu', + 'prefix' => 'il', + 'linktbl' => 'imagelinks' + ) + ); + + public function __construct($query, $moduleName) { + $code = $prefix = $linktbl = null; + extract($this->backlinksSettings[$moduleName]); + + parent :: __construct($query, $moduleName, $code); + $this->bl_ns = $prefix . '_namespace'; + $this->bl_from = $prefix . '_from'; + $this->bl_tables = array ( + $linktbl, + 'page' + ); + $this->bl_code = $code; + + $this->hasNS = $moduleName !== 'imageusage'; + if ($this->hasNS) { + $this->bl_title = $prefix . '_title'; + $this->bl_sort = "{$this->bl_ns}, {$this->bl_title}, {$this->bl_from}"; + $this->bl_fields = array ( + $this->bl_ns, + $this->bl_title + ); + } else { + $this->bl_title = $prefix . '_to'; + $this->bl_sort = "{$this->bl_title}, {$this->bl_from}"; + $this->bl_fields = array ( + $this->bl_title + ); + } + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + $this->params = $this->extractRequestParams(); + + $redirect = $this->params['redirect']; + if ($redirect) + $this->dieDebug('Redirect has not been implemented', 'notimplemented'); + + $this->processContinue(); + + $this->addFields($this->bl_fields); + if (is_null($resultPageSet)) + $this->addFields(array ( + 'page_id', + 'page_namespace', + 'page_title' + )); + else + $this->addFields($resultPageSet->getPageTableFields()); // will include page_id + + $this->addTables($this->bl_tables); + $this->addWhere($this->bl_from . '=page_id'); + + if ($this->hasNS) + $this->addWhereFld($this->bl_ns, $this->rootTitle->getNamespace()); + $this->addWhereFld($this->bl_title, $this->rootTitle->getDBkey()); + $this->addWhereFld('page_namespace', $this->params['namespace']); + + if($this->params['filterredir'] == 'redirects') + $this->addWhereFld('page_is_redirect', 1); + if($this->params['filterredir'] == 'nonredirects') + $this->addWhereFld('page_is_redirect', 0); + + $limit = $this->params['limit']; + $this->addOption('LIMIT', $limit +1); + $this->addOption('ORDER BY', $this->bl_sort); + + $db = $this->getDB(); + if (!is_null($this->params['continue'])) { + $plfrm = intval($this->contID); + if ($this->contLevel == 0) { + // For the first level, there is only one target title, so no need for complex filtering + $this->addWhere($this->bl_from . '>=' . $plfrm); + } else { + $ns = $this->contTitle->getNamespace(); + $t = $db->addQuotes($this->contTitle->getDBkey()); + $whereWithoutNS = "{$this->bl_title}>$t OR ({$this->bl_title}=$t AND {$this->bl_from}>=$plfrm))"; + + if ($this->hasNS) + $this->addWhere("{$this->bl_ns}>$ns OR ({$this->bl_ns}=$ns AND ($whereWithoutNS)"); + else + $this->addWhere($whereWithoutNS); + } + } + + $res = $this->select(__METHOD__); + + $count = 0; + $data = array (); + 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... + if ($redirect) { + $ns = $row-> { $this->bl_ns }; + $t = $row-> { $this->bl_title }; + $continue = $this->getContinueRedirStr(false, 0, $ns, $t, $row->page_id); + } else + $continue = $this->getContinueStr($row->page_id); + // TODO: Security issue - if the user has no right to view next title, it will still be shown + $this->setContinueEnumParameter('continue', $continue); + break; + } + + if (is_null($resultPageSet)) { + $vals = $this->extractRowInfo($row); + if ($vals) + $data[] = $vals; + } else { + $resultPageSet->processDbRow($row); + } + } + $db->freeResult($res); + + if (is_null($resultPageSet)) { + $result = $this->getResult(); + $result->setIndexedTagName($data, $this->bl_code); + $result->addValue('query', $this->getModuleName(), $data); + } + } + + private function extractRowInfo($row) { + + $vals = array(); + $vals['pageid'] = intval($row->page_id); + ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle($row->page_namespace, $row->page_title)); + + return $vals; + } + + protected function processContinue() { + $pageSet = $this->getPageSet(); + $count = $pageSet->getTitleCount(); + + if (!is_null($this->params['continue'])) { + $this->parseContinueParam(); + + // Skip all completed links + + } else { + $title = $this->params['title']; + if (!is_null($title)) { + $this->rootTitle = Title :: newFromText($title); + } else { // This case is obsolete. Will support this for a while + if ($count !== 1) + $this->dieUsage("The {$this->getModuleName()} query requires one title to start", 'bad_title_count'); + $this->rootTitle = current($pageSet->getTitles()); // only one title there + $this->setWarning('Using titles parameter is obsolete for this list. Use ' . $this->encodeParamName('title') . ' instead.'); + } + } + + // only image titles are allowed for the root + if (!$this->hasNS && $this->rootTitle->getNamespace() !== NS_IMAGE) + $this->dieUsage("The title for {$this->getModuleName()} query must be an image", 'bad_image_title'); + } + + protected function parseContinueParam() { + $continueList = explode('|', $this->params['continue']); + if ($this->params['redirect']) { + // + // expected redirect-mode parameter: + // ns|db_key|step|level|ns|db_key|id + // ns+db_key -- the root title + // step = 1 or 2 - which step to continue from - 1-titles, 2-redirects + // level -- how many levels to follow before starting enumerating. + // if level > 0 -- ns+title to continue from, otherwise skip these + // id = last page_id to continue from + // + if (count($continueList) > 4) { + $rootNs = intval($continueList[0]); + if (($rootNs !== 0 || $continueList[0] === '0') && !empty ($continueList[1])) { + $this->rootTitle = Title :: makeTitleSafe($rootNs, $continueList[1]); + if ($this->rootTitle) { + + $step = intval($continueList[2]); + if ($step === 1 || $step === 2) { + $this->contRedirs = ($step === 2); + + $level = intval($continueList[3]); + if ($level !== 0 || $continueList[3] === '0') { + $this->contLevel = $level; + + if ($level === 0) { + if (count($continueList) === 5) { + $contID = intval($continueList[4]); + if ($contID !== 0 || $continueList[4] === '0') { + $this->contID = $contID; + return; // done + } + } + } else { + if (count($continueList) === 7) { + $contNs = intval($continueList[4]); + if (($contNs !== 0 || $continueList[4] === '0') && !empty ($continueList[5])) { + $this->contTitle = Title :: makeTitleSafe($contNs, $continueList[5]); + + $contID = intval($continueList[6]); + if ($contID !== 0 || $continueList[6] === '0') { + $this->contID = $contID; + return; // done + } + } + } + } + } + } + } + } + } + } else { + // + // expected non-redirect-mode parameter: + // ns|db_key|id + // ns+db_key -- the root title + // id = last page_id to continue from + // + if (count($continueList) === 3) { + $rootNs = intval($continueList[0]); + if (($rootNs !== 0 || $continueList[0] === '0') && !empty ($continueList[1])) { + $this->rootTitle = Title :: makeTitleSafe($rootNs, $continueList[1]); + if ($this->rootTitle) { + + $contID = intval($continueList[2]); + if ($contID !== 0) { + $this->contID = $contID; + return; // done + } + } + } + } + } + + $this->dieUsage("Invalid continue param. You should pass the original value returned by the previous query", "_badcontinue"); + } + + protected function getContinueStr($lastPageID) { + return $this->rootTitle->getNamespace() . + '|' . $this->rootTitle->getDBkey() . + '|' . $lastPageID; + } + + protected function getContinueRedirStr($isRedirPhase, $level, $ns, $title, $lastPageID) { + return $this->rootTitle->getNamespace() . + '|' . $this->rootTitle->getDBkey() . + '|' . ($isRedirPhase ? 1 : 2) . + '|' . $level . + ($level > 0 ? ('|' . $ns . '|' . $title) : '') . + '|' . $lastPageID; + } + + protected function getAllowedParams() { + + return array ( + 'title' => null, + 'continue' => null, + 'namespace' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => 'namespace' + ), + 'filterredir' => array( + ApiBase :: PARAM_DFLT => 'all', + ApiBase :: PARAM_TYPE => array( + 'all', + 'redirects', + 'nonredirects' + ) + ), + 'redirect' => false, + '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 + ) + ); + } + + protected 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.', + 'namespace' => 'The namespace to enumerate.', + 'filterredir' => 'How to filter for redirects', + 'redirect' => 'If linking page is a redirect, find all pages that link to that redirect (not implemented)', + 'limit' => 'How many total pages to return.' + ); + } + + protected function getDescription() { + switch ($this->getModuleName()) { + case 'backlinks' : + return 'Find all pages that link to the given page'; + case 'embeddedin' : + return 'Find all pages that embed (transclude) the given title'; + case 'imageusage' : + return 'Find all pages that use the given image title.'; + default : + ApiBase :: dieDebug(__METHOD__, 'Unknown module name'); + } + } + + protected function getExamples() { + static $examples = array ( + 'backlinks' => array ( + "api.php?action=query&list=backlinks&bltitle=Main%20Page", + "api.php?action=query&generator=backlinks&gbltitle=Main%20Page&prop=info" + ), + 'embeddedin' => array ( + "api.php?action=query&list=embeddedin&eititle=Template:Stub", + "api.php?action=query&generator=embeddedin&geititle=Template:Stub&prop=info" + ), + 'imageusage' => array ( + "api.php?action=query&list=imageusage&iutitle=Image:Albert%20Einstein%20Head.jpg", + "api.php?action=query&generator=imageusage&giutitle=Image:Albert%20Einstein%20Head.jpg&prop=info" + ) + ); + + return $examples[$this->getModuleName()]; + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryBacklinks.php 27562 2007-11-16 22:50:59Z brion $'; + } +} + diff --git a/includes/api/query/ApiQueryBase.php b/includes/api/query/ApiQueryBase.php new file mode 100644 index 0000000000..28adb41554 --- /dev/null +++ b/includes/api/query/ApiQueryBase.php @@ -0,0 +1,265 @@ +@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'); +} + +/** + * This is a base class for all Query modules. + * It provides some common functionality such as constructing various SQL queries. + * + * @addtogroup API + */ +abstract class ApiQueryBase extends ApiBase { + + private $mQueryModule, $mDb, $tables, $where, $fields, $options; + + public function __construct($query, $moduleName, $paramPrefix = '') { + parent :: __construct($query->getMain(), $moduleName, $paramPrefix); + $this->mQueryModule = $query; + $this->mDb = null; + $this->resetQueryParams(); + } + + protected function resetQueryParams() { + $this->tables = array (); + $this->where = array (); + $this->fields = array (); + $this->options = array (); + } + + protected function addTables($tables, $alias = null) { + if (is_array($tables)) { + if (!is_null($alias)) + ApiBase :: dieDebug(__METHOD__, 'Multiple table aliases not supported'); + $this->tables = array_merge($this->tables, $tables); + } else { + if (!is_null($alias)) + $tables = $this->getDB()->tableName($tables) . ' ' . $alias; + $this->tables[] = $tables; + } + } + + protected function addFields($value) { + if (is_array($value)) + $this->fields = array_merge($this->fields, $value); + else + $this->fields[] = $value; + } + + protected function addFieldsIf($value, $condition) { + if ($condition) { + $this->addFields($value); + return true; + } + return false; + } + + protected function addWhere($value) { + if (is_array($value)) + $this->where = array_merge($this->where, $value); + else + $this->where[] = $value; + } + + protected function addWhereIf($value, $condition) { + if ($condition) { + $this->addWhere($value); + return true; + } + return false; + } + + protected function addWhereFld($field, $value) { + if (!is_null($value)) + $this->where[$field] = $value; + } + + protected function addWhereRange($field, $dir, $start, $end) { + $isDirNewer = ($dir === 'newer'); + $after = ($isDirNewer ? '>=' : '<='); + $before = ($isDirNewer ? '<=' : '>='); + $db = $this->getDB(); + + if (!is_null($start)) + $this->addWhere($field . $after . $db->addQuotes($start)); + + if (!is_null($end)) + $this->addWhere($field . $before . $db->addQuotes($end)); + + $this->addOption('ORDER BY', $field . ($isDirNewer ? '' : ' DESC')); + } + + protected function addOption($name, $value = null) { + if (is_null($value)) + $this->options[] = $name; + else + $this->options[$name] = $value; + } + + protected function select($method) { + + // getDB has its own profileDBIn/Out calls + $db = $this->getDB(); + + $this->profileDBIn(); + $res = $db->select($this->tables, $this->fields, $this->where, $method, $this->options); + $this->profileDBOut(); + + return $res; + } + + public static function addTitleInfo(&$arr, $title, $prefix='') { + $arr[$prefix . 'ns'] = intval($title->getNamespace()); + $arr[$prefix . 'title'] = $title->getPrefixedText(); + } + + /** + * Override this method to request extra fields from the pageSet + * using $pageSet->requestField('fieldName') + */ + public function requestExtraData($pageSet) { + } + + /** + * Get the main Query module + */ + public function getQuery() { + return $this->mQueryModule; + } + + /** + * Add sub-element under the page element with the given pageId. + */ + protected function addPageSubItems($pageId, $data) { + $result = $this->getResult(); + $result->setIndexedTagName($data, $this->getModulePrefix()); + $result->addValue(array ('query', 'pages', intval($pageId)), + $this->getModuleName(), + $data); + } + + protected function setContinueEnumParameter($paramName, $paramValue) { + + $paramName = $this->encodeParamName($paramName); + $msg = array( $paramName => $paramValue ); + +// This is an alternative continue format as a part of the URL string +// ApiResult :: setContent($msg, $paramName . '=' . urlencode($paramValue)); + + $this->getResult()->addValue('query-continue', $this->getModuleName(), $msg); + } + + /** + * Get the Query database connection (readonly) + */ + protected function getDB() { + if (is_null($this->mDb)) + $this->mDb = $this->getQuery()->getDB(); + return $this->mDb; + } + + /** + * Selects the query database connection with the given name. + * If no such connection has been requested before, it will be created. + * Subsequent calls with the same $name will return the same connection + * as the first, regardless of $db or $groups new values. + */ + public function selectNamedDB($name, $db, $groups) { + $this->mDb = $this->getQuery()->getNamedDB($name, $db, $groups); + } + + /** + * Get the PageSet object to work on + * @return ApiPageSet data + */ + protected function getPageSet() { + return $this->getQuery()->getPageSet(); + } + + /** + * This is a very simplistic utility function + * to convert a non-namespaced title string to a db key. + * It will replace all ' ' with '_' + */ + public static function titleToKey($title) { + return str_replace(' ', '_', $title); + } + + public static function keyToTitle($key) { + return str_replace('_', ' ', $key); + } + + public function getTokenFlag($tokenArr, $action) { + if (in_array($action, $tokenArr)) { + global $wgUser; + if ($wgUser->isAllowed($action)) + return true; + else + $this->dieUsage("Action '$action' is not allowed for the current user", 'permissiondenied'); + } + return false; + } + + public static function getBaseVersion() { + return __CLASS__ . ': $Id: ApiQueryBase.php 24533 2007-08-01 22:46:22Z yurik $'; + } +} + +/** + * @addtogroup API + */ +abstract class ApiQueryGeneratorBase extends ApiQueryBase { + + private $mIsGenerator; + + public function __construct($query, $moduleName, $paramPrefix = '') { + parent :: __construct($query, $moduleName, $paramPrefix); + $this->mIsGenerator = false; + } + + public function setGeneratorMode() { + $this->mIsGenerator = true; + } + + /** + * Overrides base class to prepend 'g' to every generator parameter + */ + public function encodeParamName($paramName) { + if ($this->mIsGenerator) + return 'g' . parent :: encodeParamName($paramName); + else + return parent :: encodeParamName($paramName); + } + + /** + * Execute this module as a generator + * @param $resultPageSet PageSet: All output should be appended to this object + */ + public abstract function executeGenerator($resultPageSet); +} + diff --git a/includes/api/query/ApiQueryBlocks.php b/includes/api/query/ApiQueryBlocks.php new file mode 100644 index 0000000000..a1d32dc894 --- /dev/null +++ b/includes/api/query/ApiQueryBlocks.php @@ -0,0 +1,241 @@ +.@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) + { + $block['user'] = $row->ipb_address; + $block['userid'] = $row->ipb_user; + } + if($fld_by) + { + $block['by'] = $row->user_name; + $block['byuserid'] = $row->ipb_by; + } + if($fld_timestamp) + $block['timestamp'] = wfTimestamp(TS_ISO_8601, $row->ipb_timestamp); + if($fld_expiry) + $block['expiry'] = Block::decodeExpiry($row->ipb_expiry, TS_ISO_8601); + 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); + } + + protected 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 + ) + ); + } + + protected 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', + ); + } + + protected function getDescription() { + return 'List all blocked users and IP addresses.'; + } + + protected function getExamples() { + return array ( + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryBlocks.php 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/query/ApiQueryCategories.php b/includes/api/query/ApiQueryCategories.php new file mode 100644 index 0000000000..42bc1c3847 --- /dev/null +++ b/includes/api/query/ApiQueryCategories.php @@ -0,0 +1,157 @@ +@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 module to enumerate categories the set of pages belong to. + * + * @addtogroup API + */ +class ApiQueryCategories extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'cl'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + if ($this->getPageSet()->getGoodTitleCount() == 0) + return; // nothing to do + + $params = $this->extractRequestParams(); + $prop = $params['prop']; + + $this->addFields(array ( + 'cl_from', + 'cl_to' + )); + + $fld_sortkey = false; + if (!is_null($prop)) { + foreach($prop as $p) { + switch ($p) { + case 'sortkey': + $this->addFields('cl_sortkey'); + $fld_sortkey = true; + break; + default : + ApiBase :: dieDebug(__METHOD__, "Unknown prop=$p"); + } + } + } + + $this->addTables('categorylinks'); + $this->addWhereFld('cl_from', array_keys($this->getPageSet()->getGoodTitles())); + $this->addOption('ORDER BY', "cl_from, cl_to"); + + $db = $this->getDB(); + $res = $this->select(__METHOD__); + + if (is_null($resultPageSet)) { + + $data = array(); + $lastId = 0; // database has no ID 0 + while ($row = $db->fetchObject($res)) { + if ($lastId != $row->cl_from) { + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + $data = array(); + } + $lastId = $row->cl_from; + } + + $title = Title :: makeTitle(NS_CATEGORY, $row->cl_to); + + $vals = array(); + ApiQueryBase :: addTitleInfo($vals, $title); + if ($fld_sortkey) + $vals['sortkey'] = $row->cl_sortkey; + + $data[] = $vals; + } + + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + } + + } else { + + $titles = array(); + while ($row = $db->fetchObject($res)) { + $titles[] = Title :: makeTitle(NS_CATEGORY, $row->cl_to); + } + $resultPageSet->populateFromTitles($titles); + } + + $db->freeResult($res); + } + + protected function getAllowedParams() { + return array ( + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'sortkey', + ) + ) + ); + } + + protected function getParamDescription() { + return array ( + 'prop' => 'Which additional properties to get for each category.', + ); + } + + protected function getDescription() { + return 'List all categories the page(s) belong to'; + } + + protected function getExamples() { + return array ( + "Get a list of categories [[Albert Einstein]] belongs to:", + " api.php?action=query&prop=categories&titles=Albert%20Einstein", + "Get information about all categories used in the [[Albert Einstein]]:", + " api.php?action=query&generator=categories&titles=Albert%20Einstein&prop=info" + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryCategories.php 24092 2007-07-14 19:04:31Z yurik $'; + } +} + diff --git a/includes/api/query/ApiQueryCategoryMembers.php b/includes/api/query/ApiQueryCategoryMembers.php new file mode 100644 index 0000000000..2f09d96ef9 --- /dev/null +++ b/includes/api/query/ApiQueryCategoryMembers.php @@ -0,0 +1,246 @@ +@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 module to enumerate pages that belong to a category. + * + * @addtogroup API + */ +class ApiQueryCategoryMembers extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'cm'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + $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'); + + $prop = array_flip($params['prop']); + $fld_ids = isset($prop['ids']); + $fld_title = isset($prop['title']); + $fld_sortkey = isset($prop['sortkey']); + $fld_timestamp = isset($prop['timestamp']); + + if (is_null($resultPageSet)) { + $this->addFields(array('cl_from', 'cl_sortkey', 'page_namespace', 'page_title')); + $this->addFieldsIf('page_id', $fld_ids); + } else { + $this->addFields($resultPageSet->getPageTableFields()); // will include page_ id, ns, title + $this->addFields(array('cl_from', 'cl_sortkey')); + } + + $this->addFieldsIf('cl_timestamp', $fld_timestamp); + $this->addTables(array('page','categorylinks')); // must be in this order for 'USE INDEX' + // Not needed after bug 10280 is applied to servers + if($params['sort'] == 'timestamp') + { + $this->addOption('USE INDEX', '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' . ($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']); + + $limit = $params['limit']; + $this->addOption('LIMIT', $limit +1); + + $db = $this->getDB(); + + $data = array (); + $count = 0; + $lastSortKey = null; + $res = $this->select(__METHOD__); + 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... + // TODO: Security issue - if the user has no right to view next title, it will still be shown + $this->setContinueEnumParameter('continue', $this->getContinueStr($row, $lastSortKey)); + break; + } + + $lastSortKey = $row->cl_sortkey; // detect duplicate sortkeys + + if (is_null($resultPageSet)) { + $vals = array(); + if ($fld_ids) + $vals['pageid'] = intval($row->page_id); + if ($fld_title) { + $title = Title :: makeTitle($row->page_namespace, $row->page_title); + $vals['ns'] = intval($title->getNamespace()); + $vals['title'] = $title->getPrefixedText(); + } + if ($fld_sortkey) + $vals['sortkey'] = $row->cl_sortkey; + if ($fld_timestamp) + $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->cl_timestamp); + $data[] = $vals; + } else { + $resultPageSet->processDbRow($row); + } + } + $db->freeResult($res); + + if (is_null($resultPageSet)) { + $this->getResult()->setIndexedTagName($data, 'cm'); + $this->getResult()->addValue('query', $this->getModuleName(), $data); + } + } + + private function getContinueStr($row, $lastSortKey) { + $ret = $row->cl_sortkey . '|'; + if ($row->cl_sortkey == $lastSortKey) // duplicate sort key, add cl_from + $ret .= $row->cl_from; + return $ret; + } + + /** + * Add DB WHERE clause to continue previous query based on 'continue' parameter + */ + private function setContinuation($continue) { + if (is_null($continue)) + return; // This is not a continuation request + + $continueList = explode('|', $continue); + $hasError = count($continueList) != 2; + $from = 0; + if (!$hasError && strlen($continueList[1]) > 0) { + $from = intval($continueList[1]); + $hasError = ($from == 0); + } + + if ($hasError) + $this->dieUsage("Invalid continue param. You should pass the original value returned by the previous query", "badcontinue"); + + $encSortKey = $this->getDB()->addQuotes($continueList[0]); + $encFrom = $this->getDB()->addQuotes($from); + + if ($from != 0) { + // Duplicate sort key continue + $this->addWhere( "cl_sortkey>$encSortKey OR (cl_sortkey=$encSortKey AND cl_from>=$encFrom)" ); + } else { + $this->addWhere( "cl_sortkey>=$encSortKey" ); + } + } + + protected function getAllowedParams() { + return array ( + 'category' => null, + 'prop' => array ( + ApiBase :: PARAM_DFLT => 'ids|title', + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'ids', + 'title', + 'sortkey', + 'timestamp', + ) + ), + 'namespace' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => 'namespace', + ), + 'continue' => null, + 'limit' => array ( + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_DFLT => 10, + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ), + 'sort' => array( + ApiBase :: PARAM_DFLT => 'sortkey', + ApiBase :: PARAM_TYPE => array( + 'sortkey', + 'timestamp' + ) + ), + 'dir' => array( + ApiBase :: PARAM_DFLT => 'asc', + ApiBase :: PARAM_TYPE => array( + 'asc', + 'desc' + ) + ) + ); + } + + protected function getParamDescription() { + return array ( + 'category' => 'Which category to enumerate (required)', + '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', + 'continue' => 'For large categories, give the value retured from previous query', + 'limit' => 'The maximum number of pages to return.', + ); + } + + protected 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", + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryCategoryMembers.php 25726 2007-09-10 14:17:33Z catrope $'; + } +} + diff --git a/includes/api/query/ApiQueryDeletedrevs.php b/includes/api/query/ApiQueryDeletedrevs.php new file mode 100644 index 0000000000..ce5a7758a1 --- /dev/null +++ b/includes/api/query/ApiQueryDeletedrevs.php @@ -0,0 +1,230 @@ +.@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(); + $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 limits and stricter restrictions + if(!$wgUser->isAllowed('undelete')) + $this->dieUsage('You don\'t have permission to view deleted revision content', 'permissiondenied'); + $userMax = ApiBase :: LIMIT_SML1; + $botMax = ApiBase :: LIMIT_SML2; + $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); + } + + protected 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 + ) + ); + } + + protected 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' + ); + } + + protected 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 28209 2007-12-06 16:06:22Z vasilievvv $'; + } +} diff --git a/includes/api/query/ApiQueryExtLinksUsage.php b/includes/api/query/ApiQueryExtLinksUsage.php new file mode 100644 index 0000000000..385ae65b90 --- /dev/null +++ b/includes/api/query/ApiQueryExtLinksUsage.php @@ -0,0 +1,200 @@ +@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'); +} + +/** + * @addtogroup API + */ +class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'eu'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + $params = $this->extractRequestParams(); + + $protocol = $params['protocol']; + $query = $params['query']; + if (is_null($query)) + $this->dieUsage('Missing required query parameter', 'params'); + + // Find the right prefix + global $wgUrlProtocols; + foreach ($wgUrlProtocols as $p) { + if( substr( $p, 0, strlen( $protocol ) ) === $protocol ) { + $protocol = $p; + break; + } + } + + $likeQuery = LinkFilter::makeLike($query , $protocol); + if (!$likeQuery) + $this->dieUsage('Invalid query', 'bad_query'); + $likeQuery = substr($likeQuery, 0, strpos($likeQuery,'%')+1); + + $this->addTables(array('page','externallinks')); // must be in this order for 'USE INDEX' + $this->addOption('USE INDEX', 'el_index'); + + $db = $this->getDB(); + $this->addWhere('page_id=el_from'); + $this->addWhere('el_index LIKE ' . $db->addQuotes( $likeQuery )); + $this->addWhereFld('page_namespace', $params['namespace']); + + $prop = array_flip($params['prop']); + $fld_ids = isset($prop['ids']); + $fld_title = isset($prop['title']); + $fld_url = isset($prop['url']); + + if (is_null($resultPageSet)) { + $this->addFields(array ( + 'page_id', + 'page_namespace', + 'page_title' + )); + $this->addFieldsIf('el_to', $fld_url); + } else { + $this->addFields($resultPageSet->getPageTableFields()); + } + + $limit = $params['limit']; + $offset = $params['offset']; + $this->addOption('LIMIT', $limit +1); + if (isset ($offset)) + $this->addOption('OFFSET', $offset); + + $res = $this->select(__METHOD__); + + $data = array (); + $count = 0; + 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... + $this->setContinueEnumParameter('offset', $offset+$limit+1); + break; + } + + if (is_null($resultPageSet)) { + $vals = array(); + if ($fld_ids) + $vals['pageid'] = intval($row->page_id); + if ($fld_title) { + $title = Title :: makeTitle($row->page_namespace, $row->page_title); + $vals['ns'] = intval($title->getNamespace()); + $vals['title'] = $title->getPrefixedText(); + } + if ($fld_url) + $vals['url'] = $row->el_to; + $data[] = $vals; + } else { + $resultPageSet->processDbRow($row); + } + } + $db->freeResult($res); + + if (is_null($resultPageSet)) { + $result = $this->getResult(); + $result->setIndexedTagName($data, $this->getModulePrefix()); + $result->addValue('query', $this->getModuleName(), $data); + } + } + + protected function getAllowedParams() { + global $wgUrlProtocols; + $protocols = array(); + foreach ($wgUrlProtocols as $p) { + $protocols[] = substr($p, 0, strpos($p,':')); + } + + return array ( + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_DFLT => 'ids|title|url', + ApiBase :: PARAM_TYPE => array ( + 'ids', + 'title', + 'url' + ) + ), + 'offset' => array ( + ApiBase :: PARAM_TYPE => 'integer' + ), + 'protocol' => array ( + ApiBase :: PARAM_TYPE => $protocols, + ApiBase :: PARAM_DFLT => 'http', + ), + 'query' => null, + '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 + ) + ); + } + + protected function getParamDescription() { + return array ( + 'prop' => 'What pieces of information to include', + 'offset' => 'Used for paging. Use the value returned for "continue"', + 'protocol' => 'Protocol of the url', + 'query' => 'Search string without protocol. See [[Special:LinkSearch]]', + 'namespace' => 'The page namespace(s) to enumerate.', + 'limit' => 'How many entries to return.' + ); + } + + protected function getDescription() { + return 'Enumerate pages that contain a given URL'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=exturlusage&euquery=www.mediawiki.org' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryExtLinksUsage.php 24694 2007-08-09 08:41:58Z yurik $'; + } +} diff --git a/includes/api/query/ApiQueryExternalLinks.php b/includes/api/query/ApiQueryExternalLinks.php new file mode 100644 index 0000000000..440b31d6f0 --- /dev/null +++ b/includes/api/query/ApiQueryExternalLinks.php @@ -0,0 +1,93 @@ +@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 module to list all external URLs found on a given set of pages. + * + * @addtogroup API + */ +class ApiQueryExternalLinks extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'el'); + } + + public function execute() { + + $this->addFields(array ( + 'el_from', + 'el_to' + )); + + $this->addTables('externallinks'); + $this->addWhereFld('el_from', array_keys($this->getPageSet()->getGoodTitles())); + + $db = $this->getDB(); + $res = $this->select(__METHOD__); + + $data = array(); + $lastId = 0; // database has no ID 0 + while ($row = $db->fetchObject($res)) { + if ($lastId != $row->el_from) { + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + $data = array(); + } + $lastId = $row->el_from; + } + + $entry = array(); + ApiResult :: setContent($entry, $row->el_to); + $data[] = $entry; + } + + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + } + + $db->freeResult($res); + } + + protected function getDescription() { + return 'Returns all external urls (not interwikies) from the given page(s)'; + } + + protected function getExamples() { + return array ( + "Get a list of external links on the [[Main Page]]:", + " api.php?action=query&prop=extlinks&titles=Main%20Page", + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryExternalLinks.php 23819 2007-07-07 03:05:09Z yurik $'; + } +} + diff --git a/includes/api/query/ApiQueryImageInfo.php b/includes/api/query/ApiQueryImageInfo.php new file mode 100644 index 0000000000..5b3002ba93 --- /dev/null +++ b/includes/api/query/ApiQueryImageInfo.php @@ -0,0 +1,164 @@ +@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 get image information and upload history. + * + * @addtogroup API + */ +class ApiQueryImageInfo extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'ii'); + } + + 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']); + $fld_metadata = isset($prop['metadata']); + + $pageIds = $this->getPageSet()->getAllTitlesByNamespace(); + if (!empty($pageIds[NS_IMAGE])) { + foreach ($pageIds[NS_IMAGE] as $dbKey => $pageId) { + + $title = Title :: makeTitle(NS_IMAGE, $dbKey); + $img = wfFindFile($title); + + $data = array(); + if ( !$img ) { + $repository = ''; + } 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); + + if ($fld_metadata) { + $metadata = unserialize($row["{$prefix}_metadata"]); + $vals['metadata'] = $metadata ? $metadata : null; + $this->getResult()->setIndexedTagName_recursive($vals['metadata'], 'meta'); + } + + $data[] = $vals; + + if (!$history) // Stop after the first line. + break; + + $isCur = false; + } + + $img->resetHistory(); + } + + $this->getResult()->addValue(array ('query', 'pages', intval($pageId)), + 'imagerepository', + $repository); + if (!empty($data)) + $this->addPageSubItems($pageId, $data); + } + } + } + + protected function getAllowedParams() { + return array ( + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_DFLT => 'timestamp|user', + ApiBase :: PARAM_TYPE => array ( + 'timestamp', + 'user', + 'comment', + 'url', + 'size', + 'sha1', + 'metadata' + ) + ), + 'history' => false, + ); + } + + protected function getParamDescription() { + return array ( + 'prop' => 'What image information to get.', + 'history' => 'Include upload history', + ); + } + + protected function getDescription() { + return array ( + 'Returns image information and upload history' + ); + } + + 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', + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryImageInfo.php 26855 2007-10-20 18:27:39Z catrope $'; + } +} diff --git a/includes/api/query/ApiQueryImages.php b/includes/api/query/ApiQueryImages.php new file mode 100644 index 0000000000..d64a653b40 --- /dev/null +++ b/includes/api/query/ApiQueryImages.php @@ -0,0 +1,118 @@ +@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"); +} + +/** + * This query adds subelement to all pages with the list of images embedded into those pages. + * + * @addtogroup API + */ +class ApiQueryImages extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'im'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + if ($this->getPageSet()->getGoodTitleCount() == 0) + return; // nothing to do + + $this->addFields(array ( + 'il_from', + 'il_to' + )); + + $this->addTables('imagelinks'); + $this->addWhereFld('il_from', array_keys($this->getPageSet()->getGoodTitles())); + $this->addOption('ORDER BY', "il_from, il_to"); + + $db = $this->getDB(); + $res = $this->select(__METHOD__); + + if (is_null($resultPageSet)) { + + $data = array(); + $lastId = 0; // database has no ID 0 + while ($row = $db->fetchObject($res)) { + if ($lastId != $row->il_from) { + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + $data = array(); + } + $lastId = $row->il_from; + } + + $vals = array(); + ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle(NS_IMAGE, $row->il_to)); + $data[] = $vals; + } + + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + } + + } else { + + $titles = array(); + while ($row = $db->fetchObject($res)) { + $titles[] = Title :: makeTitle(NS_IMAGE, $row->il_to); + } + $resultPageSet->populateFromTitles($titles); + } + + $db->freeResult($res); + } + + protected function getDescription() { + return 'Returns all images contained on the given page(s)'; + } + + protected function getExamples() { + return array ( + "Get a list of images used in the [[Main Page]]:", + " api.php?action=query&prop=images&titles=Main%20Page", + "Get information about all images used in the [[Main Page]]:", + " api.php?action=query&generator=images&titles=Main%20Page&prop=info" + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryImages.php 24092 2007-07-14 19:04:31Z yurik $'; + } +} + diff --git a/includes/api/query/ApiQueryInfo.php b/includes/api/query/ApiQueryInfo.php new file mode 100644 index 0000000000..8f9fc02c07 --- /dev/null +++ b/includes/api/query/ApiQueryInfo.php @@ -0,0 +1,226 @@ +@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 module to show basic page information. + * + * @addtogroup API + */ +class ApiQueryInfo extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'in'); + } + + public function requestExtraData($pageSet) { + $pageSet->requestField('page_restrictions'); + $pageSet->requestField('page_is_redirect'); + $pageSet->requestField('page_is_new'); + $pageSet->requestField('page_counter'); + $pageSet->requestField('page_touched'); + $pageSet->requestField('page_latest'); + $pageSet->requestField('page_len'); + } + + public function execute() { + + global $wgUser; + + $params = $this->extractRequestParams(); + $fld_protection = false; + if(!is_null($params['prop'])) { + $prop = array_flip($params['prop']); + $fld_protection = isset($prop['protection']); + } + if(!is_null($params['token'])) { + $token = $params['token']; + $tok_edit = $this->getTokenFlag($token, 'edit'); + $tok_delete = $this->getTokenFlag($token, 'delete'); + $tok_protect = $this->getTokenFlag($token, 'protect'); + $tok_move = $this->getTokenFlag($token, 'move'); + } + + $pageSet = $this->getPageSet(); + $titles = $pageSet->getGoodTitles(); + $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'); + $pageTouched = $pageSet->getCustomField('page_touched'); + $pageLatest = $pageSet->getCustomField('page_latest'); + $pageLength = $pageSet->getCustomField('page_len'); + + if ($fld_protection && count($titles) > 0) { + $this->addTables('page_restrictions'); + $this->addFields(array('pr_page', 'pr_type', 'pr_level', 'pr_expiry')); + $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 ) + ); + } + $db->freeResult($res); + } + + foreach ( $titles as $pageid => $title ) { + $pageInfo = array ( + 'touched' => wfTimestamp(TS_ISO_8601, $pageTouched[$pageid]), + 'lastrevid' => intval($pageLatest[$pageid]), + 'counter' => intval($pageCounter[$pageid]), + 'length' => intval($pageLength[$pageid]), + ); + + if ($pageIsRedir[$pageid]) + $pageInfo['redirect'] = ''; + + if ($pageIsNew[$pageid]) + $pageInfo['new'] = ''; + + if (!is_null($token)) { + // Currently all tokens are generated the same way, but it might change + if ($tok_edit) + $pageInfo['edittoken'] = $wgUser->editToken(); + if ($tok_delete) + $pageInfo['deletetoken'] = $wgUser->editToken(); + if ($tok_protect) + $pageInfo['protecttoken'] = $wgUser->editToken(); + if ($tok_move) + $pageInfo['movetoken'] = $wgUser->editToken(); + } + + if($fld_protection) { + if (isset($protections[$pageid])) { + $pageInfo['protection'] = $protections[$pageid]; + $result->setIndexedTagName($pageInfo['protection'], 'pr'); + } else { + # 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(); + } + } + } + + $result->addValue(array ( + 'query', + 'pages' + ), $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) + { + $missing = $pageSet->getMissingTitles(); + $res = &$result->getData(); + foreach($missing as $pageid => $title) + $res['query']['pages'][$pageid]['edittoken'] = $wgUser->editToken(); + } + } + + protected function getAllowedParams() { + return array ( + 'prop' => array ( + ApiBase :: PARAM_DFLT => NULL, + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'protection' + )), + 'token' => array ( + ApiBase :: PARAM_DFLT => NULL, + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'edit', + 'delete', + 'protect', + 'move', + )), + ); + } + + protected function getParamDescription() { + return array ( + 'prop' => array ( + 'Which additional properties to get:', + ' "protection" - List the protection level of each page' + ), + 'token' => 'Request a token to perform a data-modifying action on a page', + ); + } + + + protected function getDescription() { + return 'Get basic page information such as namespace, title, last touched date, ...'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&prop=info&titles=Main%20Page', + 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryInfo.php 27877 2007-11-27 10:22:14Z rotem $'; + } +} + diff --git a/includes/api/query/ApiQueryLangLinks.php b/includes/api/query/ApiQueryLangLinks.php new file mode 100644 index 0000000000..ae5ff79064 --- /dev/null +++ b/includes/api/query/ApiQueryLangLinks.php @@ -0,0 +1,94 @@ +@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 module to list all langlinks (links to correspanding foreign language pages). + * + * @addtogroup API + */ +class ApiQueryLangLinks extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'll'); + } + + public function execute() { + $this->addFields(array ( + 'll_from', + 'll_lang', + 'll_title' + )); + + $this->addTables('langlinks'); + $this->addWhereFld('ll_from', array_keys($this->getPageSet()->getGoodTitles())); + $this->addOption('ORDER BY', "ll_from, ll_lang"); + $res = $this->select(__METHOD__); + + $data = array(); + $lastId = 0; // database has no ID 0 + $db = $this->getDB(); + while ($row = $db->fetchObject($res)) { + + if ($lastId != $row->ll_from) { + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + $data = array(); + } + $lastId = $row->ll_from; + } + + $entry = array('lang'=>$row->ll_lang); + ApiResult :: setContent($entry, $row->ll_title); + $data[] = $entry; + } + + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + } + + $db->freeResult($res); + } + + protected function getDescription() { + return 'Returns all interlanguage links from the given page(s)'; + } + + protected function getExamples() { + return array ( + "Get interlanguage links from the [[Main Page]]:", + " api.php?action=query&prop=langlinks&titles=Main%20Page&redirects", + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryLangLinks.php 23819 2007-07-07 03:05:09Z yurik $'; + } +} + diff --git a/includes/api/query/ApiQueryLinks.php b/includes/api/query/ApiQueryLinks.php new file mode 100644 index 0000000000..7ec20f442b --- /dev/null +++ b/includes/api/query/ApiQueryLinks.php @@ -0,0 +1,162 @@ +@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 module to list all wiki links on a given set of pages. + * + * @addtogroup API + */ +class ApiQueryLinks extends ApiQueryGeneratorBase { + + const LINKS = 'links'; + const TEMPLATES = 'templates'; + + private $table, $prefix, $description; + + public function __construct($query, $moduleName) { + + switch ($moduleName) { + case self::LINKS : + $this->table = 'pagelinks'; + $this->prefix = 'pl'; + $this->description = 'link'; + break; + case self::TEMPLATES : + $this->table = 'templatelinks'; + $this->prefix = 'tl'; + $this->description = 'template'; + break; + default : + ApiBase :: dieDebug(__METHOD__, 'Unknown module name'); + } + + parent :: __construct($query, $moduleName, $this->prefix); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + if ($this->getPageSet()->getGoodTitleCount() == 0) + return; // nothing to do + + $params = $this->extractRequestParams(); + + $this->addFields(array ( + $this->prefix . '_from pl_from', + $this->prefix . '_namespace pl_namespace', + $this->prefix . '_title pl_title' + )); + + $this->addTables($this->table); + $this->addWhereFld($this->prefix . '_from', array_keys($this->getPageSet()->getGoodTitles())); + $this->addWhereFld($this->prefix . '_namespace', $params['namespace']); + $this->addOption('ORDER BY', str_replace('pl_', $this->prefix . '_', 'pl_from, pl_namespace, pl_title')); + + $db = $this->getDB(); + $res = $this->select(__METHOD__); + + if (is_null($resultPageSet)) { + + $data = array(); + $lastId = 0; // database has no ID 0 + while ($row = $db->fetchObject($res)) { + if ($lastId != $row->pl_from) { + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + $data = array(); + } + $lastId = $row->pl_from; + } + + $vals = array(); + ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle($row->pl_namespace, $row->pl_title)); + $data[] = $vals; + } + + if($lastId != 0) { + $this->addPageSubItems($lastId, $data); + } + + } else { + + $titles = array(); + while ($row = $db->fetchObject($res)) { + $titles[] = Title :: makeTitle($row->pl_namespace, $row->pl_title); + } + $resultPageSet->populateFromTitles($titles); + } + + $db->freeResult($res); + } + + protected function getAllowedParams() + { + return array( + 'namespace' => array( + ApiBase :: PARAM_TYPE => 'namespace', + ApiBase :: PARAM_ISMULTI => true + ) + ); + } + + protected function getParamDescription() + { + return array( + 'namespace' => "Show {$this->description}s in this namespace(s) only" + ); + } + + protected function getDescription() { + return "Returns all {$this->description}s from the given page(s)"; + } + + protected function getExamples() { + return array ( + "Get {$this->description}s from the [[Main Page]]:", + " api.php?action=query&prop={$this->getModuleName()}&titles=Main%20Page", + "Get information about the {$this->description} pages in the [[Main Page]]:", + " api.php?action=query&generator={$this->getModuleName()}&titles=Main%20Page&prop=info", + "Get {$this->description}s from the Main Page in the User and Template namespaces:", + " api.php?action=query&prop={$this->getModuleName()}&titles=Main%20Page&{$this->prefix}namespace=2|10" + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryLinks.php 24092 2007-07-14 19:04:31Z yurik $'; + } +} + diff --git a/includes/api/query/ApiQueryLogEvents.php b/includes/api/query/ApiQueryLogEvents.php new file mode 100644 index 0000000000..0f143658bd --- /dev/null +++ b/includes/api/query/ApiQueryLogEvents.php @@ -0,0 +1,272 @@ +@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'); +} + +/** + * Query action to List the log events, with optional filtering by various parameters. + * + * @addtogroup API + */ +class ApiQueryLogEvents extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'le'); + } + + public function execute() { + $params = $this->extractRequestParams(); + $db = $this->getDB(); + + $prop = $params['prop']; + $this->fld_ids = in_array('ids', $prop); + $this->fld_title = in_array('title', $prop); + $this->fld_type = in_array('type', $prop); + $this->fld_user = in_array('user', $prop); + $this->fld_timestamp = in_array('timestamp', $prop); + $this->fld_comment = in_array('comment', $prop); + $this->fld_details = in_array('details', $prop); + + list($tbl_logging, $tbl_page, $tbl_user) = $db->tableNamesN('logging', 'page', 'user'); + + $this->addOption('STRAIGHT_JOIN'); + $this->addTables("$tbl_logging LEFT OUTER JOIN $tbl_page ON " . + "log_namespace=page_namespace AND log_title=page_title " . + "INNER JOIN $tbl_user ON user_id=log_user"); + + $this->addFields(array ( + 'log_type', + 'log_action', + 'log_timestamp', + )); + + // FIXME: Fake out log_id for now until the column is live on Wikimedia + // $this->addFieldsIf('log_id', $this->fld_ids); + $this->addFieldsIf('page_id', $this->fld_ids); + $this->addFieldsIf('log_user', $this->fld_user); + $this->addFieldsIf('user_name', $this->fld_user); + $this->addFieldsIf('log_namespace', $this->fld_title); + $this->addFieldsIf('log_title', $this->fld_title); + $this->addFieldsIf('log_comment', $this->fld_comment); + $this->addFieldsIf('log_params', $this->fld_details); + + + $this->addWhereFld('log_deleted', 0); + $this->addWhereFld('log_type', $params['type']); + $this->addWhereRange('log_timestamp', $params['dir'], $params['start'], $params['end']); + + $limit = $params['limit']; + $this->addOption('LIMIT', $limit +1); + + $user = $params['user']; + if (!is_null($user)) { + $userid = $db->selectField('user', 'user_id', array ( + 'user_name' => $user + )); + if (!$userid) + $this->dieUsage("User name $user not found", 'param_user'); + $this->addWhereFld('log_user', $userid); + } + + $title = $params['title']; + if (!is_null($title)) { + $titleObj = Title :: newFromText($title); + if (is_null($titleObj)) + $this->dieUsage("Bad title value '$title'", 'param_title'); + $this->addWhereFld('log_namespace', $titleObj->getNamespace()); + $this->addWhereFld('log_title', $titleObj->getDBkey()); + } + + $data = array (); + $count = 0; + $res = $this->select(__METHOD__); + 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... + $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->log_timestamp)); + break; + } + + $vals = $this->extractRowInfo($row); + if($vals) + $data[] = $vals; + } + $db->freeResult($res); + + $this->getResult()->setIndexedTagName($data, 'item'); + $this->getResult()->addValue('query', $this->getModuleName(), $data); + } + + private function extractRowInfo($row) { + $vals = array(); + + if ($this->fld_ids) { + // FIXME: Fake out log_id for now until the column is live on Wikimedia + // $vals['logid'] = intval($row->log_id); + $vals['logid'] = 0; + $vals['pageid'] = intval($row->page_id); + } + + if ($this->fld_title) { + $title = Title :: makeTitle($row->log_namespace, $row->log_title); + ApiQueryBase :: addTitleInfo($vals, $title); + } + + if ($this->fld_type) { + $vals['type'] = $row->log_type; + $vals['action'] = $row->log_action; + } + + if ($this->fld_details && $row->log_params !== '') { + $params = explode("\n", $row->log_params); + switch ($row->log_type) { + case 'move': + if (isset ($params[0])) { + $title = Title :: newFromText($params[0]); + if ($title) { + $vals2 = array(); + ApiQueryBase :: addTitleInfo($vals2, $title, "new_"); + $vals[$row->log_type] = $vals2; + $params = null; + } + } + break; + case 'patrol': + $vals2 = array(); + list( $vals2['cur'], $vals2['prev'], $vals2['auto'] ) = $params; + $vals[$row->log_type] = $vals2; + $params = null; + break; + case 'rights': + $vals2 = array(); + list( $vals2['old'], $vals2['new'] ) = $params; + $vals[$row->log_type] = $vals2; + $params = null; + break; + case 'block': + $vals2 = array(); + list( $vals2['duration'], $vals2['flags'] ) = $params; + $vals[$row->log_type] = $vals2; + $params = null; + break; + } + + if (isset($params)) { + $this->getResult()->setIndexedTagName($params, 'param'); + $vals = array_merge($vals, $params); + } + } + + if ($this->fld_user) { + $vals['user'] = $row->user_name; + if(!$row->log_user) + $vals['anon'] = ''; + } + if ($this->fld_timestamp) { + $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->log_timestamp); + } + if ($this->fld_comment && !empty ($row->log_comment)) { + $vals['comment'] = $row->log_comment; + } + + return $vals; + } + + + protected function getAllowedParams() { + global $wgLogTypes; + return array ( + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_DFLT => 'ids|title|type|user|timestamp|comment|details', + ApiBase :: PARAM_TYPE => array ( + 'ids', + 'title', + 'type', + 'user', + 'timestamp', + 'comment', + 'details', + ) + ), + 'type' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => $wgLogTypes + ), + 'start' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'end' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'dir' => array ( + ApiBase :: PARAM_DFLT => 'older', + ApiBase :: PARAM_TYPE => array ( + 'newer', + 'older' + ) + ), + 'user' => null, + 'title' => null, + 'limit' => array ( + ApiBase :: PARAM_DFLT => 10, + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ) + ); + } + + protected function getParamDescription() { + return array ( + 'type' => 'Filter log entries to only this type(s)', + 'start' => 'The timestamp to start enumerating from.', + 'end' => 'The timestamp to end enumerating.', + 'dir' => 'In which direction to enumerate.', + 'user' => 'Filter entries to those made by the given user.', + 'title' => 'Filter entries to those related to a page.', + 'limit' => 'How many total event entries to return.' + ); + } + + protected function getDescription() { + return 'Get events from logs.'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=logevents' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryLogEvents.php 24256 2007-07-18 21:47:09Z robchurch $'; + } +} + diff --git a/includes/api/query/ApiQueryRecentChanges.php b/includes/api/query/ApiQueryRecentChanges.php new file mode 100644 index 0000000000..a7072ea292 --- /dev/null +++ b/includes/api/query/ApiQueryRecentChanges.php @@ -0,0 +1,354 @@ +@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 enumerate the recent changes that were done to the wiki. + * Various filters are supported. + * + * @addtogroup API + */ +class ApiQueryRecentChanges extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'rc'); + } + + private $fld_comment = false, $fld_user = false, $fld_flags = false, + $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() { + /* 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); + + /* 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'])); + } + + /* Add the fields we're concerned with to out query. */ + $this->addFields(array ( + 'rc_timestamp', + 'rc_namespace', + 'rc_title', + 'rc_type', + 'rc_moved_to_ns', + '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']); + $this->fld_timestamp = isset ($prop['timestamp']); + $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); + $this->addFieldsIf('rc_last_oldid', $this->fld_ids); + $this->addFieldsIf('rc_comment', $this->fld_comment); + $this->addFieldsIf('rc_user', $this->fld_user); + $this->addFieldsIf('rc_user_text', $this->fld_user); + $this->addFieldsIf('rc_minor', $this->fld_flags); + $this->addFieldsIf('rc_bot', $this->fld_flags); + $this->addFieldsIf('rc_new', $this->fld_flags); + $this->addFieldsIf('rc_old_len', $this->fld_sizes); + $this->addFieldsIf('rc_new_len', $this->fld_sizes); + } + + /* 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... + $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp)); + 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 (); + + $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); + $vals['revid'] = intval($row->rc_this_oldid); + $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'] = ''; + if ($row->rc_new) + $vals['new'] = ''; + if ($row->rc_minor) + $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() { + return array ( + 'start' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'end' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'dir' => array ( + ApiBase :: PARAM_DFLT => 'older', + ApiBase :: PARAM_TYPE => array ( + 'newer', + 'older' + ) + ), + 'namespace' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => 'namespace' + ), + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_DFLT => 'title|timestamp|ids', + ApiBase :: PARAM_TYPE => array ( + 'user', + 'comment', + 'flags', + 'timestamp', + 'title', + 'ids', + 'sizes' + ) + ), + 'show' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'minor', + '!minor', + 'bot', + '!bot', + 'anon', + '!anon' + ) + ), + '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 + ), + 'type' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'edit', + 'new', + 'log' + ) + ) + ); + } + + protected function getParamDescription() { + return array ( + 'start' => 'The timestamp to start enumerating from.', + 'end' => 'The timestamp to end enumerating.', + 'dir' => 'In which direction to enumerate.', + 'namespace' => 'Filter log entries to only this namespace(s)', + 'prop' => 'Include additional pieces of information', + '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' + ), + 'type' => 'Which types of changes to show.', + 'limit' => 'How many total pages to return.' + ); + } + + protected function getDescription() { + return 'Enumerate recent changes'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=recentchanges' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryRecentChanges.php 26633 2007-10-12 14:03:43Z catrope $'; + } +} + diff --git a/includes/api/query/ApiQueryRevisions.php b/includes/api/query/ApiQueryRevisions.php new file mode 100644 index 0000000000..52edf99f7e --- /dev/null +++ b/includes/api/query/ApiQueryRevisions.php @@ -0,0 +1,383 @@ +@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 enumerate revisions of a given page, or show top revisions of multiple pages. + * Various pieces of information may be shown - flags, comments, and the actual wiki markup of the rev. + * In the enumeration mode, ranges of revisions may be requested and filtered. + * + * @addtogroup API + */ +class ApiQueryRevisions extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'rv'); + } + + private $fld_ids = false, $fld_flags = false, $fld_timestamp = false, $fld_size = false, + $fld_comment = false, $fld_user = false, $fld_content = false; + + public function execute() { + $limit = $startid = $endid = $start = $end = $dir = $prop = $user = $excludeuser = $token = null; + extract($this->extractRequestParams()); + + // 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 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(); + $revCount = $pageSet->getRevisionCount(); + + // Optimization -- nothing to do + if ($revCount === 0 && $pageCount === 0) + return; + + if ($revCount > 0 && $enumRevMode) + $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->addTables('revision'); + $this->addWhere('rev_deleted=0'); + + $prop = array_flip($prop); + + // These field are needed regardless of the client requesting them + $this->addFields('rev_id'); + $this->addFields('rev_page'); + + // Optional fields + $this->fld_ids = isset ($prop['ids']); + // $this->addFieldsIf('rev_text_id', $this->fld_ids); // should this be exposed? + $this->fld_flags = $this->addFieldsIf('rev_minor_edit', isset ($prop['flags'])); + $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'])); + 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 + foreach ($pageSet->getGoodTitles() as $title) { + if( !$title->userCanRead() ) + $this->dieUsage( + 'The current user is not allowed to read ' . $title->getPrefixedText(), + 'accessdenied'); + } + + $this->addTables('text'); + $this->addWhere('rev_text_id=old_id'); + $this->addFields('old_id'); + $this->addFields('old_text'); + $this->addFields('old_flags'); + + $this->fld_content = true; + + $this->expandTemplates = $expandtemplates; + } + + $userMax = ( $this->fld_content ? ApiBase::LIMIT_SML1 : ApiBase::LIMIT_BIG1 ); + $botMax = ( $this->fld_content ? ApiBase::LIMIT_SML2 : ApiBase::LIMIT_BIG2 ); + + if ($enumRevMode) { + + // 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'); + + if (!is_null($endid) && !is_null($end)) + $this->dieUsage('end and endid cannot be used together', 'badparams'); + + if(!is_null($user) && !is_null( $excludeuser)) + $this->dieUsage('user and excludeuser cannot be used together', 'badparams'); + + // This code makes an assumption that sorting by rev_id and rev_timestamp produces + // the same result. This way users may request revisions starting at a given time, + // but to page through results use the rev_id returned after each page. + // Switching to rev_id removes the potential problem of having more than + // 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) && is_null($endid)) + $this->addWhereRange('rev_timestamp', $dir, $start, $end); + else + $this->addWhereRange('rev_id', $dir, $startid, $endid); + + // must manually initialize unset limit + if (is_null($limit)) + $limit = 10; + $this->validateLimit('limit', $limit, 1, $userMax, $botMax); + + // There is only one ID, use it + $this->addWhereFld('rev_page', current(array_keys($pageSet->getGoodTitles()))); + + if(!is_null($user)) { + $this->addWhereFld('rev_user_text', $user); + } elseif (!is_null( $excludeuser)) { + $this->addWhere('rev_user_text != ' . $this->getDB()->addQuotes($excludeuser)); + } + } + elseif ($revCount > 0) { + $this->validateLimit('rev_count', $revCount, 1, $userMax, $botMax); + + // Get all revision IDs + $this->addWhereFld('rev_id', array_keys($pageSet->getRevisionIDs())); + + // assumption testing -- we should never get more then $revCount rows. + $limit = $revCount; + } + elseif ($pageCount > 0) { + // When working in multi-page non-enumeration mode, + // limit to the latest revision only + $this->addTables('page'); + $this->addWhere('page_id=rev_page'); + $this->addWhere('page_latest=rev_id'); + $this->validateLimit('page_count', $pageCount, 1, $userMax, $botMax); + + // Get all page IDs + $this->addWhereFld('page_id', array_keys($pageSet->getGoodTitles())); + + // assumption testing -- we should never get more then $pageCount rows. + $limit = $pageCount; + } else + ApiBase :: dieDebug(__METHOD__, 'param validation?'); + + $this->addOption('LIMIT', $limit +1); + + $data = array (); + $count = 0; + $res = $this->select(__METHOD__); + + $db = $this->getDB(); + 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... + if (!$enumRevMode) + ApiBase :: dieDebug(__METHOD__, 'Got more rows then expected'); // bug report + $this->setContinueEnumParameter('startid', intval($row->rev_id)); + break; + } + + $this->getResult()->addValue( + array ( + 'query', + 'pages', + intval($row->rev_page), + 'revisions'), + null, + $this->extractRowInfo($row)); + } + $db->freeResult($res); + + // Ensure that all revisions are shown as '' elements + $result = $this->getResult(); + if ($result->getIsRawMode()) { + $data =& $result->getData(); + foreach ($data['query']['pages'] as & $page) { + if (is_array($page) && array_key_exists('revisions', $page)) { + $result->setIndexedTagName($page['revisions'], 'rev'); + } + } + } + } + + private function extractRowInfo($row) { + + $vals = array (); + + if ($this->fld_ids) { + $vals['revid'] = intval($row->rev_id); + // $vals['oldid'] = intval($row->rev_text_id); // todo: should this be exposed? + } + + if ($this->fld_flags && $row->rev_minor_edit) + $vals['minor'] = ''; + + if ($this->fld_user) { + $vals['user'] = $row->rev_user_text; + if (!$row->rev_user) + $vals['anon'] = ''; + } + + if ($this->fld_timestamp) { + $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rev_timestamp); + } + + if ($this->fld_size && !is_null($row->rev_len)) { + $vals['size'] = intval($row->rev_len); + } + + if ($this->fld_comment && !empty ($row->rev_comment)) { + $vals['comment'] = $row->rev_comment; + } + + 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() { + return array ( + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_DFLT => 'ids|timestamp|flags|comment|user', + ApiBase :: PARAM_TYPE => array ( + 'ids', + 'flags', + 'timestamp', + 'user', + 'size', + 'comment', + 'content', + ) + ), + 'limit' => array ( + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ), + 'startid' => array ( + ApiBase :: PARAM_TYPE => 'integer' + ), + 'endid' => array ( + ApiBase :: PARAM_TYPE => 'integer' + ), + 'start' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'end' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'dir' => array ( + ApiBase :: PARAM_DFLT => 'older', + ApiBase :: PARAM_TYPE => array ( + 'newer', + 'older' + ) + ), + 'user' => array( + ApiBase :: PARAM_TYPE => 'user' + ), + 'excludeuser' => array( + ApiBase :: PARAM_TYPE => 'user' + ), + + 'expandtemplates' => false, + 'token' => array( + ApiBase :: PARAM_TYPE => array( + 'rollback' + ), + ApiBase :: PARAM_ISMULTI => true + ), + ); + } + + protected function getParamDescription() { + return array ( + 'prop' => 'Which properties to get for each revision.', + 'limit' => 'limit how many revisions will be returned (enum)', + 'startid' => 'from which revision id to start enumeration (enum)', + 'endid' => 'stop revision enumeration on this revid (enum)', + 'start' => 'from which revision timestamp to start enumeration (enum)', + 'end' => 'enumerate up to this timestamp (enum)', + 'dir' => 'direction of enumeration - towards "newer" or "older" revisions (enum)', + 'user' => 'only include revisions made by user', + 'excludeuser' => 'exclude revisions made by user', + 'expandtemplates' => 'expand templates in revision content', + 'token' => 'Which tokens to obtain for each revision', + ); + } + + protected function getDescription() { + return array ( + 'Get revision information.', + 'This module may be used in several ways:', + ' 1) Get data about a set of pages (last revision), by setting titles or pageids parameter.', + ' 2) Get revisions for one given page, by using titles/pageids with start/end/limit params.', + ' 3) Get data about a set of revisions by setting their IDs with revids parameter.', + 'All parameters marked as (enum) may only be used with a single page (#2).' + ); + } + + protected function getExamples() { + return array ( + 'Get data with content for the last revision of titles "API" and "Main Page":', + ' api.php?action=query&prop=revisions&titles=API|Main%20Page&rvprop=timestamp|user|comment|content', + 'Get last 5 revisions of the "Main Page":', + ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment', + 'Get first 5 revisions of the "Main Page":', + ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer', + 'Get first 5 revisions of the "Main Page" made after 2006-05-01:', + ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer&rvstart=20060501000000', + 'Get first 5 revisions of the "Main Page" that were not made made by anonymous user "127.0.0.1"', + ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvexcludeuser=127.0.0.1', + 'Get first 5 revisions of the "Main Page" that were made by the user "MediaWiki default"', + ' api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvuser=MediaWiki%20default', + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryRevisions.php 28176 2007-12-05 06:32:17Z amidaniel $'; + } +} + diff --git a/includes/api/query/ApiQuerySearch.php b/includes/api/query/ApiQuerySearch.php new file mode 100644 index 0000000000..268616b164 --- /dev/null +++ b/includes/api/query/ApiQuerySearch.php @@ -0,0 +1,151 @@ +@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'); +} + +/** + * Query module to perform full text search within wiki titles and content + * + * @addtogroup API + */ +class ApiQuerySearch extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'sr'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private function run($resultPageSet = null) { + + $params = $this->extractRequestParams(); + + $limit = $params['limit']; + $query = $params['search']; + if (is_null($query) || empty($query)) + $this->dieUsage("empty search string is not allowed", 'param-search'); + + $search = SearchEngine::create(); + $search->setLimitOffset( $limit+1, $params['offset'] ); + $search->setNamespaces( $params['namespace'] ); + $search->showRedirects = $params['redirects']; + + if ($params['what'] == 'text') + $matches = $search->searchText( $query ); + else + $matches = $search->searchTitle( $query ); + + $data = array (); + $count = 0; + while( $result = $matches->next() ) { + if (++ $count > $limit) { + // We've reached the one extra which shows that there are additional items to be had. Stop here... + $this->setContinueEnumParameter('offset', $params['offset'] + $params['limit']); + break; + } + + $title = $result->getTitle(); + if (is_null($resultPageSet)) { + $data[] = array( + 'ns' => intval($title->getNamespace()), + 'title' => $title->getPrefixedText()); + } else { + $data[] = $title; + } + } + + if (is_null($resultPageSet)) { + $result = $this->getResult(); + $result->setIndexedTagName($data, 'p'); + $result->addValue('query', $this->getModuleName(), $data); + } else { + $resultPageSet->populateFromTitles($data); + } + } + + protected function getAllowedParams() { + return array ( + 'search' => null, + 'namespace' => array ( + ApiBase :: PARAM_DFLT => 0, + ApiBase :: PARAM_TYPE => 'namespace', + ApiBase :: PARAM_ISMULTI => true, + ), + 'what' => array ( + ApiBase :: PARAM_DFLT => 'title', + ApiBase :: PARAM_TYPE => array ( + 'title', + 'text', + ) + ), + 'redirects' => false, + 'offset' => 0, + 'limit' => array ( + ApiBase :: PARAM_DFLT => 10, + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ) + ); + } + + protected function getParamDescription() { + return array ( + 'search' => 'Search for all page titles (or content) that has this value.', + 'namespace' => 'The namespace(s) to enumerate.', + 'what' => 'Search inside the text or titles.', + 'redirects' => 'Include redirect pages in the search.', + 'offset' => 'Use this value to continue paging (return by query)', + 'limit' => 'How many total pages to return.' + ); + } + + protected function getDescription() { + return 'Perform a full text search'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=search&srsearch=meaning', + 'api.php?action=query&list=search&srwhat=text&srsearch=meaning', + 'api.php?action=query&generator=search&gsrsearch=meaning&prop=info', + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQuerySearch.php 24453 2007-07-30 08:09:15Z yurik $'; + } +} + diff --git a/includes/api/query/ApiQuerySiteinfo.php b/includes/api/query/ApiQuerySiteinfo.php new file mode 100644 index 0000000000..576ea98eaa --- /dev/null +++ b/includes/api/query/ApiQuerySiteinfo.php @@ -0,0 +1,238 @@ +@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 meta information about the wiki site. + * + * @addtogroup API + */ +class ApiQuerySiteinfo extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'si'); + } + + public function execute() { + + $params = $this->extractRequestParams(); + + foreach ($params['prop'] as $p) { + switch ($p) { + default : + ApiBase :: dieDebug(__METHOD__, "Unknown prop=$p"); + case 'general' : + $this->appendGeneralInfo($p); + break; + case 'namespaces' : + $this->appendNamespaces($p); + break; + case 'interwikimap' : + $filteriw = isset($params['filteriw']) ? $params['filteriw'] : false; + $this->appendInterwikiMap($p, $filteriw); + break; + case 'dbrepllag' : + $this->appendDbReplLagInfo($p, $params['showalldb']); + break; + case 'statistics' : + $this->appendStatistics($p); + break; + } + } + } + + protected function appendGeneralInfo($property) { + global $wgSitename, $wgVersion, $wgCapitalLinks, $wgRightsCode, $wgRightsText, $wgLanguageCode, $IP; + + $data = array (); + $mainPage = Title :: newFromText(wfMsgForContent('mainpage')); + $data['mainpage'] = $mainPage->getText(); + $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; + $data['rights'] = $wgRightsText; + $data['lang'] = $wgLanguageCode; + + $this->getResult()->addValue('query', $property, $data); + } + + protected function appendNamespaces($property) { + global $wgContLang; + + $data = array (); + foreach ($wgContLang->getFormattedNamespaces() as $ns => $title) { + $data[$ns] = array ( + 'id' => $ns + ); + ApiResult :: setContent($data[$ns], $title); + } + + $this->getResult()->setIndexedTagName($data, 'ns'); + $this->getResult()->addValue('query', $property, $data); + } + + protected function appendInterwikiMap($property, $filter) { + + $this->resetQueryParams(); + $this->addTables('interwiki'); + $this->addFields(array('iw_prefix', 'iw_local', 'iw_url')); + + if($filter === 'local') { + $this->addWhere('iw_local = 1'); + } elseif($filter === '!local') { + $this->addWhere('iw_local = 0'); + } elseif($filter !== false) { + ApiBase :: dieDebug(__METHOD__, "Unknown filter=$filter"); + } + + $this->addOption('ORDER BY', 'iw_prefix'); + + $db = $this->getDB(); + $res = $this->select(__METHOD__); + + $data = array(); + while($row = $db->fetchObject($res)) + { + $val['prefix'] = $row->iw_prefix; + if ($row->iw_local == '1') + $val['local'] = ''; +// $val['trans'] = intval($row->iw_trans); // should this be exposed? + $val['url'] = $row->iw_url; + + $data[] = $val; + } + $db->freeResult($res); + + $this->getResult()->setIndexedTagName($data, 'iw'); + $this->getResult()->addValue('query', $property, $data); + } + + protected function appendDbReplLagInfo($property, $includeAll) { + global $wgLoadBalancer, $wgShowHostnames; + + $data = array(); + + if ($includeAll) { + if (!$wgShowHostnames) + $this->dieUsage('Cannot view all servers info unless $wgShowHostnames is true', 'includeAllDenied'); + + global $wgDBservers; + $lags = $wgLoadBalancer->getLagTimes(); + foreach( $lags as $i => $lag ) { + $data[] = array ( + 'host' => $wgDBservers[$i]['host'], + 'lag' => $lag); + } + } else { + list( $host, $lag ) = $wgLoadBalancer->getMaxLag(); + $data[] = array ( + 'host' => $wgShowHostnames ? $host : '', + 'lag' => $lag); + } + + $result = $this->getResult(); + $result->setIndexedTagName($data, 'db'); + $result->addValue('query', $property, $data); + } + + protected function appendStatistics($property) { + $data = array (); + $data['pages'] = intval(SiteStats::pages()); + $data['articles'] = intval(SiteStats::articles()); + $data['views'] = intval(SiteStats::views()); + $data['edits'] = intval(SiteStats::edits()); + $data['images'] = intval(SiteStats::images()); + $data['users'] = intval(SiteStats::users()); + $data['admins'] = intval(SiteStats::admins()); + $data['jobs'] = intval(SiteStats::jobs()); + $this->getResult()->addValue('query', $property, $data); + } + + protected function getAllowedParams() { + return array ( + + 'prop' => array ( + ApiBase :: PARAM_DFLT => 'general', + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'general', + 'namespaces', + 'interwikimap', + 'dbrepllag', + 'statistics', + )), + + 'filteriw' => array ( + ApiBase :: PARAM_TYPE => array ( + 'local', + '!local', + )), + + 'showalldb' => false, + ); + } + + protected function getParamDescription() { + return array ( + 'prop' => array ( + 'Which sysinfo properties to get:', + ' "general" - Overall system information', + ' "namespaces" - List of registered namespaces (localized)', + ' "statistics" - Returns site statistics', + ' "interwikimap" - Returns interwiki map (optionally filtered)', + ' "dbrepllag" - Returns database server with the highest replication lag', + ), + 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map', + 'showalldb' => 'List all database servers, not just the one lagging the most', + ); + } + + protected 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=interwikimap&sifilteriw=local', + 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb', + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQuerySiteinfo.php 26444 2007-10-06 02:30:00Z amidaniel $'; + } +} diff --git a/includes/api/query/ApiQueryUserContributions.php b/includes/api/query/ApiQueryUserContributions.php new file mode 100644 index 0000000000..05c3d94599 --- /dev/null +++ b/includes/api/query/ApiQueryUserContributions.php @@ -0,0 +1,276 @@ +@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'); +} + +/** + * This query action adds a list of a specified user's contributions to the output. + * + * @addtogroup API + */ +class ApiQueryContributions extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'uc'); + } + + private $params, $username; + private $fld_ids = false, $fld_title = false, $fld_timestamp = false, + $fld_comment = false, $fld_flags = false; + + public function execute() { + + // Parse some parameters + $this->params = $this->extractRequestParams(); + + $prop = array_flip($this->params['prop']); + $this->fld_ids = isset($prop['ids']); + $this->fld_title = isset($prop['title']); + $this->fld_comment = isset($prop['comment']); + $this->fld_flags = isset($prop['flags']); + $this->fld_timestamp = isset($prop['timestamp']); + + // TODO: if the query is going only against the revision table, should this be done? + $this->selectNamedDB('contributions', DB_SLAVE, 'contributions'); + $db = $this->getDB(); + + // Prepare query + $this->prepareUsername(); + $this->prepareQuery(); + + //Do the actual query. + $res = $this->select( __METHOD__ ); + + //Initialise some variables + $data = array (); + $count = 0; + $limit = $this->params['limit']; + + //Fetch each row + 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... + $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rev_timestamp)); + break; + } + + $vals = $this->extractRowInfo($row); + if ($vals) + $data[] = $vals; + } + + //Free the database record so the connection can get on with other stuff + $db->freeResult($res); + + //And send the whole shebang out as output. + $this->getResult()->setIndexedTagName($data, 'item'); + $this->getResult()->addValue('query', $this->getModuleName(), $data); + } + + /** + * Validate the 'user' parameter and set the value to compare + * against `revision`.`rev_user_text` + */ + private function prepareUsername() { + $user = $this->params['user']; + if( $user ) { + $name = User::isIP( $user ) + ? $user + : User::getCanonicalName( $user, 'valid' ); + if( $name === false ) { + $this->dieUsage( "User name {$user} is not valid", 'param_user' ); + } else { + $this->username = $name; + } + } else { + $this->dieUsage( 'User parameter may not be empty', 'param_user' ); + } + } + + /** + * Prepares the query and returns the limit of rows requested + */ + private function prepareQuery() { + + //We're after the revision table, and the corresponding page row for + //anything we retrieve. + list ($tbl_page, $tbl_revision) = $this->getDB()->tableNamesN('page', 'revision'); + $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 ); + + // ... 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']; + if (!is_null($show)) { + $show = array_flip($show); + if (isset ($show['minor']) && isset ($show['!minor'])) + $this->dieUsage("Incorrect parameter - mutually exclusive values may not be supplied", 'show'); + + $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 + $this->addFields(array( + 'rev_timestamp', + 'page_namespace', + 'page_title', + )); + + $this->addFieldsIf('rev_page', $this->fld_ids); + $this->addFieldsIf('rev_id', $this->fld_ids); + // $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); + } + + /** + * Extract fields from the database row and append them to a result array + */ + private function extractRowInfo($row) { + + $vals = array(); + + if ($this->fld_ids) { + $vals['pageid'] = intval($row->rev_page); + $vals['revid'] = intval($row->rev_id); + // $vals['textid'] = intval($row->rev_text_id); // todo: Should this field be exposed? + } + + if ($this->fld_title) + ApiQueryBase :: addTitleInfo($vals, + Title :: makeTitle($row->page_namespace, $row->page_title)); + + if ($this->fld_timestamp) + $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rev_timestamp); + + if ($this->fld_flags) { + if ($row->page_is_new) + $vals['new'] = ''; + if ($row->rev_minor_edit) + $vals['minor'] = ''; + } + + if ($this->fld_comment && !empty ($row->rev_comment)) + $vals['comment'] = $row->rev_comment; + + return $vals; + } + + protected function getAllowedParams() { + return array ( + '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 + ), + 'start' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'end' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'user' => array ( + ApiBase :: PARAM_TYPE => 'user' + ), + 'dir' => array ( + ApiBase :: PARAM_DFLT => 'older', + ApiBase :: PARAM_TYPE => array ( + 'newer', + 'older' + ) + ), + 'namespace' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => 'namespace' + ), + 'prop' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_DFLT => 'ids|title|timestamp|flags|comment', + ApiBase :: PARAM_TYPE => array ( + 'ids', + 'title', + 'timestamp', + 'comment', + 'flags' + ) + ), + 'show' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'minor', + '!minor', + ) + ), + ); + } + + protected function getParamDescription() { + return array ( + 'limit' => 'The maximum number of contributions to return.', + 'start' => 'The start timestamp to return from.', + 'end' => 'The end timestamp to return to.', + 'user' => 'The user to retrieve contributions for.', + 'dir' => 'The direction to search (older or newer).', + 'namespace' => 'Only list contributions in these namespaces', + 'prop' => 'Include additional pieces of information', + 'show' => 'Show only items that meet this criteria, e.g. non minor edits only: show=!minor', + ); + } + + protected function getDescription() { + return 'Get all edits by a user'; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=usercontribs&ucuser=YurikBot' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryUserContributions.php 24754 2007-08-13 18:18:18Z robchurch $'; + } +} + diff --git a/includes/api/query/ApiQueryUserInfo.php b/includes/api/query/ApiQueryUserInfo.php new file mode 100644 index 0000000000..978c67d235 --- /dev/null +++ b/includes/api/query/ApiQueryUserInfo.php @@ -0,0 +1,125 @@ +@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'); +} + +/** + * Query module to get information about the currently logged-in user + * + * @addtogroup API + */ +class ApiQueryUserInfo extends ApiQueryBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'ui'); + } + + public function execute() { + + global $wgUser; + + $params = $this->extractRequestParams(); + $result = $this->getResult(); + + $vals = array(); + $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 (isset($prop['options'])) { + $vals['options'] = (is_null($wgUser->mOptions) ? User::getDefaultOptions() : $wgUser->mOptions); + } + } + + $result->addValue(null, $this->getModuleName(), $vals); + } + + protected function getAllowedParams() { + return array ( + 'prop' => array ( + ApiBase :: PARAM_DFLT => NULL, + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => array ( + 'blockinfo', + 'hasmsg', + 'groups', + 'rights', + 'options' + )) + ); + } + + protected 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', + ' options - lists all preferences the current user has set' + ) + ); + } + + protected function getDescription() { + return 'Get information about the current user'; + } + + protected function getExamples() { + 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 27153 2007-11-03 16:08:43Z catrope $'; + } +} + diff --git a/includes/api/query/ApiQueryWatchlist.php b/includes/api/query/ApiQueryWatchlist.php new file mode 100644 index 0000000000..16586a4005 --- /dev/null +++ b/includes/api/query/ApiQueryWatchlist.php @@ -0,0 +1,299 @@ +@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'); +} + +/** + * This query action allows clients to retrieve a list of recently modified pages + * that are part of the logged-in user's watchlist. + * + * @addtogroup API + */ +class ApiQueryWatchlist extends ApiQueryGeneratorBase { + + public function __construct($query, $moduleName) { + parent :: __construct($query, $moduleName, 'wl'); + } + + public function execute() { + $this->run(); + } + + public function executeGenerator($resultPageSet) { + $this->run($resultPageSet); + } + + private $fld_ids = false, $fld_title = false, $fld_patrol = false, $fld_flags = false, + $fld_timestamp = false, $fld_user = false, $fld_comment = false, $fld_sizes = false; + + private function run($resultPageSet = null) { + global $wgUser, $wgDBtype; + + $this->selectNamedDB('watchlist', DB_SLAVE, 'watchlist'); + + if (!$wgUser->isLoggedIn()) + $this->dieUsage('You must be logged-in to have a watchlist', 'notloggedin'); + + $allrev = $start = $end = $namespace = $dir = $limit = $prop = null; + extract($this->extractRequestParams()); + + if (!is_null($prop) && is_null($resultPageSet)) { + + $prop = array_flip($prop); + + $this->fld_ids = isset($prop['ids']); + $this->fld_title = isset($prop['title']); + $this->fld_flags = isset($prop['flags']); + $this->fld_user = isset($prop['user']); + $this->fld_comment = isset($prop['comment']); + $this->fld_timestamp = isset($prop['timestamp']); + $this->fld_sizes = isset($prop['sizes']); + $this->fld_patrol = isset($prop['patrol']); + + if ($this->fld_patrol) { + global $wgUseRCPatrol, $wgUser; + if (!$wgUseRCPatrol || !$wgUser->isAllowed('patrol')) + $this->dieUsage('patrol property is not available', 'patrol'); + } + } + + if (is_null($resultPageSet)) { + $this->addFields(array ( + 'rc_cur_id', + 'rc_this_oldid', + 'rc_namespace', + 'rc_title', + 'rc_timestamp' + )); + + $this->addFieldsIf('rc_new', $this->fld_flags); + $this->addFieldsIf('rc_minor', $this->fld_flags); + $this->addFieldsIf('rc_user', $this->fld_user); + $this->addFieldsIf('rc_user_text', $this->fld_user); + $this->addFieldsIf('rc_comment', $this->fld_comment); + $this->addFieldsIf('rc_patrolled', $this->fld_patrol); + $this->addFieldsIf('rc_old_len', $this->fld_sizes); + $this->addFieldsIf('rc_new_len', $this->fld_sizes); + } + elseif ($allrev) { + $this->addFields(array ( + 'rc_this_oldid', + 'rc_namespace', + 'rc_title', + 'rc_timestamp' + )); + } else { + $this->addFields(array ( + 'rc_cur_id', + 'rc_namespace', + 'rc_title', + 'rc_timestamp' + )); + } + + $this->addTables(array ( + 'watchlist', + 'page', + 'recentchanges' + )); + + $userId = $wgUser->getID(); + $this->addWhere(array ( + 'wl_namespace = rc_namespace', + 'wl_title = rc_title', + 'rc_cur_id = page_id', + 'wl_user' => $userId, + 'rc_deleted' => 0, + )); + + $this->addWhereRange('rc_timestamp', $dir, $start, $end); + $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 + $this->addWhereIf("rc_timestamp > ''", !isset ($start) && !isset ($end) && $wgDBtype == 'mysql'); + + $this->addOption('LIMIT', $limit +1); + + $data = array (); + $count = 0; + $res = $this->select(__METHOD__); + + $db = $this->getDB(); + 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... + $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->rc_timestamp)); + break; + } + + if (is_null($resultPageSet)) { + $vals = $this->extractRowInfo($row); + if ($vals) + $data[] = $vals; + } else { + if ($allrev) { + $data[] = intval($row->rc_this_oldid); + } else { + $data[] = intval($row->rc_cur_id); + } + } + } + + $db->freeResult($res); + + if (is_null($resultPageSet)) { + $this->getResult()->setIndexedTagName($data, 'item'); + $this->getResult()->addValue('query', $this->getModuleName(), $data); + } + elseif ($allrev) { + $resultPageSet->populateFromRevisionIDs($data); + } else { + $resultPageSet->populateFromPageIDs($data); + } + } + + private function extractRowInfo($row) { + + $vals = array (); + + if ($this->fld_ids) { + $vals['pageid'] = intval($row->rc_cur_id); + $vals['revid'] = intval($row->rc_this_oldid); + } + + if ($this->fld_title) + ApiQueryBase :: addTitleInfo($vals, Title :: makeTitle($row->rc_namespace, $row->rc_title)); + + if ($this->fld_user) { + $vals['user'] = $row->rc_user_text; + if (!$row->rc_user) + $vals['anon'] = ''; + } + + if ($this->fld_flags) { + if ($row->rc_new) + $vals['new'] = ''; + if ($row->rc_minor) + $vals['minor'] = ''; + } + + if ($this->fld_patrol && isset($row->rc_patrolled)) + $vals['patrolled'] = ''; + + if ($this->fld_timestamp) + $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->rc_timestamp); + + $this->addFieldsIf('rc_new_len', $this->fld_sizes); + + if ($this->fld_sizes) { + $vals['oldlen'] = intval($row->rc_old_len); + $vals['newlen'] = intval($row->rc_new_len); + } + + if ($this->fld_comment && !empty ($row->rc_comment)) + $vals['comment'] = $row->rc_comment; + + return $vals; + } + + protected function getAllowedParams() { + return array ( + 'allrev' => false, + 'start' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'end' => array ( + ApiBase :: PARAM_TYPE => 'timestamp' + ), + 'namespace' => array ( + ApiBase :: PARAM_ISMULTI => true, + ApiBase :: PARAM_TYPE => 'namespace' + ), + 'dir' => array ( + ApiBase :: PARAM_DFLT => 'older', + ApiBase :: PARAM_TYPE => array ( + 'newer', + 'older' + ) + ), + 'limit' => array ( + ApiBase :: PARAM_DFLT => 10, + ApiBase :: PARAM_TYPE => 'limit', + ApiBase :: PARAM_MIN => 1, + ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1, + ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2 + ), + 'prop' => array ( + APIBase :: PARAM_ISMULTI => true, + APIBase :: PARAM_DFLT => 'ids|title|flags', + APIBase :: PARAM_TYPE => array ( + 'ids', + 'title', + 'flags', + 'user', + 'comment', + 'timestamp', + 'patrol', + 'sizes', + ) + ) + ); + } + + protected function getParamDescription() { + return array ( + 'allrev' => 'Include multiple revisions of the same page within given timeframe.', + 'start' => 'The timestamp to start enumerating from.', + 'end' => 'The timestamp to end enumerating.', + '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).' + ); + } + + protected function getDescription() { + return ''; + } + + protected function getExamples() { + return array ( + 'api.php?action=query&list=watchlist', + 'api.php?action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment', + 'api.php?action=query&list=watchlist&wlallrev&wlprop=ids|title|timestamp|user|comment', + 'api.php?action=query&generator=watchlist&prop=info', + 'api.php?action=query&generator=watchlist&gwlallrev&prop=revisions&rvprop=timestamp|user' + ); + } + + public function getVersion() { + return __CLASS__ . ': $Id: ApiQueryWatchlist.php 24092 2007-07-14 19:04:31Z yurik $'; + } +} +