From: Petr Onderka Date: Wed, 11 Apr 2012 15:10:22 +0000 (+0200) Subject: Corrected capitalization in the file and class names of API modules X-Git-Tag: 1.31.0-rc.0~23895^2 X-Git-Url: https://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/comptes/journal.php?a=commitdiff_plain;h=720c1b7be0d881f782e227ac7a2b86eab996fff3;p=lhc%2Fweb%2Fwiklou.git Corrected capitalization in the file and class names of API modules Change-Id: I8f317e458ee0f8706434e43a7890cda530595e64 --- diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index a1bbc3c0aa..56f3af6b5b 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -323,10 +323,10 @@ $wgAutoloadLocalClasses = array( 'ApiPurge' => 'includes/api/ApiPurge.php', 'ApiQuery' => 'includes/api/ApiQuery.php', 'ApiQueryAllCategories' => 'includes/api/ApiQueryAllCategories.php', - 'ApiQueryAllimages' => 'includes/api/ApiQueryAllimages.php', + 'ApiQueryAllImages' => 'includes/api/ApiQueryAllImages.php', 'ApiQueryAllLinks' => 'includes/api/ApiQueryAllLinks.php', - 'ApiQueryAllmessages' => 'includes/api/ApiQueryAllmessages.php', - 'ApiQueryAllpages' => 'includes/api/ApiQueryAllpages.php', + 'ApiQueryAllMessages' => 'includes/api/ApiQueryAllMessages.php', + 'ApiQueryAllPages' => 'includes/api/ApiQueryAllPages.php', 'ApiQueryAllUsers' => 'includes/api/ApiQueryAllUsers.php', 'ApiQueryBacklinks' => 'includes/api/ApiQueryBacklinks.php', 'ApiQueryBase' => 'includes/api/ApiQueryBase.php', diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php index c172d24dc1..866b71c25f 100644 --- a/includes/api/ApiQuery.php +++ b/includes/api/ApiQuery.php @@ -64,8 +64,8 @@ class ApiQuery extends ApiBase { ); private $mQueryListModules = array( - 'allimages' => 'ApiQueryAllimages', - 'allpages' => 'ApiQueryAllpages', + 'allimages' => 'ApiQueryAllImages', + 'allpages' => 'ApiQueryAllPages', 'alllinks' => 'ApiQueryAllLinks', 'allcategories' => 'ApiQueryAllCategories', 'allusers' => 'ApiQueryAllUsers', @@ -95,7 +95,7 @@ class ApiQuery extends ApiBase { private $mQueryMetaModules = array( 'siteinfo' => 'ApiQuerySiteinfo', 'userinfo' => 'ApiQueryUserInfo', - 'allmessages' => 'ApiQueryAllmessages', + 'allmessages' => 'ApiQueryAllMessages', ); private $mSlaveDB = null; diff --git a/includes/api/ApiQueryAllImages.php b/includes/api/ApiQueryAllImages.php new file mode 100644 index 0000000000..60a05a7e3c --- /dev/null +++ b/includes/api/ApiQueryAllImages.php @@ -0,0 +1,267 @@ +mRepo = RepoGroup::singleton()->getLocalRepo(); + } + + /** + * Override parent method to make sure to make sure the repo's DB is used + * which may not necesarilly be the same as the local DB. + * + * TODO: allow querying non-local repos. + * @return DatabaseBase + */ + protected function getDB() { + return $this->mRepo->getSlaveDB(); + } + + public function execute() { + $this->run(); + } + + public function getCacheMode( $params ) { + return 'public'; + } + + /** + * @param $resultPageSet ApiPageSet + * @return void + */ + public function executeGenerator( $resultPageSet ) { + if ( $resultPageSet->isResolvingRedirects() ) { + $this->dieUsage( 'Use "gaifilterredir=nonredirects" option instead of "redirects" when using allimages as a generator', 'params' ); + } + + $this->run( $resultPageSet ); + } + + /** + * @param $resultPageSet ApiPageSet + * @return void + */ + private function run( $resultPageSet = null ) { + $repo = $this->mRepo; + if ( !$repo instanceof LocalRepo ) { + $this->dieUsage( 'Local file repository does not support querying all images', 'unsupportedrepo' ); + } + + $db = $this->getDB(); + + $params = $this->extractRequestParams(); + + // Image filters + $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' ); + $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) ); + $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) ); + $this->addWhereRange( 'img_name', $dir, $from, $to ); + + if ( isset( $params['prefix'] ) ) + $this->addWhere( 'img_name' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) ); + + if ( isset( $params['minsize'] ) ) { + $this->addWhere( 'img_size>=' . intval( $params['minsize'] ) ); + } + + if ( isset( $params['maxsize'] ) ) { + $this->addWhere( 'img_size<=' . intval( $params['maxsize'] ) ); + } + + $sha1 = false; + if ( isset( $params['sha1'] ) ) { + if ( !$this->validateSha1Hash( $params['sha1'] ) ) { + $this->dieUsage( 'The SHA1 hash provided is not valid', 'invalidsha1hash' ); + } + $sha1 = wfBaseConvert( $params['sha1'], 16, 36, 31 ); + } elseif ( isset( $params['sha1base36'] ) ) { + $sha1 = $params['sha1base36']; + if ( !$this->validateSha1Base36Hash( $sha1 ) ) { + $this->dieUsage( 'The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash' ); + } + } + if ( $sha1 ) { + $this->addWhereFld( 'img_sha1', $sha1 ); + } + + if ( !is_null( $params['mime'] ) ) { + global $wgMiserMode; + if ( $wgMiserMode ) { + $this->dieUsage( 'MIME search disabled in Miser Mode', 'mimesearchdisabled' ); + } + + list( $major, $minor ) = File::splitMime( $params['mime'] ); + + $this->addWhereFld( 'img_major_mime', $major ); + $this->addWhereFld( 'img_minor_mime', $minor ); + } + + $this->addTables( 'image' ); + + $prop = array_flip( $params['prop'] ); + $this->addFields( LocalFile::selectFields() ); + + $limit = $params['limit']; + $this->addOption( 'LIMIT', $limit + 1 ); + $this->addOption( 'ORDER BY', 'img_name' . + ( $params['dir'] == 'descending' ? ' DESC' : '' ) ); + + $res = $this->select( __METHOD__ ); + + $titles = array(); + $count = 0; + $result = $this->getResult(); + foreach ( $res as $row ) { + if ( ++ $count > $limit ) { + // We've reached the one extra which shows that there are additional pages to be had. Stop here... + // TODO: Security issue - if the user has no right to view next title, it will still be shown + $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->img_name ) ); + break; + } + + if ( is_null( $resultPageSet ) ) { + $file = $repo->newFileFromRow( $row ); + $info = array_merge( array( 'name' => $row->img_name ), + ApiQueryImageInfo::getInfo( $file, $prop, $result ) ); + self::addTitleInfo( $info, $file->getTitle() ); + + $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $info ); + if ( !$fit ) { + $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->img_name ) ); + break; + } + } else { + $titles[] = Title::makeTitle( NS_IMAGE, $row->img_name ); + } + } + + if ( is_null( $resultPageSet ) ) { + $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'img' ); + } else { + $resultPageSet->populateFromTitles( $titles ); + } + } + + public function getAllowedParams() { + return array ( + 'from' => null, + 'to' => null, + 'prefix' => null, + 'minsize' => array( + ApiBase::PARAM_TYPE => 'integer', + ), + 'maxsize' => array( + ApiBase::PARAM_TYPE => 'integer', + ), + '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 => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), + 'sha1' => null, + 'sha1base36' => null, + 'prop' => array( + ApiBase::PARAM_TYPE => ApiQueryImageInfo::getPropertyNames( $this->propertyFilter ), + ApiBase::PARAM_DFLT => 'timestamp|url', + ApiBase::PARAM_ISMULTI => true + ), + 'mime' => null, + ); + } + + public function getParamDescription() { + return array( + 'from' => 'The image title to start enumerating from', + 'to' => 'The image title to stop enumerating at', + 'prefix' => 'Search for all image titles that begin with this value', + 'dir' => 'The direction in which to list', + 'minsize' => 'Limit to images with at least this many bytes', + 'maxsize' => 'Limit to images with at most this many bytes', + 'limit' => 'How many images in total to return', + 'sha1' => "SHA1 hash of image. Overrides {$this->getModulePrefix()}sha1base36", + 'sha1base36' => 'SHA1 hash of image in base 36 (used in MediaWiki)', + 'prop' => ApiQueryImageInfo::getPropertyDescriptions( $this->propertyFilter ), + 'mime' => 'What MIME type to search for. e.g. image/jpeg. Disabled in Miser Mode', + ); + } + + private $propertyFilter = array( 'archivename' ); + + public function getDescription() { + return 'Enumerate all images sequentially'; + } + + public function getPossibleErrors() { + return array_merge( parent::getPossibleErrors(), array( + array( 'code' => 'params', 'info' => 'Use "gaifilterredir=nonredirects" option instead of "redirects" when using allimages as a generator' ), + array( 'code' => 'unsupportedrepo', 'info' => 'Local file repository does not support querying all images' ), + array( 'code' => 'mimesearchdisabled', 'info' => 'MIME search disabled in Miser Mode' ), + array( 'code' => 'invalidsha1hash', 'info' => 'The SHA1 hash provided is not valid' ), + array( 'code' => 'invalidsha1base36hash', 'info' => 'The SHA1Base36 hash provided is not valid' ), + ) ); + } + + public function getExamples() { + return array( + 'api.php?action=query&list=allimages&aifrom=B' => array( + 'Simple Use', + 'Show a list of images starting at the letter "B"', + ), + 'api.php?action=query&generator=allimages&gailimit=4&gaifrom=T&prop=imageinfo' => array( + 'Using as Generator', + 'Show info about 4 images starting at the letter "T"', + ), + ); + } + + public function getHelpUrls() { + return 'https://www.mediawiki.org/wiki/API:Allimages'; + } + + public function getVersion() { + return __CLASS__ . ': $Id$'; + } +} diff --git a/includes/api/ApiQueryAllMessages.php b/includes/api/ApiQueryAllMessages.php new file mode 100644 index 0000000000..dedd3e5c30 --- /dev/null +++ b/includes/api/ApiQueryAllMessages.php @@ -0,0 +1,277 @@ +@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +/** + * A query action to return messages from site message cache + * + * @ingroup API + */ +class ApiQueryAllMessages extends ApiQueryBase { + + public function __construct( $query, $moduleName ) { + parent::__construct( $query, $moduleName, 'am' ); + } + + public function execute() { + $params = $this->extractRequestParams(); + + if ( is_null( $params['lang'] ) ) { + global $wgLang; + $langObj = $wgLang; + } else { + $langObj = Language::factory( $params['lang'] ); + } + + if ( $params['enableparser'] ) { + if ( !is_null( $params['title'] ) ) { + $title = Title::newFromText( $params['title'] ); + if ( !$title ) { + $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) ); + } + } else { + $title = Title::newFromText( 'API' ); + } + } + + $prop = array_flip( (array)$params['prop'] ); + + // Determine which messages should we print + if ( in_array( '*', $params['messages'] ) ) { + $message_names = Language::getMessageKeysFor( $langObj->getCode() ); + if ( $params['includelocal'] ) { + global $wgLanguageCode; + $message_names = array_unique( array_merge( + $message_names, + // Pass in the content language code so we get local messages that have a + // MediaWiki:msgkey page. We might theoretically miss messages that have no + // MediaWiki:msgkey page but do have a MediaWiki:msgkey/lang page, but that's + // just a stupid case. + MessageCache::singleton()->getAllMessageKeys( $wgLanguageCode ) + ) ); + } + sort( $message_names ); + $messages_target = $message_names; + } else { + $messages_target = $params['messages']; + } + + // Filter messages that have the specified prefix + // Because we sorted the message array earlier, they will appear in a clump: + if ( isset( $params['prefix'] ) ) { + $skip = false; + $messages_filtered = array(); + foreach ( $messages_target as $message ) { + // === 0: must be at beginning of string (position 0) + if ( strpos( $message, $params['prefix'] ) === 0 ) { + if( !$skip ) { + $skip = true; + } + $messages_filtered[] = $message; + } elseif ( $skip ) { + break; + } + } + $messages_target = $messages_filtered; + } + + // Filter messages that contain specified string + if ( isset( $params['filter'] ) ) { + $messages_filtered = array(); + foreach ( $messages_target as $message ) { + // !== is used because filter can be at the beginning of the string + if ( strpos( $message, $params['filter'] ) !== false ) { + $messages_filtered[] = $message; + } + } + $messages_target = $messages_filtered; + } + + // Whether we have any sort of message customisation filtering + $customiseFilterEnabled = $params['customised'] !== 'all'; + if ( $customiseFilterEnabled ) { + global $wgContLang; + $lang = $langObj->getCode(); + + $customisedMessages = AllmessagesTablePager::getCustomisedStatuses( + array_map( array( $langObj, 'ucfirst'), $messages_target ), $lang, $lang != $wgContLang->getCode() ); + + $customised = $params['customised'] === 'modified'; + } + + // Get all requested messages and print the result + $skip = !is_null( $params['from'] ); + $useto = !is_null( $params['to'] ); + $result = $this->getResult(); + foreach ( $messages_target as $message ) { + // Skip all messages up to $params['from'] + if ( $skip && $message === $params['from'] ) { + $skip = false; + } + + if ( $useto && $message > $params['to'] ) { + break; + } + + if ( !$skip ) { + $a = array( 'name' => $message ); + $args = array(); + if ( isset( $params['args'] ) && count( $params['args'] ) != 0 ) { + $args = $params['args']; + } + + if ( $customiseFilterEnabled ) { + $messageIsCustomised = isset( $customisedMessages['pages'][ $langObj->ucfirst( $message ) ] ); + if ( $customised === $messageIsCustomised ) { + if ( $customised ) { + $a['customised'] = ''; + } + } else { + continue; + } + } + + $msg = wfMessage( $message, $args )->inLanguage( $langObj ); + + if ( !$msg->exists() ) { + $a['missing'] = ''; + } else { + // Check if the parser is enabled: + if ( $params['enableparser'] ) { + $msgString = $msg->title( $title )->text(); + } else { + $msgString = $msg->plain(); + } + if ( !$params['nocontent'] ) { + ApiResult::setContent( $a, $msgString ); + } + if ( isset( $prop['default'] ) ) { + $default = wfMessage( $message )->inLanguage( $langObj )->useDatabase( false ); + if ( !$default->exists() ) { + $a['defaultmissing'] = ''; + } elseif ( $default->plain() != $msgString ) { + $a['default'] = $default->plain(); + } + } + } + $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $a ); + if ( !$fit ) { + $this->setContinueEnumParameter( 'from', $message ); + break; + } + } + } + $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'message' ); + } + + public function getCacheMode( $params ) { + if ( is_null( $params['lang'] ) ) { + // Language not specified, will be fetched from preferences + return 'anon-public-user-private'; + } elseif ( $params['enableparser'] ) { + // User-specific parser options will be used + return 'anon-public-user-private'; + } else { + // OK to cache + return 'public'; + } + } + + public function getAllowedParams() { + return array( + 'messages' => array( + ApiBase::PARAM_DFLT => '*', + ApiBase::PARAM_ISMULTI => true, + ), + 'prop' => array( + ApiBase::PARAM_ISMULTI => true, + ApiBase::PARAM_TYPE => array( + 'default' + ) + ), + 'enableparser' => false, + 'nocontent' => false, + 'includelocal' => false, + 'args' => array( + ApiBase::PARAM_ISMULTI => true, + ApiBase::PARAM_ALLOW_DUPLICATES => true, + ), + 'filter' => array(), + 'customised' => array( + ApiBase::PARAM_DFLT => 'all', + ApiBase::PARAM_TYPE => array( + 'all', + 'modified', + 'unmodified' + ) + ), + 'lang' => null, + 'from' => null, + 'to' => null, + 'title' => null, + 'prefix' => null, + ); + } + + public function getParamDescription() { + return array( + 'messages' => 'Which messages to output. "*" (default) means all messages', + 'prop' => 'Which properties to get', + 'enableparser' => array( 'Set to enable parser, will preprocess the wikitext of message', + 'Will substitute magic words, handle templates etc.' ), + 'nocontent' => 'If set, do not include the content of the messages in the output.', + 'includelocal' => array( "Also include local messages, i.e. messages that don't exist in the software but do exist as a MediaWiki: page.", + "This lists all MediaWiki: pages, so it will also list those that aren't 'really' messages such as Common.js", + ), + 'title' => 'Page name to use as context when parsing message (for enableparser option)', + 'args' => 'Arguments to be substituted into message', + 'prefix' => 'Return messages with this prefix', + 'filter' => 'Return only messages with names that contain this string', + 'customised' => 'Return only messages in this customisation state', + 'lang' => 'Return messages in this language', + 'from' => 'Return messages starting at this message', + 'to' => 'Return messages ending at this message', + ); + } + + public function getDescription() { + return 'Return messages from this site'; + } + + public function getExamples() { + return array( + 'api.php?action=query&meta=allmessages&refix=ipb-', + 'api.php?action=query&meta=allmessages&ammessages=august|mainpage&amlang=de', + ); + } + + public function getHelpUrls() { + return 'https://www.mediawiki.org/wiki/API:Meta#allmessages_.2F_am'; + } + + public function getVersion() { + return __CLASS__ . ': $Id$'; + } +} diff --git a/includes/api/ApiQueryAllPages.php b/includes/api/ApiQueryAllPages.php new file mode 100644 index 0000000000..f3254c5b5d --- /dev/null +++ b/includes/api/ApiQueryAllPages.php @@ -0,0 +1,333 @@ +@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +/** + * Query module to enumerate all available pages. + * + * @ingroup API + */ +class ApiQueryAllPages extends ApiQueryGeneratorBase { + + public function __construct( $query, $moduleName ) { + parent::__construct( $query, $moduleName, 'ap' ); + } + + public function execute() { + $this->run(); + } + + public function getCacheMode( $params ) { + return 'public'; + } + + /** + * @param $resultPageSet ApiPageSet + * @return void + */ + public function executeGenerator( $resultPageSet ) { + if ( $resultPageSet->isResolvingRedirects() ) { + $this->dieUsage( 'Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator', 'params' ); + } + + $this->run( $resultPageSet ); + } + + /** + * @param $resultPageSet ApiPageSet + * @return void + */ + private function run( $resultPageSet = null ) { + $db = $this->getDB(); + + $params = $this->extractRequestParams(); + + // Page filters + $this->addTables( 'page' ); + + if ( $params['filterredir'] == 'redirects' ) { + $this->addWhereFld( 'page_is_redirect', 1 ); + } elseif ( $params['filterredir'] == 'nonredirects' ) { + $this->addWhereFld( 'page_is_redirect', 0 ); + } + + $this->addWhereFld( 'page_namespace', $params['namespace'] ); + $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' ); + $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) ); + $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) ); + $this->addWhereRange( 'page_title', $dir, $from, $to ); + + if ( isset( $params['prefix'] ) ) { + $this->addWhere( 'page_title' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) ); + } + + if ( is_null( $resultPageSet ) ) { + $selectFields = array( + 'page_namespace', + 'page_title', + 'page_id' + ); + } else { + $selectFields = $resultPageSet->getPageTableFields(); + } + + $this->addFields( $selectFields ); + $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 ( count( $params['prtype'] ) || $params['prexpiry'] != 'all' ) { + $this->addTables( 'page_restrictions' ); + $this->addWhere( 'page_id=pr_page' ); + $this->addWhere( 'pr_expiry>' . $db->addQuotes( $db->timestamp() ) ); + + if ( count( $params['prtype'] ) ) { + $this->addWhereFld( 'pr_type', $params['prtype'] ); + + if ( isset( $params['prlevel'] ) ) { + // Remove the empty string and '*' from the prlevel array + $prlevel = array_diff( $params['prlevel'], array( '', '*' ) ); + + if ( count( $prlevel ) ) { + $this->addWhereFld( 'pr_level', $prlevel ); + } + } + if ( $params['prfiltercascade'] == 'cascading' ) { + $this->addWhereFld( 'pr_cascade', 1 ); + } elseif ( $params['prfiltercascade'] == 'noncascading' ) { + $this->addWhereFld( 'pr_cascade', 0 ); + } + + $this->addOption( 'DISTINCT' ); + } + $forceNameTitleIndex = false; + + if ( $params['prexpiry'] == 'indefinite' ) { + $this->addWhere( "pr_expiry = {$db->addQuotes( $db->getInfinity() )} OR pr_expiry IS NULL" ); + } elseif ( $params['prexpiry'] == 'definite' ) { + $this->addWhere( "pr_expiry != {$db->addQuotes( $db->getInfinity() )}" ); + } + + } elseif ( isset( $params['prlevel'] ) ) { + $this->dieUsage( 'prlevel may not be used without prtype', 'params' ); + } + + if ( $params['filterlanglinks'] == 'withoutlanglinks' ) { + $this->addTables( 'langlinks' ); + $this->addJoinConds( array( 'langlinks' => array( 'LEFT JOIN', 'page_id=ll_from' ) ) ); + $this->addWhere( 'll_from IS NULL' ); + $forceNameTitleIndex = false; + } elseif ( $params['filterlanglinks'] == 'withlanglinks' ) { + $this->addTables( 'langlinks' ); + $this->addWhere( 'page_id=ll_from' ); + $this->addOption( 'STRAIGHT_JOIN' ); + // We have to GROUP BY all selected fields to stop + // PostgreSQL from whining + $this->addOption( 'GROUP BY', implode( ', ', $selectFields ) ); + $forceNameTitleIndex = false; + } + + if ( $forceNameTitleIndex ) { + $this->addOption( 'USE INDEX', 'name_title' ); + } + + $limit = $params['limit']; + $this->addOption( 'LIMIT', $limit + 1 ); + $res = $this->select( __METHOD__ ); + + $count = 0; + $result = $this->getResult(); + foreach ( $res as $row ) { + if ( ++ $count > $limit ) { + // We've reached the one extra which shows that there are additional pages to be had. Stop here... + // TODO: Security issue - if the user has no right to view next title, it will still be shown + $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->page_title ) ); + break; + } + + if ( is_null( $resultPageSet ) ) { + $title = Title::makeTitle( $row->page_namespace, $row->page_title ); + $vals = array( + 'pageid' => intval( $row->page_id ), + 'ns' => intval( $title->getNamespace() ), + 'title' => $title->getPrefixedText() + ); + $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $vals ); + if ( !$fit ) { + $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->page_title ) ); + break; + } + } else { + $resultPageSet->processDbRow( $row ); + } + } + + if ( is_null( $resultPageSet ) ) { + $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'p' ); + } + } + + public function getAllowedParams() { + global $wgRestrictionLevels; + + return array( + 'from' => null, + 'to' => 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 => Title::getFilteredRestrictionTypes( true ), + ApiBase::PARAM_ISMULTI => true + ), + 'prlevel' => array( + ApiBase::PARAM_TYPE => $wgRestrictionLevels, + ApiBase::PARAM_ISMULTI => true + ), + 'prfiltercascade' => array( + ApiBase::PARAM_DFLT => 'all', + ApiBase::PARAM_TYPE => array( + 'cascading', + 'noncascading', + 'all' + ), + ), + '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 => 'ascending', + ApiBase::PARAM_TYPE => array( + 'ascending', + 'descending' + ) + ), + 'filterlanglinks' => array( + ApiBase::PARAM_TYPE => array( + 'withlanglinks', + 'withoutlanglinks', + 'all' + ), + ApiBase::PARAM_DFLT => 'all' + ), + 'prexpiry' => array( + ApiBase::PARAM_TYPE => array( + 'indefinite', + 'definite', + 'all' + ), + ApiBase::PARAM_DFLT => 'all' + ), + ); + } + + public function getParamDescription() { + $p = $this->getModulePrefix(); + return array( + 'from' => 'The page title to start enumerating from', + 'to' => 'The page title to stop enumerating at', + '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 {$p}prtype= parameter)", + 'prfiltercascade' => "Filter protections based on cascadingness (ignored when {$p}prtype isn't set)", + 'filterlanglinks' => 'Filter based on whether a page has langlinks', + 'limit' => 'How many total pages to return.', + 'prexpiry' => array( + 'Which protection expiry to filter the page on', + ' indefinite - Get only pages with indefinite protection expiry', + ' definite - Get only pages with a definite (specific) protection expiry', + ' all - Get pages with any protections expiry' + ), + ); + } + + public function getDescription() { + return 'Enumerate all pages sequentially in a given namespace'; + } + + public function getPossibleErrors() { + return array_merge( parent::getPossibleErrors(), array( + array( 'code' => 'params', 'info' => 'Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator' ), + array( 'code' => 'params', 'info' => 'prlevel may not be used without prtype' ), + ) ); + } + + public function getExamples() { + return array( + 'api.php?action=query&list=allpages&apfrom=B' => array( + 'Simple Use', + 'Show a list of pages starting at the letter "B"', + ), + 'api.php?action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info' => array( + 'Using as Generator', + 'Show info about 4 pages starting at the letter "T"', + ), + 'api.php?action=query&generator=allpages&gaplimit=2&gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content' => array( + 'Show content of first 2 non-redirect pages begining at "Re"', + ) + ); + } + + public function getHelpUrls() { + return 'https://www.mediawiki.org/wiki/API:Allpages'; + } + + public function getVersion() { + return __CLASS__ . ': $Id$'; + } +} diff --git a/includes/api/ApiQueryAllimages.php b/includes/api/ApiQueryAllimages.php deleted file mode 100644 index ca344f7337..0000000000 --- a/includes/api/ApiQueryAllimages.php +++ /dev/null @@ -1,267 +0,0 @@ -mRepo = RepoGroup::singleton()->getLocalRepo(); - } - - /** - * Override parent method to make sure to make sure the repo's DB is used - * which may not necesarilly be the same as the local DB. - * - * TODO: allow querying non-local repos. - * @return DatabaseBase - */ - protected function getDB() { - return $this->mRepo->getSlaveDB(); - } - - public function execute() { - $this->run(); - } - - public function getCacheMode( $params ) { - return 'public'; - } - - /** - * @param $resultPageSet ApiPageSet - * @return void - */ - public function executeGenerator( $resultPageSet ) { - if ( $resultPageSet->isResolvingRedirects() ) { - $this->dieUsage( 'Use "gaifilterredir=nonredirects" option instead of "redirects" when using allimages as a generator', 'params' ); - } - - $this->run( $resultPageSet ); - } - - /** - * @param $resultPageSet ApiPageSet - * @return void - */ - private function run( $resultPageSet = null ) { - $repo = $this->mRepo; - if ( !$repo instanceof LocalRepo ) { - $this->dieUsage( 'Local file repository does not support querying all images', 'unsupportedrepo' ); - } - - $db = $this->getDB(); - - $params = $this->extractRequestParams(); - - // Image filters - $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' ); - $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) ); - $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) ); - $this->addWhereRange( 'img_name', $dir, $from, $to ); - - if ( isset( $params['prefix'] ) ) - $this->addWhere( 'img_name' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) ); - - if ( isset( $params['minsize'] ) ) { - $this->addWhere( 'img_size>=' . intval( $params['minsize'] ) ); - } - - if ( isset( $params['maxsize'] ) ) { - $this->addWhere( 'img_size<=' . intval( $params['maxsize'] ) ); - } - - $sha1 = false; - if ( isset( $params['sha1'] ) ) { - if ( !$this->validateSha1Hash( $params['sha1'] ) ) { - $this->dieUsage( 'The SHA1 hash provided is not valid', 'invalidsha1hash' ); - } - $sha1 = wfBaseConvert( $params['sha1'], 16, 36, 31 ); - } elseif ( isset( $params['sha1base36'] ) ) { - $sha1 = $params['sha1base36']; - if ( !$this->validateSha1Base36Hash( $sha1 ) ) { - $this->dieUsage( 'The SHA1Base36 hash provided is not valid', 'invalidsha1base36hash' ); - } - } - if ( $sha1 ) { - $this->addWhereFld( 'img_sha1', $sha1 ); - } - - if ( !is_null( $params['mime'] ) ) { - global $wgMiserMode; - if ( $wgMiserMode ) { - $this->dieUsage( 'MIME search disabled in Miser Mode', 'mimesearchdisabled' ); - } - - list( $major, $minor ) = File::splitMime( $params['mime'] ); - - $this->addWhereFld( 'img_major_mime', $major ); - $this->addWhereFld( 'img_minor_mime', $minor ); - } - - $this->addTables( 'image' ); - - $prop = array_flip( $params['prop'] ); - $this->addFields( LocalFile::selectFields() ); - - $limit = $params['limit']; - $this->addOption( 'LIMIT', $limit + 1 ); - $this->addOption( 'ORDER BY', 'img_name' . - ( $params['dir'] == 'descending' ? ' DESC' : '' ) ); - - $res = $this->select( __METHOD__ ); - - $titles = array(); - $count = 0; - $result = $this->getResult(); - foreach ( $res as $row ) { - if ( ++ $count > $limit ) { - // We've reached the one extra which shows that there are additional pages to be had. Stop here... - // TODO: Security issue - if the user has no right to view next title, it will still be shown - $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->img_name ) ); - break; - } - - if ( is_null( $resultPageSet ) ) { - $file = $repo->newFileFromRow( $row ); - $info = array_merge( array( 'name' => $row->img_name ), - ApiQueryImageInfo::getInfo( $file, $prop, $result ) ); - self::addTitleInfo( $info, $file->getTitle() ); - - $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $info ); - if ( !$fit ) { - $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->img_name ) ); - break; - } - } else { - $titles[] = Title::makeTitle( NS_IMAGE, $row->img_name ); - } - } - - if ( is_null( $resultPageSet ) ) { - $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'img' ); - } else { - $resultPageSet->populateFromTitles( $titles ); - } - } - - public function getAllowedParams() { - return array ( - 'from' => null, - 'to' => null, - 'prefix' => null, - 'minsize' => array( - ApiBase::PARAM_TYPE => 'integer', - ), - 'maxsize' => array( - ApiBase::PARAM_TYPE => 'integer', - ), - '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 => 'ascending', - ApiBase::PARAM_TYPE => array( - 'ascending', - 'descending' - ) - ), - 'sha1' => null, - 'sha1base36' => null, - 'prop' => array( - ApiBase::PARAM_TYPE => ApiQueryImageInfo::getPropertyNames( $this->propertyFilter ), - ApiBase::PARAM_DFLT => 'timestamp|url', - ApiBase::PARAM_ISMULTI => true - ), - 'mime' => null, - ); - } - - public function getParamDescription() { - return array( - 'from' => 'The image title to start enumerating from', - 'to' => 'The image title to stop enumerating at', - 'prefix' => 'Search for all image titles that begin with this value', - 'dir' => 'The direction in which to list', - 'minsize' => 'Limit to images with at least this many bytes', - 'maxsize' => 'Limit to images with at most this many bytes', - 'limit' => 'How many images in total to return', - 'sha1' => "SHA1 hash of image. Overrides {$this->getModulePrefix()}sha1base36", - 'sha1base36' => 'SHA1 hash of image in base 36 (used in MediaWiki)', - 'prop' => ApiQueryImageInfo::getPropertyDescriptions( $this->propertyFilter ), - 'mime' => 'What MIME type to search for. e.g. image/jpeg. Disabled in Miser Mode', - ); - } - - private $propertyFilter = array( 'archivename' ); - - public function getDescription() { - return 'Enumerate all images sequentially'; - } - - public function getPossibleErrors() { - return array_merge( parent::getPossibleErrors(), array( - array( 'code' => 'params', 'info' => 'Use "gaifilterredir=nonredirects" option instead of "redirects" when using allimages as a generator' ), - array( 'code' => 'unsupportedrepo', 'info' => 'Local file repository does not support querying all images' ), - array( 'code' => 'mimesearchdisabled', 'info' => 'MIME search disabled in Miser Mode' ), - array( 'code' => 'invalidsha1hash', 'info' => 'The SHA1 hash provided is not valid' ), - array( 'code' => 'invalidsha1base36hash', 'info' => 'The SHA1Base36 hash provided is not valid' ), - ) ); - } - - public function getExamples() { - return array( - 'api.php?action=query&list=allimages&aifrom=B' => array( - 'Simple Use', - 'Show a list of images starting at the letter "B"', - ), - 'api.php?action=query&generator=allimages&gailimit=4&gaifrom=T&prop=imageinfo' => array( - 'Using as Generator', - 'Show info about 4 images starting at the letter "T"', - ), - ); - } - - public function getHelpUrls() { - return 'https://www.mediawiki.org/wiki/API:Allimages'; - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryAllmessages.php b/includes/api/ApiQueryAllmessages.php deleted file mode 100644 index 44774927ee..0000000000 --- a/includes/api/ApiQueryAllmessages.php +++ /dev/null @@ -1,277 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * @file - */ - -/** - * A query action to return messages from site message cache - * - * @ingroup API - */ -class ApiQueryAllmessages extends ApiQueryBase { - - public function __construct( $query, $moduleName ) { - parent::__construct( $query, $moduleName, 'am' ); - } - - public function execute() { - $params = $this->extractRequestParams(); - - if ( is_null( $params['lang'] ) ) { - global $wgLang; - $langObj = $wgLang; - } else { - $langObj = Language::factory( $params['lang'] ); - } - - if ( $params['enableparser'] ) { - if ( !is_null( $params['title'] ) ) { - $title = Title::newFromText( $params['title'] ); - if ( !$title ) { - $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) ); - } - } else { - $title = Title::newFromText( 'API' ); - } - } - - $prop = array_flip( (array)$params['prop'] ); - - // Determine which messages should we print - if ( in_array( '*', $params['messages'] ) ) { - $message_names = Language::getMessageKeysFor( $langObj->getCode() ); - if ( $params['includelocal'] ) { - global $wgLanguageCode; - $message_names = array_unique( array_merge( - $message_names, - // Pass in the content language code so we get local messages that have a - // MediaWiki:msgkey page. We might theoretically miss messages that have no - // MediaWiki:msgkey page but do have a MediaWiki:msgkey/lang page, but that's - // just a stupid case. - MessageCache::singleton()->getAllMessageKeys( $wgLanguageCode ) - ) ); - } - sort( $message_names ); - $messages_target = $message_names; - } else { - $messages_target = $params['messages']; - } - - // Filter messages that have the specified prefix - // Because we sorted the message array earlier, they will appear in a clump: - if ( isset( $params['prefix'] ) ) { - $skip = false; - $messages_filtered = array(); - foreach ( $messages_target as $message ) { - // === 0: must be at beginning of string (position 0) - if ( strpos( $message, $params['prefix'] ) === 0 ) { - if( !$skip ) { - $skip = true; - } - $messages_filtered[] = $message; - } elseif ( $skip ) { - break; - } - } - $messages_target = $messages_filtered; - } - - // Filter messages that contain specified string - if ( isset( $params['filter'] ) ) { - $messages_filtered = array(); - foreach ( $messages_target as $message ) { - // !== is used because filter can be at the beginning of the string - if ( strpos( $message, $params['filter'] ) !== false ) { - $messages_filtered[] = $message; - } - } - $messages_target = $messages_filtered; - } - - // Whether we have any sort of message customisation filtering - $customiseFilterEnabled = $params['customised'] !== 'all'; - if ( $customiseFilterEnabled ) { - global $wgContLang; - $lang = $langObj->getCode(); - - $customisedMessages = AllmessagesTablePager::getCustomisedStatuses( - array_map( array( $langObj, 'ucfirst'), $messages_target ), $lang, $lang != $wgContLang->getCode() ); - - $customised = $params['customised'] === 'modified'; - } - - // Get all requested messages and print the result - $skip = !is_null( $params['from'] ); - $useto = !is_null( $params['to'] ); - $result = $this->getResult(); - foreach ( $messages_target as $message ) { - // Skip all messages up to $params['from'] - if ( $skip && $message === $params['from'] ) { - $skip = false; - } - - if ( $useto && $message > $params['to'] ) { - break; - } - - if ( !$skip ) { - $a = array( 'name' => $message ); - $args = array(); - if ( isset( $params['args'] ) && count( $params['args'] ) != 0 ) { - $args = $params['args']; - } - - if ( $customiseFilterEnabled ) { - $messageIsCustomised = isset( $customisedMessages['pages'][ $langObj->ucfirst( $message ) ] ); - if ( $customised === $messageIsCustomised ) { - if ( $customised ) { - $a['customised'] = ''; - } - } else { - continue; - } - } - - $msg = wfMessage( $message, $args )->inLanguage( $langObj ); - - if ( !$msg->exists() ) { - $a['missing'] = ''; - } else { - // Check if the parser is enabled: - if ( $params['enableparser'] ) { - $msgString = $msg->title( $title )->text(); - } else { - $msgString = $msg->plain(); - } - if ( !$params['nocontent'] ) { - ApiResult::setContent( $a, $msgString ); - } - if ( isset( $prop['default'] ) ) { - $default = wfMessage( $message )->inLanguage( $langObj )->useDatabase( false ); - if ( !$default->exists() ) { - $a['defaultmissing'] = ''; - } elseif ( $default->plain() != $msgString ) { - $a['default'] = $default->plain(); - } - } - } - $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $a ); - if ( !$fit ) { - $this->setContinueEnumParameter( 'from', $message ); - break; - } - } - } - $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'message' ); - } - - public function getCacheMode( $params ) { - if ( is_null( $params['lang'] ) ) { - // Language not specified, will be fetched from preferences - return 'anon-public-user-private'; - } elseif ( $params['enableparser'] ) { - // User-specific parser options will be used - return 'anon-public-user-private'; - } else { - // OK to cache - return 'public'; - } - } - - public function getAllowedParams() { - return array( - 'messages' => array( - ApiBase::PARAM_DFLT => '*', - ApiBase::PARAM_ISMULTI => true, - ), - 'prop' => array( - ApiBase::PARAM_ISMULTI => true, - ApiBase::PARAM_TYPE => array( - 'default' - ) - ), - 'enableparser' => false, - 'nocontent' => false, - 'includelocal' => false, - 'args' => array( - ApiBase::PARAM_ISMULTI => true, - ApiBase::PARAM_ALLOW_DUPLICATES => true, - ), - 'filter' => array(), - 'customised' => array( - ApiBase::PARAM_DFLT => 'all', - ApiBase::PARAM_TYPE => array( - 'all', - 'modified', - 'unmodified' - ) - ), - 'lang' => null, - 'from' => null, - 'to' => null, - 'title' => null, - 'prefix' => null, - ); - } - - public function getParamDescription() { - return array( - 'messages' => 'Which messages to output. "*" (default) means all messages', - 'prop' => 'Which properties to get', - 'enableparser' => array( 'Set to enable parser, will preprocess the wikitext of message', - 'Will substitute magic words, handle templates etc.' ), - 'nocontent' => 'If set, do not include the content of the messages in the output.', - 'includelocal' => array( "Also include local messages, i.e. messages that don't exist in the software but do exist as a MediaWiki: page.", - "This lists all MediaWiki: pages, so it will also list those that aren't 'really' messages such as Common.js", - ), - 'title' => 'Page name to use as context when parsing message (for enableparser option)', - 'args' => 'Arguments to be substituted into message', - 'prefix' => 'Return messages with this prefix', - 'filter' => 'Return only messages with names that contain this string', - 'customised' => 'Return only messages in this customisation state', - 'lang' => 'Return messages in this language', - 'from' => 'Return messages starting at this message', - 'to' => 'Return messages ending at this message', - ); - } - - public function getDescription() { - return 'Return messages from this site'; - } - - public function getExamples() { - return array( - 'api.php?action=query&meta=allmessages&refix=ipb-', - 'api.php?action=query&meta=allmessages&ammessages=august|mainpage&amlang=de', - ); - } - - public function getHelpUrls() { - return 'https://www.mediawiki.org/wiki/API:Meta#allmessages_.2F_am'; - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryAllpages.php b/includes/api/ApiQueryAllpages.php deleted file mode 100644 index e003ee9115..0000000000 --- a/includes/api/ApiQueryAllpages.php +++ /dev/null @@ -1,333 +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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * @file - */ - -/** - * Query module to enumerate all available pages. - * - * @ingroup API - */ -class ApiQueryAllpages extends ApiQueryGeneratorBase { - - public function __construct( $query, $moduleName ) { - parent::__construct( $query, $moduleName, 'ap' ); - } - - public function execute() { - $this->run(); - } - - public function getCacheMode( $params ) { - return 'public'; - } - - /** - * @param $resultPageSet ApiPageSet - * @return void - */ - public function executeGenerator( $resultPageSet ) { - if ( $resultPageSet->isResolvingRedirects() ) { - $this->dieUsage( 'Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator', 'params' ); - } - - $this->run( $resultPageSet ); - } - - /** - * @param $resultPageSet ApiPageSet - * @return void - */ - private function run( $resultPageSet = null ) { - $db = $this->getDB(); - - $params = $this->extractRequestParams(); - - // Page filters - $this->addTables( 'page' ); - - if ( $params['filterredir'] == 'redirects' ) { - $this->addWhereFld( 'page_is_redirect', 1 ); - } elseif ( $params['filterredir'] == 'nonredirects' ) { - $this->addWhereFld( 'page_is_redirect', 0 ); - } - - $this->addWhereFld( 'page_namespace', $params['namespace'] ); - $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' ); - $from = ( is_null( $params['from'] ) ? null : $this->titlePartToKey( $params['from'] ) ); - $to = ( is_null( $params['to'] ) ? null : $this->titlePartToKey( $params['to'] ) ); - $this->addWhereRange( 'page_title', $dir, $from, $to ); - - if ( isset( $params['prefix'] ) ) { - $this->addWhere( 'page_title' . $db->buildLike( $this->titlePartToKey( $params['prefix'] ), $db->anyString() ) ); - } - - if ( is_null( $resultPageSet ) ) { - $selectFields = array( - 'page_namespace', - 'page_title', - 'page_id' - ); - } else { - $selectFields = $resultPageSet->getPageTableFields(); - } - - $this->addFields( $selectFields ); - $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 ( count( $params['prtype'] ) || $params['prexpiry'] != 'all' ) { - $this->addTables( 'page_restrictions' ); - $this->addWhere( 'page_id=pr_page' ); - $this->addWhere( 'pr_expiry>' . $db->addQuotes( $db->timestamp() ) ); - - if ( count( $params['prtype'] ) ) { - $this->addWhereFld( 'pr_type', $params['prtype'] ); - - if ( isset( $params['prlevel'] ) ) { - // Remove the empty string and '*' from the prlevel array - $prlevel = array_diff( $params['prlevel'], array( '', '*' ) ); - - if ( count( $prlevel ) ) { - $this->addWhereFld( 'pr_level', $prlevel ); - } - } - if ( $params['prfiltercascade'] == 'cascading' ) { - $this->addWhereFld( 'pr_cascade', 1 ); - } elseif ( $params['prfiltercascade'] == 'noncascading' ) { - $this->addWhereFld( 'pr_cascade', 0 ); - } - - $this->addOption( 'DISTINCT' ); - } - $forceNameTitleIndex = false; - - if ( $params['prexpiry'] == 'indefinite' ) { - $this->addWhere( "pr_expiry = {$db->addQuotes( $db->getInfinity() )} OR pr_expiry IS NULL" ); - } elseif ( $params['prexpiry'] == 'definite' ) { - $this->addWhere( "pr_expiry != {$db->addQuotes( $db->getInfinity() )}" ); - } - - } elseif ( isset( $params['prlevel'] ) ) { - $this->dieUsage( 'prlevel may not be used without prtype', 'params' ); - } - - if ( $params['filterlanglinks'] == 'withoutlanglinks' ) { - $this->addTables( 'langlinks' ); - $this->addJoinConds( array( 'langlinks' => array( 'LEFT JOIN', 'page_id=ll_from' ) ) ); - $this->addWhere( 'll_from IS NULL' ); - $forceNameTitleIndex = false; - } elseif ( $params['filterlanglinks'] == 'withlanglinks' ) { - $this->addTables( 'langlinks' ); - $this->addWhere( 'page_id=ll_from' ); - $this->addOption( 'STRAIGHT_JOIN' ); - // We have to GROUP BY all selected fields to stop - // PostgreSQL from whining - $this->addOption( 'GROUP BY', implode( ', ', $selectFields ) ); - $forceNameTitleIndex = false; - } - - if ( $forceNameTitleIndex ) { - $this->addOption( 'USE INDEX', 'name_title' ); - } - - $limit = $params['limit']; - $this->addOption( 'LIMIT', $limit + 1 ); - $res = $this->select( __METHOD__ ); - - $count = 0; - $result = $this->getResult(); - foreach ( $res as $row ) { - if ( ++ $count > $limit ) { - // We've reached the one extra which shows that there are additional pages to be had. Stop here... - // TODO: Security issue - if the user has no right to view next title, it will still be shown - $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->page_title ) ); - break; - } - - if ( is_null( $resultPageSet ) ) { - $title = Title::makeTitle( $row->page_namespace, $row->page_title ); - $vals = array( - 'pageid' => intval( $row->page_id ), - 'ns' => intval( $title->getNamespace() ), - 'title' => $title->getPrefixedText() - ); - $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $vals ); - if ( !$fit ) { - $this->setContinueEnumParameter( 'from', $this->keyToTitle( $row->page_title ) ); - break; - } - } else { - $resultPageSet->processDbRow( $row ); - } - } - - if ( is_null( $resultPageSet ) ) { - $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'p' ); - } - } - - public function getAllowedParams() { - global $wgRestrictionLevels; - - return array( - 'from' => null, - 'to' => 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 => Title::getFilteredRestrictionTypes( true ), - ApiBase::PARAM_ISMULTI => true - ), - 'prlevel' => array( - ApiBase::PARAM_TYPE => $wgRestrictionLevels, - ApiBase::PARAM_ISMULTI => true - ), - 'prfiltercascade' => array( - ApiBase::PARAM_DFLT => 'all', - ApiBase::PARAM_TYPE => array( - 'cascading', - 'noncascading', - 'all' - ), - ), - '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 => 'ascending', - ApiBase::PARAM_TYPE => array( - 'ascending', - 'descending' - ) - ), - 'filterlanglinks' => array( - ApiBase::PARAM_TYPE => array( - 'withlanglinks', - 'withoutlanglinks', - 'all' - ), - ApiBase::PARAM_DFLT => 'all' - ), - 'prexpiry' => array( - ApiBase::PARAM_TYPE => array( - 'indefinite', - 'definite', - 'all' - ), - ApiBase::PARAM_DFLT => 'all' - ), - ); - } - - public function getParamDescription() { - $p = $this->getModulePrefix(); - return array( - 'from' => 'The page title to start enumerating from', - 'to' => 'The page title to stop enumerating at', - '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 {$p}prtype= parameter)", - 'prfiltercascade' => "Filter protections based on cascadingness (ignored when {$p}prtype isn't set)", - 'filterlanglinks' => 'Filter based on whether a page has langlinks', - 'limit' => 'How many total pages to return.', - 'prexpiry' => array( - 'Which protection expiry to filter the page on', - ' indefinite - Get only pages with indefinite protection expiry', - ' definite - Get only pages with a definite (specific) protection expiry', - ' all - Get pages with any protections expiry' - ), - ); - } - - public function getDescription() { - return 'Enumerate all pages sequentially in a given namespace'; - } - - public function getPossibleErrors() { - return array_merge( parent::getPossibleErrors(), array( - array( 'code' => 'params', 'info' => 'Use "gapfilterredir=nonredirects" option instead of "redirects" when using allpages as a generator' ), - array( 'code' => 'params', 'info' => 'prlevel may not be used without prtype' ), - ) ); - } - - public function getExamples() { - return array( - 'api.php?action=query&list=allpages&apfrom=B' => array( - 'Simple Use', - 'Show a list of pages starting at the letter "B"', - ), - 'api.php?action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info' => array( - 'Using as Generator', - 'Show info about 4 pages starting at the letter "T"', - ), - 'api.php?action=query&generator=allpages&gaplimit=2&gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content' => array( - 'Show content of first 2 non-redirect pages begining at "Re"', - ) - ); - } - - public function getHelpUrls() { - return 'https://www.mediawiki.org/wiki/API:Allpages'; - } - - public function getVersion() { - return __CLASS__ . ': $Id$'; - } -} diff --git a/includes/api/ApiQueryFilearchive.php b/includes/api/ApiQueryFilearchive.php index be995f3086..7bf97d3ec0 100644 --- a/includes/api/ApiQueryFilearchive.php +++ b/includes/api/ApiQueryFilearchive.php @@ -6,7 +6,7 @@ * * Copyright © 2010 Sam Reed * Copyright © 2008 Vasiliev Victor vasilvv@gmail.com, - * based on ApiQueryAllpages.php + * based on ApiQueryAllPages.php * * 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