2006-09-26 05:43:02 +00:00
< ? php
/*
* Created on Sep 7 , 2006
*
* API for MediaWiki 1.8 +
*
2007-05-20 23:31:44 +00:00
* Copyright ( C ) 2006 Yuri Astrakhan < Firstname >< Lastname >@ gmail . com
2006-09-26 05:43:02 +00:00
*
* 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
2006-10-01 02:02:13 +00:00
require_once ( 'ApiQueryBase.php' );
2006-09-26 05:43:02 +00:00
}
2007-04-20 08:55:14 +00:00
/**
2007-05-20 23:31:44 +00:00
* 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 .
*
2007-04-20 08:55:14 +00:00
* @ addtogroup API
*/
2006-09-26 05:43:02 +00:00
class ApiQueryRevisions extends ApiQueryBase {
2006-10-03 05:41:55 +00:00
public function __construct ( $query , $moduleName ) {
parent :: __construct ( $query , $moduleName , 'rv' );
2006-09-26 05:43:02 +00:00
}
2007-08-09 06:38:48 +00:00
private $fld_ids = false , $fld_flags = false , $fld_timestamp = false , $fld_size = false ,
2007-05-21 06:32:32 +00:00
$fld_comment = false , $fld_user = false , $fld_content = false ;
2007-05-20 08:34:47 +00:00
2006-09-27 05:13:48 +00:00
public function execute () {
2007-12-02 00:22:32 +00:00
$limit = $startid = $endid = $start = $end = $dir = $prop = $user = $excludeuser = $token = null ;
2006-09-27 05:13:48 +00:00
extract ( $this -> extractRequestParams ());
2006-09-26 05:43:02 +00:00
2006-10-01 02:02:13 +00:00
// If any of those parameters are used, work in 'enumeration' mode.
2006-09-30 08:06:27 +00:00
// Enum mode can only be used when exactly one page is provided.
2007-11-27 16:41:13 +00:00
// Enumerating revisions on multiple pages make it extremely
// difficult to manage continuations and require additional SQL indexes
2007-12-02 00:22:32 +00:00
$enumRevMode = ( ! is_null ( $user ) || ! is_null ( $excludeuser ) || ! is_null ( $limit ) || ! is_null ( $startid ) || ! is_null ( $endid ) || $dir === 'newer' || ! is_null ( $start ) || ! is_null ( $end ));
2007-10-02 15:30:39 +00:00
2006-09-27 05:13:48 +00:00
2006-10-01 20:17:16 +00:00
$pageSet = $this -> getPageSet ();
$pageCount = $pageSet -> getGoodTitleCount ();
$revCount = $pageSet -> getRevisionCount ();
2006-09-29 07:29:13 +00:00
2006-10-01 02:02:13 +00:00
// Optimization -- nothing to do
if ( $revCount === 0 && $pageCount === 0 )
return ;
2006-09-30 08:06:27 +00:00
if ( $revCount > 0 && $enumRevMode )
2006-10-03 05:41:55 +00:00
$this -> dieUsage ( 'The revids= parameter may not be used with the list options (limit, startid, endid, dirNewer, start, end).' , 'revids' );
2006-09-30 08:06:27 +00:00
2006-10-13 04:59:14 +00:00
if ( $pageCount > 1 && $enumRevMode )
2007-12-02 00:22:32 +00:00
$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' );
2006-09-27 05:13:48 +00:00
2006-10-21 08:26:32 +00:00
$this -> addTables ( 'revision' );
$this -> addWhere ( 'rev_deleted=0' );
2007-05-21 06:32:32 +00:00
$prop = array_flip ( $prop );
// These field are needed regardless of the client requesting them
$this -> addFields ( 'rev_id' );
$this -> addFields ( 'rev_page' );
// Optional fields
2007-07-01 06:45:14 +00:00
$this -> fld_ids = isset ( $prop [ 'ids' ]);
2007-05-21 06:32:32 +00:00
// $this->addFieldsIf('rev_text_id', $this->fld_ids); // should this be exposed?
$this -> fld_flags = $this -> addFieldsIf ( 'rev_minor_edit' , isset ( $prop [ 'flags' ]));
2007-07-01 06:45:14 +00:00
$this -> fld_timestamp = $this -> addFieldsIf ( 'rev_timestamp' , isset ( $prop [ 'timestamp' ]));
2007-05-21 06:32:32 +00:00
$this -> fld_comment = $this -> addFieldsIf ( 'rev_comment' , isset ( $prop [ 'comment' ]));
2007-08-09 06:38:48 +00:00
$this -> fld_size = $this -> addFieldsIf ( 'rev_len' , isset ( $prop [ 'size' ]));
2007-12-01 15:08:57 +00:00
if ( ! is_null ( $token ))
{
$this -> tok_rollback = $this -> getTokenFlag ( $token , 'rollback' );
}
2007-05-21 06:32:32 +00:00
if ( isset ( $prop [ 'user' ])) {
$this -> addFields ( 'rev_user' );
$this -> addFields ( 'rev_user_text' );
$this -> fld_user = true ;
}
2007-12-01 15:08:57 +00:00
else if ( $this -> tok_rollback )
$this -> addFields ( 'rev_user_text' );
2007-12-02 00:22:32 +00:00
if ( isset ( $prop [ 'content' ])) {
2007-07-14 19:04:31 +00:00
// 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' );
}
2007-05-21 06:32:32 +00:00
$this -> addTables ( 'text' );
$this -> addWhere ( 'rev_text_id=old_id' );
$this -> addFields ( 'old_id' );
$this -> addFields ( 'old_text' );
$this -> addFields ( 'old_flags' );
2007-09-25 18:36:25 +00:00
2007-12-02 00:22:32 +00:00
$this -> fld_content = true ;
2007-09-25 18:36:25 +00:00
$this -> expandTemplates = $expandtemplates ;
2006-09-27 05:13:48 +00:00
}
2007-12-02 00:22:32 +00:00
$userMax = ( $this -> fld_content ? 50 : 500 );
$botMax = ( $this -> fld_content ? 200 : 10000 );
2006-09-29 07:29:13 +00:00
if ( $enumRevMode ) {
2006-09-27 05:13:48 +00:00
2007-11-27 16:41:13 +00:00
// This is mostly to prevent parameter errors (and optimize SQL?)
2006-10-16 00:08:03 +00:00
if ( ! is_null ( $startid ) && ! is_null ( $start ))
2006-10-03 05:41:55 +00:00
$this -> dieUsage ( 'start and startid cannot be used together' , 'badparams' );
2006-09-30 08:06:27 +00:00
2006-10-16 00:08:03 +00:00
if ( ! is_null ( $endid ) && ! is_null ( $end ))
2006-10-03 05:41:55 +00:00
$this -> dieUsage ( 'end and endid cannot be used together' , 'badparams' );
2006-09-30 08:06:27 +00:00
2007-05-19 04:13:48 +00:00
if ( ! is_null ( $user ) && ! is_null ( $excludeuser ))
$this -> dieUsage ( 'user and excludeuser cannot be used together' , 'badparams' );
2006-10-02 18:27:06 +00:00
// 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.
2007-10-02 15:30:39 +00:00
if ( is_null ( $startid ) && is_null ( $endid ))
2006-10-21 08:26:32 +00:00
$this -> addWhereRange ( 'rev_timestamp' , $dir , $start , $end );
2006-11-03 06:53:47 +00:00
else
$this -> addWhereRange ( 'rev_id' , $dir , $startid , $endid );
2006-09-29 07:29:13 +00:00
2006-10-03 05:41:55 +00:00
// must manually initialize unset limit
2006-10-18 23:49:09 +00:00
if ( is_null ( $limit ))
2006-10-03 05:41:55 +00:00
$limit = 10 ;
2007-06-25 05:44:33 +00:00
$this -> validateLimit ( 'limit' , $limit , 1 , $userMax , $botMax );
2006-09-29 07:29:13 +00:00
2006-09-30 08:06:27 +00:00
// There is only one ID, use it
2006-10-30 00:18:05 +00:00
$this -> addWhereFld ( 'rev_page' , current ( array_keys ( $pageSet -> getGoodTitles ())));
2007-07-14 19:04:31 +00:00
2007-05-19 04:13:48 +00:00
if ( ! is_null ( $user )) {
2007-05-27 23:50:24 +00:00
$this -> addWhereFld ( 'rev_user_text' , $user );
2007-05-19 04:13:48 +00:00
} elseif ( ! is_null ( $excludeuser )) {
$this -> addWhere ( 'rev_user_text != ' . $this -> getDB () -> addQuotes ( $excludeuser ));
}
2006-10-01 20:17:16 +00:00
}
2007-05-19 01:46:13 +00:00
elseif ( $revCount > 0 ) {
$this -> validateLimit ( 'rev_count' , $revCount , 1 , $userMax , $botMax );
// Get all revision IDs
$this -> addWhereFld ( 'rev_id' , array_keys ( $pageSet -> getRevisionIDs ()));
2007-05-21 06:32:32 +00:00
// assumption testing -- we should never get more then $revCount rows.
$limit = $revCount ;
2007-05-19 01:46:13 +00:00
}
2006-10-01 20:17:16 +00:00
elseif ( $pageCount > 0 ) {
// When working in multi-page non-enumeration mode,
// limit to the latest revision only
2006-10-21 08:26:32 +00:00
$this -> addTables ( 'page' );
$this -> addWhere ( 'page_id=rev_page' );
$this -> addWhere ( 'page_latest=rev_id' );
2006-10-01 20:17:16 +00:00
$this -> validateLimit ( 'page_count' , $pageCount , 1 , $userMax , $botMax );
// Get all page IDs
2006-10-21 08:26:32 +00:00
$this -> addWhereFld ( 'page_id' , array_keys ( $pageSet -> getGoodTitles ()));
2006-10-01 20:17:16 +00:00
2007-05-21 06:32:32 +00:00
// assumption testing -- we should never get more then $pageCount rows.
$limit = $pageCount ;
2006-10-01 20:17:16 +00:00
} else
ApiBase :: dieDebug ( __METHOD__ , 'param validation?' );
2006-09-30 08:06:27 +00:00
2006-10-21 08:26:32 +00:00
$this -> addOption ( 'LIMIT' , $limit + 1 );
2006-09-27 05:13:48 +00:00
$data = array ();
$count = 0 ;
2006-10-21 08:26:32 +00:00
$res = $this -> select ( __METHOD__ );
2006-10-25 03:54:56 +00:00
2007-01-22 23:50:42 +00:00
$db = $this -> getDB ();
2006-09-27 05:13:48 +00:00
while ( $row = $db -> fetchObject ( $res )) {
2006-10-03 05:41:55 +00:00
if ( ++ $count > $limit ) {
2006-09-27 05:13:48 +00:00
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
2006-09-30 08:06:27 +00:00
if ( ! $enumRevMode )
2006-10-01 20:17:16 +00:00
ApiBase :: dieDebug ( __METHOD__ , 'Got more rows then expected' ); // bug report
2007-05-21 06:32:32 +00:00
$this -> setContinueEnumParameter ( 'startid' , intval ( $row -> rev_id ));
2006-09-27 05:13:48 +00:00
break ;
}
2007-05-20 08:34:47 +00:00
$this -> getResult () -> addValue (
array (
'query' ,
'pages' ,
intval ( $row -> rev_page ),
'revisions' ),
null ,
2007-07-01 06:45:14 +00:00
$this -> extractRowInfo ( $row ));
2006-09-27 05:13:48 +00:00
}
$db -> freeResult ( $res );
2007-11-27 16:41:13 +00:00
2006-10-18 05:35:24 +00:00
// Ensure that all revisions are shown as '<rev>' elements
2006-10-18 05:27:43 +00:00
$result = $this -> getResult ();
2006-10-21 08:26:32 +00:00
if ( $result -> getIsRawMode ()) {
2007-01-18 02:01:47 +00:00
$data =& $result -> getData ();
2006-10-18 05:35:24 +00:00
foreach ( $data [ 'query' ][ 'pages' ] as & $page ) {
if ( is_array ( $page ) && array_key_exists ( 'revisions' , $page )) {
$result -> setIndexedTagName ( $page [ 'revisions' ], 'rev' );
}
2006-10-01 02:02:13 +00:00
}
}
2006-09-26 05:43:02 +00:00
}
2007-05-20 08:34:47 +00:00
private function extractRowInfo ( $row ) {
$vals = array ();
2007-05-21 06:32:32 +00:00
if ( $this -> fld_ids ) {
$vals [ 'revid' ] = intval ( $row -> rev_id );
// $vals['oldid'] = intval($row->rev_text_id); // todo: should this be exposed?
}
2007-05-20 08:34:47 +00:00
2007-05-21 06:32:32 +00:00
if ( $this -> fld_flags && $row -> rev_minor_edit )
2007-05-20 08:34:47 +00:00
$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 );
}
2007-09-02 14:00:11 +00:00
if ( $this -> fld_size && ! is_null ( $row -> rev_len )) {
2007-08-09 06:38:48 +00:00
$vals [ 'size' ] = intval ( $row -> rev_len );
}
2007-05-20 08:34:47 +00:00
if ( $this -> fld_comment && ! empty ( $row -> rev_comment )) {
$vals [ 'comment' ] = $row -> rev_comment ;
}
2007-12-01 15:08:57 +00:00
if ( $this -> tok_rollback || ( $this -> fld_content && $this -> expandTemplates ))
$title = Title :: newFromID ( $row -> rev_page );
if ( $this -> tok_rollback ) {
2007-12-01 15:13:29 +00:00
global $wgUser ;
2007-12-01 15:08:57 +00:00
$vals [ 'rollbacktoken' ] = $wgUser -> editToken ( array ( $title -> getPrefixedText (), $row -> rev_user_text ));
}
2007-12-02 00:22:32 +00:00
2007-11-27 16:41:13 +00:00
if ( $this -> fld_content ) {
2007-12-02 00:22:32 +00:00
$text = Revision :: getRevisionText ( $row );
2007-09-25 18:36:25 +00:00
if ( $this -> expandTemplates ) {
global $wgParser ;
2007-12-01 15:08:57 +00:00
$text = $wgParser -> preprocess ( $text , $title , new ParserOptions () );
2007-09-25 18:36:25 +00:00
}
ApiResult :: setContent ( $vals , $text );
2007-12-02 00:22:32 +00:00
}
2007-05-20 08:34:47 +00:00
return $vals ;
}
2006-09-27 05:13:48 +00:00
protected function getAllowedParams () {
2006-09-26 05:43:02 +00:00
return array (
2006-10-03 05:41:55 +00:00
'prop' => array (
2006-10-01 20:17:16 +00:00
ApiBase :: PARAM_ISMULTI => true ,
2007-05-21 06:32:32 +00:00
ApiBase :: PARAM_DFLT => 'ids|timestamp|flags|comment|user' ,
2006-10-01 20:17:16 +00:00
ApiBase :: PARAM_TYPE => array (
2007-05-21 06:32:32 +00:00
'ids' ,
'flags' ,
2006-10-01 20:17:16 +00:00
'timestamp' ,
'user' ,
2007-08-09 06:38:48 +00:00
'size' ,
2006-10-01 20:17:16 +00:00
'comment' ,
2007-08-09 06:38:48 +00:00
'content' ,
2006-10-01 20:17:16 +00:00
)
),
2006-10-03 05:41:55 +00:00
'limit' => array (
2006-10-01 20:17:16 +00:00
ApiBase :: PARAM_TYPE => 'limit' ,
2006-10-17 02:01:20 +00:00
ApiBase :: PARAM_MIN => 1 ,
2007-10-05 07:37:58 +00:00
ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1 ,
ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
2006-09-27 05:13:48 +00:00
),
2006-10-16 00:08:03 +00:00
'startid' => array (
ApiBase :: PARAM_TYPE => 'integer'
),
'endid' => array (
ApiBase :: PARAM_TYPE => 'integer'
),
2006-10-03 05:41:55 +00:00
'start' => array (
2006-10-01 20:17:16 +00:00
ApiBase :: PARAM_TYPE => 'timestamp'
2006-09-26 05:43:02 +00:00
),
2006-10-03 05:41:55 +00:00
'end' => array (
2006-10-01 20:17:16 +00:00
ApiBase :: PARAM_TYPE => 'timestamp'
2006-09-26 05:43:02 +00:00
),
2006-10-03 05:41:55 +00:00
'dir' => array (
2006-10-01 20:17:16 +00:00
ApiBase :: PARAM_DFLT => 'older' ,
ApiBase :: PARAM_TYPE => array (
2006-09-26 05:43:02 +00:00
'newer' ,
'older'
)
2007-05-19 04:13:48 +00:00
),
'user' => array (
ApiBase :: PARAM_TYPE => 'user'
),
'excludeuser' => array (
ApiBase :: PARAM_TYPE => 'user'
2007-09-25 18:36:25 +00:00
),
'expandtemplates' => false ,
2007-12-01 15:08:57 +00:00
'token' => array (
ApiBase :: PARAM_TYPE => array (
'rollback'
),
ApiBase :: PARAM_ISMULTI => true
),
2006-09-26 05:43:02 +00:00
);
}
2006-10-01 20:17:16 +00:00
protected function getParamDescription () {
return array (
2006-10-16 00:08:03 +00:00
'prop' => 'Which properties to get for each revision.' ,
2006-10-03 05:41:55 +00:00
'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)' ,
2007-05-19 04:13:48 +00:00
'dir' => 'direction of enumeration - towards "newer" or "older" revisions (enum)' ,
'user' => 'only include revisions made by user' ,
'excludeuser' => 'exclude revisions made by user' ,
2007-11-27 16:41:13 +00:00
'expandtemplates' => 'expand templates in revision content' ,
2007-12-01 15:08:57 +00:00
'token' => 'Which tokens to obtain for each revision' ,
2006-10-01 20:17:16 +00:00
);
}
2006-09-27 05:13:48 +00:00
protected function getDescription () {
2006-09-30 08:06:27 +00:00
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.' ,
2006-10-03 05:41:55 +00:00
' 2) Get revisions for one given page, by using titles/pageids with start/end/limit params.' ,
2006-10-01 20:17:16 +00:00
' 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).'
2006-09-30 08:06:27 +00:00
);
2006-09-26 05:43:02 +00:00
}
2006-09-27 05:13:48 +00:00
protected function getExamples () {
2006-09-26 05:43:02 +00:00
return array (
2007-12-01 17:53:42 +00:00
'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' ,
2006-10-01 20:17:16 +00:00
'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:' ,
2007-05-19 04:13:48 +00:00
' 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' ,
2006-09-26 05:43:02 +00:00
);
}
2006-10-01 21:20:55 +00:00
public function getVersion () {
return __CLASS__ . ': $Id$' ;
}
2006-09-26 05:43:02 +00:00
}
2007-06-29 01:19:14 +00:00