$fld_sha1 = isset( $prop['sha1'] );
$fld_content = isset( $prop['content'] );
$fld_token = isset( $prop['token'] );
+ $fld_tags = isset( $prop['tags'] );
// If we're in JSON callback mode, no tokens can be obtained
if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) {
$this->addFieldsIf( 'ar_len', $fld_len );
$this->addFieldsIf( 'ar_sha1', $fld_sha1 );
+ if ( $fld_tags ) {
+ $this->addTables( 'tag_summary' );
+ $this->addJoinConds(
+ array( 'tag_summary' => array( 'LEFT JOIN', array( 'ar_rev_id=ts_rev_id' ) ) )
+ );
+ $this->addFields( 'ts_tags' );
+ }
+
+ if ( !is_null( $params['tag'] ) ) {
+ $this->addTables( 'change_tag' );
+ $this->addJoinConds(
+ array( 'change_tag' => array( 'INNER JOIN', array( 'ar_rev_id=ct_rev_id' ) ) )
+ );
+ $this->addWhereFld( 'ct_tag', $params['tag'] );
+ }
+
if ( $fld_content ) {
$this->addTables( 'text' );
$this->addFields( array( 'ar_text', 'ar_text_id', 'old_text', 'old_flags' ) );
ApiResult::setContent( $rev, Revision::getRevisionText( $row ) );
}
+ if ( $fld_tags ) {
+ if ( $row->ts_tags ) {
+ $tags = explode( ',', $row->ts_tags );
+ $this->getResult()->setIndexedTagName( $tags, 'tag' );
+ $rev['tags'] = $tags;
+ } else {
+ $rev['tags'] = array();
+ }
+ }
+
if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
$pageID = $newPageID++;
$pageMap[$row->ar_namespace][$row->ar_title] = $pageID;
'prefix' => null,
'continue' => null,
'unique' => false,
+ 'tag' => null,
'user' => array(
ApiBase::PARAM_TYPE => 'user'
),
'len',
'sha1',
'content',
- 'token'
+ 'token',
+ 'tags'
),
ApiBase::PARAM_ISMULTI => true
),
' sha1 - Adds the SHA-1 (base 16) of the revision',
' content - Adds the content of the revision',
' token - Gives the edit token',
+ ' tags - Tags for the revision',
),
'namespace' => 'Only list pages in this namespace (3)',
'user' => 'Only list revisions by this user',
'excludeuser' => 'Don\'t list revisions by this user',
'continue' => 'When more results are available, use this to continue (1, 3)',
'unique' => 'List only one revision for each page (3)',
+ 'tag' => 'Only list revisions tagged with this tag',
);
}
* $findItem = array( 'title' => $title, 'private' => true );
* $findBatch = array( $findItem );
* $repo->findFiles( $findBatch );
- * @return array
+ *
+ * No title should appear in $items twice, as the result use titles as keys
+ * @return array (Map of file names => File objects) for matches
*/
public function findFiles( array $items ) {
$result = array();
return $id;
}
+ public function findFiles( array $items ) {
+ $finalFiles = array(); // map of (DB key => corresponding File) for matches
+
+ $searchSet = array(); // map of (DB key => normalized search params)
+ foreach ( $items as $item ) {
+ $title = is_array( $item )
+ ? File::normalizeTitle( $item['title'] )
+ : File::normalizeTitle( $item );
+ if ( $title ) { // valid title
+ $searchSet[$title->getDbKey()] = ( is_array( $item ) ? $item : array() );
+ }
+ }
+
+ $fileMatchesSearch = function( File $file, array $search ) {
+ // Note: file name comparison done elsewhere (to handle redirects)
+ return (
+ $file->exists() &&
+ (
+ ( empty( $search['time'] ) && !$file->isOld() ) ||
+ ( !empty( $search['time'] ) && $search['time'] === $file->getTimestamp() )
+ ) &&
+ ( !empty( $search['private'] ) || !$file->isDeleted( File::DELETED_FILE ) ) &&
+ $file->userCan( File::DELETED_FILE )
+ );
+ };
+
+ $repo = $this;
+ $applyMatchingFiles = function( ResultWrapper $res, &$searchSet, &$finalFiles )
+ use ( $repo, $fileMatchesSearch )
+ {
+ foreach ( $res as $row ) {
+ $possFile = $repo->newFileFromRow( $row );
+ $dbKey = $possFile->getName();
+ // There must have been a search for this DB Key
+ if ( $fileMatchesSearch( $possFile, $searchSet[$dbKey] ) ) {
+ $finalFiles[$dbKey] = $possFile;
+ unset( $searchSet[$dbKey] );
+ }
+ }
+ };
+
+ $dbr = $this->getSlaveDB();
+
+ // Query image table
+ $imgNames = array_keys( $searchSet );
+ if ( count( $imgNames ) ) {
+ $res = $dbr->select( 'image',
+ LocalFile::selectFields(), array( 'img_name' => $imgNames ), __METHOD__ );
+ $applyMatchingFiles( $res, $searchSet, $finalFiles );
+ }
+
+ // Query old image table
+ $oiConds = array(); // WHERE clause array for each file
+ foreach ( $searchSet as $dbKey => $search ) {
+ if ( isset( $search['params']['time'] ) ) {
+ $oiConds[] = $dbr->makeList( array( 'oi_name' => $dbKey,
+ 'oi_timestamp' => $dbr->timestamp( $search['params']['time'] ) ), LIST_AND );
+ }
+ }
+ if ( count( $oiConds ) ) {
+ $res = $dbr->select( 'oldimage',
+ OldLocalFile::selectFields(), $dbr->makeList( $oiConds, LIST_OR ), __METHOD__ );
+ $applyMatchingFiles( $res, $searchSet, $finalFiles );
+ }
+
+ // Check for redirects...
+ foreach ( $searchSet as $dbKey => $search ) {
+ if ( !empty( $search['ignoreRedirect'] ) ) {
+ continue;
+ }
+ $title = File::normalizeTitle( $dbKey );
+ $redir = $this->checkRedirect( $title ); // hopefully hits memcached
+ if ( $redir && $redir->getNamespace() == NS_FILE ) {
+ $possFile = $this->newFile( $redir );
+ if ( $possFile && $fileMatchesSearch( $possFile, $search ) ) {
+ $possFile->redirectedFrom( $title->getDBkey() );
+ $finalFiles[$dbKey] = $possFile;
+ }
+ }
+ }
+
+ return $finalFiles;
+ }
+
/**
* Get an array or iterator of file objects for files that have a given
* SHA-1 content hash.
return null;
}
$extension = $this->getExtension();
- list( $thumbExt, $thumbMime ) = $this->handler->getThumbType(
+ list( $thumbExt, ) = $this->handler->getThumbType(
$extension, $this->getMimeType(), $params );
$thumbName = $this->handler->makeParamString( $params ) . '-' . $name;
if ( $thumbExt != $extension ) {
'crh-cyrl' => "къырымтатарджа (Кирилл)\xE2\x80\x8E", # Crimean Tatar (Cyrillic)
'cs' => 'čeština', # Czech
'csb' => 'kaszëbsczi', # Cassubian
- 'cu' => 'словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ', # Old Church Slavonic (ancient language)
+ 'cu' => 'словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ', # Old Church Slavonic (ancient language)
'cv' => 'Чӑвашла', # Chuvash
'cy' => 'Cymraeg', # Welsh
'da' => 'dansk', # Danish
'search-summary' => '', # do not translate or duplicate this message to other languages
'searchresults' => 'Search results',
'searchresults-title' => 'Search results for "$1"',
-'searchresulttext' => 'For more information about searching {{SITENAME}}, see [[{{MediaWiki:Helppage}}|{{int:help}}]].',
-'searchsubtitle' => 'You searched for \'\'\'[[:$1]]\'\'\' ([[Special:Prefixindex/$1|all pages starting with "$1"]]{{int:pipe-separator}}[[Special:WhatLinksHere/$1|all pages that link to "$1"]])',
-'searchsubtitleinvalid' => "You searched for '''$1'''",
'toomanymatches' => 'Too many matches were returned, please try a different query',
'titlematches' => 'Page title matches',
-'notitlematches' => 'No page title matches',
'textmatches' => 'Page text matches',
'notextmatches' => 'No page text matches',
'prevn' => 'previous {{PLURAL:$1|$1}}',
'nextn-title' => 'Next $1 {{PLURAL:$1|result|results}}',
'shown-title' => 'Show $1 {{PLURAL:$1|result|results}} per page',
'viewprevnext' => 'View ($1 {{int:pipe-separator}} $2) ($3)',
-'searchmenu-legend' => 'Search options',
'searchmenu-exists' => "'''There is a page named \"[[:\$1]]\" on this wiki.'''",
'searchmenu-new' => "'''Create the page \"[[:\$1]]\" on this wiki!'''",
'searchmenu-new-nocreate' => '', # do not translate or duplicate this message to other languages
-'searchmenu-prefix' => '[[Special:PrefixIndex/$1|Browse pages with this prefix]]',
'searchprofile-articles' => 'Content pages',
'searchprofile-project' => 'Help and Project pages',
'searchprofile-images' => 'Multimedia',
'showingresults' => "Showing below up to {{PLURAL:$1|'''1''' result|'''$1''' results}} starting with #'''$2'''.",
'showingresultsnum' => "Showing below {{PLURAL:$3|'''1''' result|'''$3''' results}} starting with #'''$2'''.",
'showingresultsheader' => "{{PLURAL:$5|Result '''$1''' of '''$3'''|Results '''$1 - $2''' of '''$3'''}} for '''$4'''",
-'nonefound' => "'''Note:''' Only some namespaces are searched by default.
-Try prefixing your query with ''all:'' to search all content (including talk pages, templates, etc.), or use the desired namespace as prefix.",
'search-nonefound' => 'There were no results matching the query.',
-'powersearch' => 'Advanced search',
'powersearch-legend' => 'Advanced search',
'powersearch-ns' => 'Search in namespaces:',
'powersearch-redir' => 'List redirects',
-'powersearch-field' => 'Search for',
'powersearch-togglelabel' => 'Check:',
'powersearch-toggleall' => 'All',
'powersearch-togglenone' => 'None',
'prefs-email' => 'Email options',
'prefs-rendering' => 'Appearance',
'saveprefs' => 'Save',
-'resetprefs' => 'Clear unsaved changes',
'restoreprefs' => 'Restore all default settings (in all sections)',
'prefs-editing' => 'Editing',
'rows' => 'Rows:',
'localtime' => 'Local time:',
'timezoneuseserverdefault' => 'Use wiki default ($1)',
'timezoneuseoffset' => 'Other (specify offset)',
-'timezoneoffset' => 'Offset¹:',
'servertime' => 'Server time:',
'guesstimezone' => 'Fill in from browser',
'timezoneregion-africa' => 'Africa',
'protectedpages-indef' => 'Indefinite protections only',
'protectedpages-summary' => '', # do not translate or duplicate this message to other languages
'protectedpages-cascade' => 'Cascading protections only',
-'protectedpagestext' => 'The following pages are protected from moving or editing',
'protectedpagesempty' => 'No pages are currently protected with these parameters.',
'protectedtitles' => 'Protected titles',
'protectedtitles-summary' => '', # do not translate or duplicate this message to other languages
-'protectedtitlestext' => 'The following titles are protected from creation',
'protectedtitlesempty' => 'No titles are currently protected with these parameters.',
'listusers' => 'User list',
'listusers-summary' => '', # do not translate or duplicate this message to other languages
{{Identical|Row}}',
'columns' => 'Used on [[Special:Preferences]], "Editing" section in the "Size of editing window" fieldset.
{{Identical|Column}}',
-'searchresultshead' => 'This is the label of the tab in [[Special:Preferences|my preferences]] which contains options for searching the wiki.
+'searchresultshead' => 'Replaced by {{msg-mw|prefs-searchoptions}}, though may still be used in some extensions. DEPRECATED.
{{Identical|Search}}',
'resultsperpage' => "Option on the 'Search options' tab of [[Special:Preferences]]",
'search-summary',
'searchresults',
'searchresults-title',
- 'searchresulttext',
- 'searchsubtitle',
- 'searchsubtitleinvalid',
'toomanymatches',
'titlematches',
- 'notitlematches',
'textmatches',
'notextmatches',
'prevn',
'nextn-title',
'shown-title',
'viewprevnext',
- 'searchmenu-legend',
'searchmenu-exists',
'searchmenu-new',
'searchmenu-new-nocreate',
- 'searchmenu-prefix',
'searchprofile-articles',
'searchprofile-project',
'searchprofile-images',
'showingresults',
'showingresultsnum',
'showingresultsheader',
- 'nonefound',
'search-nonefound',
- 'powersearch',
'powersearch-legend',
'powersearch-ns',
'powersearch-redir',
- 'powersearch-field',
'powersearch-togglelabel',
'powersearch-toggleall',
'powersearch-togglenone',
'prefs-email',
'prefs-rendering',
'saveprefs',
- 'resetprefs',
'restoreprefs',
'prefs-editing',
'rows',
'localtime',
'timezoneuseserverdefault',
'timezoneuseoffset',
- 'timezoneoffset',
'servertime',
'guesstimezone',
'timezoneregion-africa',
'protectedpages-indef',
'protectedpages-summary',
'protectedpages-cascade',
- 'protectedpagestext',
'protectedpagesempty',
'protectedtitles',
'protectedtitles-summary',
- 'protectedtitlestext',
'protectedtitlesempty',
'listusers',
'listusers-summary',
/**
* This script provides a function which is run to evaluate whether or not to
- * continue loading the jquery and mediawiki modules. This code should work on
+ * continue loading jQuery and the MediaWiki modules. This code should work on
* even the most ancient of browsers, so be very careful when editing.
*/