4 * Created on Sep 25, 2006
6 * API for MediaWiki 1.8+
8 * Copyright © 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/gpl.html
26 if ( !defined( 'MEDIAWIKI' ) ) {
27 // Eclipse helper - will be ignored in production
28 require_once( 'ApiQueryBase.php' );
32 * This query action allows clients to retrieve a list of recently modified pages
33 * that are part of the logged-in user's watchlist.
37 class ApiQueryWatchlist
extends ApiQueryGeneratorBase
{
39 public function __construct( $query, $moduleName ) {
40 parent
::__construct( $query, $moduleName, 'wl' );
43 public function execute() {
47 public function executeGenerator( $resultPageSet ) {
48 $this->run( $resultPageSet );
51 private $fld_ids = false, $fld_title = false, $fld_patrol = false, $fld_flags = false,
52 $fld_timestamp = false, $fld_user = false, $fld_comment = false, $fld_parsedcomment = false, $fld_sizes = false,
53 $fld_notificationtimestamp = false;
55 private function run( $resultPageSet = null ) {
56 $this->selectNamedDB( 'watchlist', DB_SLAVE
, 'watchlist' );
58 $params = $this->extractRequestParams();
60 $user = $this->getWatchlistUser( $params );
62 if ( !is_null( $params['prop'] ) && is_null( $resultPageSet ) ) {
63 $prop = array_flip( $params['prop'] );
65 $this->fld_ids
= isset( $prop['ids'] );
66 $this->fld_title
= isset( $prop['title'] );
67 $this->fld_flags
= isset( $prop['flags'] );
68 $this->fld_user
= isset( $prop['user'] );
69 $this->fld_comment
= isset( $prop['comment'] );
70 $this->fld_parsedcomment
= isset ( $prop['parsedcomment'] );
71 $this->fld_timestamp
= isset( $prop['timestamp'] );
72 $this->fld_sizes
= isset( $prop['sizes'] );
73 $this->fld_patrol
= isset( $prop['patrol'] );
74 $this->fld_notificationtimestamp
= isset( $prop['notificationtimestamp'] );
76 if ( $this->fld_patrol
) {
77 if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
78 $this->dieUsage( 'patrol property is not available', 'patrol' );
83 $this->addFields( array(
89 if ( is_null( $resultPageSet ) ) {
90 $this->addFields( array(
95 $this->addFieldsIf( 'rc_new', $this->fld_flags
);
96 $this->addFieldsIf( 'rc_minor', $this->fld_flags
);
97 $this->addFieldsIf( 'rc_bot', $this->fld_flags
);
98 $this->addFieldsIf( 'rc_user', $this->fld_user
);
99 $this->addFieldsIf( 'rc_user_text', $this->fld_user
);
100 $this->addFieldsIf( 'rc_comment', $this->fld_comment ||
$this->fld_parsedcomment
);
101 $this->addFieldsIf( 'rc_patrolled', $this->fld_patrol
);
102 $this->addFieldsIf( 'rc_old_len', $this->fld_sizes
);
103 $this->addFieldsIf( 'rc_new_len', $this->fld_sizes
);
104 $this->addFieldsIf( 'wl_notificationtimestamp', $this->fld_notificationtimestamp
);
105 } elseif ( $params['allrev'] ) {
106 $this->addFields( 'rc_this_oldid' );
108 $this->addFields( 'rc_cur_id' );
111 $this->addTables( array(
117 $userId = $user->getId();
118 $this->addWhere( array(
119 'wl_namespace = rc_namespace',
120 'wl_title = rc_title',
121 'rc_cur_id = page_id',
122 'wl_user' => $userId,
126 $this->addWhereRange( 'rc_timestamp', $params['dir'], $params['start'], $params['end'] );
127 $this->addWhereFld( 'wl_namespace', $params['namespace'] );
128 $this->addWhereIf( 'rc_this_oldid=page_latest', !$params['allrev'] );
130 if ( !is_null( $params['show'] ) ) {
131 $show = array_flip( $params['show'] );
133 /* Check for conflicting parameters. */
134 if ( ( isset ( $show['minor'] ) && isset ( $show['!minor'] ) )
135 ||
( isset ( $show['bot'] ) && isset ( $show['!bot'] ) )
136 ||
( isset ( $show['anon'] ) && isset ( $show['!anon'] ) )
137 ||
( isset ( $show['patrolled'] ) && isset ( $show['!patrolled'] ) )
140 $this->dieUsageMsg( array( 'show' ) );
143 // Check permissions.
144 if ( isset( $show['patrolled'] ) ||
isset( $show['!patrolled'] ) ) {
145 if ( !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() ) {
146 $this->dieUsage( 'You need the patrol right to request the patrolled flag', 'permissiondenied' );
150 /* Add additional conditions to query depending upon parameters. */
151 $this->addWhereIf( 'rc_minor = 0', isset( $show['!minor'] ) );
152 $this->addWhereIf( 'rc_minor != 0', isset( $show['minor'] ) );
153 $this->addWhereIf( 'rc_bot = 0', isset( $show['!bot'] ) );
154 $this->addWhereIf( 'rc_bot != 0', isset( $show['bot'] ) );
155 $this->addWhereIf( 'rc_user = 0', isset( $show['anon'] ) );
156 $this->addWhereIf( 'rc_user != 0', isset( $show['!anon'] ) );
157 $this->addWhereIf( 'rc_patrolled = 0', isset( $show['!patrolled'] ) );
158 $this->addWhereIf( 'rc_patrolled != 0', isset( $show['patrolled'] ) );
161 if ( !is_null( $params['user'] ) && !is_null( $params['excludeuser'] ) ) {
162 $this->dieUsage( 'user and excludeuser cannot be used together', 'user-excludeuser' );
164 if ( !is_null( $params['user'] ) ) {
165 $this->addWhereFld( 'rc_user_text', $params['user'] );
167 if ( !is_null( $params['excludeuser'] ) ) {
168 $this->addWhere( 'rc_user_text != ' . $this->getDB()->addQuotes( $params['excludeuser'] ) );
171 $db = $this->getDB();
173 // This is an index optimization for mysql, as done in the Special:Watchlist page
174 $this->addWhereIf( "rc_timestamp > ''", !isset( $params['start'] ) && !isset( $params['end'] ) && $db->getType() == 'mysql' );
176 $this->addOption( 'LIMIT', $params['limit'] +
1 );
180 $res = $this->select( __METHOD__
);
182 foreach ( $res as $row ) {
183 if ( ++
$count > $params['limit'] ) {
184 // We've reached the one extra which shows that there are additional pages to be had. Stop here...
185 $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601
, $row->rc_timestamp
) );
189 if ( is_null( $resultPageSet ) ) {
190 $vals = $this->extractRowInfo( $row );
191 $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ), null, $vals );
193 $this->setContinueEnumParameter( 'start',
194 wfTimestamp( TS_ISO_8601
, $row->rc_timestamp
) );
198 if ( $params['allrev'] ) {
199 $ids[] = intval( $row->rc_this_oldid
);
201 $ids[] = intval( $row->rc_cur_id
);
206 if ( is_null( $resultPageSet ) ) {
207 $this->getResult()->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'item' );
208 } elseif ( $params['allrev'] ) {
209 $resultPageSet->populateFromRevisionIDs( $ids );
211 $resultPageSet->populateFromPageIDs( $ids );
215 private function extractRowInfo( $row ) {
218 if ( $this->fld_ids
) {
219 $vals['pageid'] = intval( $row->rc_cur_id
);
220 $vals['revid'] = intval( $row->rc_this_oldid
);
223 $title = Title
::makeTitle( $row->rc_namespace
, $row->rc_title
);
225 if ( $this->fld_title
) {
226 ApiQueryBase
::addTitleInfo( $vals, $title );
229 if ( $this->fld_user
) {
230 $vals['user'] = $row->rc_user_text
;
231 if ( !$row->rc_user
) {
236 if ( $this->fld_flags
) {
237 if ( $row->rc_new
) {
240 if ( $row->rc_minor
) {
243 if ( $row->rc_bot
) {
248 if ( $this->fld_patrol
&& isset( $row->rc_patrolled
) ) {
249 $vals['patrolled'] = '';
252 if ( $this->fld_timestamp
) {
253 $vals['timestamp'] = wfTimestamp( TS_ISO_8601
, $row->rc_timestamp
);
256 if ( $this->fld_sizes
) {
257 $vals['oldlen'] = intval( $row->rc_old_len
);
258 $vals['newlen'] = intval( $row->rc_new_len
);
261 if ( $this->fld_notificationtimestamp
) {
262 $vals['notificationtimestamp'] = ( $row->wl_notificationtimestamp
== null )
264 : wfTimestamp( TS_ISO_8601
, $row->wl_notificationtimestamp
);
267 if ( $this->fld_comment
&& isset( $row->rc_comment
) ) {
268 $vals['comment'] = $row->rc_comment
;
271 if ( $this->fld_parsedcomment
&& isset( $row->rc_comment
) ) {
273 $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->rc_comment
, $title );
279 public function getAllowedParams() {
283 ApiBase
::PARAM_TYPE
=> 'timestamp'
286 ApiBase
::PARAM_TYPE
=> 'timestamp'
288 'namespace' => array (
289 ApiBase
::PARAM_ISMULTI
=> true,
290 ApiBase
::PARAM_TYPE
=> 'namespace'
293 ApiBase
::PARAM_TYPE
=> 'user',
295 'excludeuser' => array(
296 ApiBase
::PARAM_TYPE
=> 'user',
299 ApiBase
::PARAM_DFLT
=> 'older',
300 ApiBase
::PARAM_TYPE
=> array(
306 ApiBase
::PARAM_DFLT
=> 10,
307 ApiBase
::PARAM_TYPE
=> 'limit',
308 ApiBase
::PARAM_MIN
=> 1,
309 ApiBase
::PARAM_MAX
=> ApiBase
::LIMIT_BIG1
,
310 ApiBase
::PARAM_MAX2
=> ApiBase
::LIMIT_BIG2
313 APIBase
::PARAM_ISMULTI
=> true,
314 APIBase
::PARAM_DFLT
=> 'ids|title|flags',
315 APIBase
::PARAM_TYPE
=> array(
325 'notificationtimestamp'
329 ApiBase
::PARAM_ISMULTI
=> true,
330 ApiBase
::PARAM_TYPE
=> array(
342 ApiBase
::PARAM_TYPE
=> 'user'
345 ApiBase
::PARAM_TYPE
=> 'string'
350 public function getParamDescription() {
352 'allrev' => 'Include multiple revisions of the same page within given timeframe',
353 'start' => 'The timestamp to start enumerating from',
354 'end' => 'The timestamp to end enumerating',
355 'namespace' => 'Filter changes to only the given namespace(s)',
356 'user' => 'Only list changes by this user',
357 'excludeuser' => 'Don\'t list changes by this user',
358 'dir' => 'In which direction to enumerate pages',
359 'limit' => 'How many total results to return per request',
361 'Which additional items to get (non-generator mode only).',
362 ' ids - Adds revision ids and page ids',
363 ' title - Adds title of the page',
364 ' flags - Adds flags for the edit',
365 ' user - Adds user who made the edit',
366 ' comment - Adds comment of the edit',
367 ' parsedcomment - Adds parsed comment of the edit',
368 ' timestamp - Adds timestamp of the edit',
369 ' patrol - Tags edits that are patrolled',
370 ' size - Adds the old and new lengths of the page',
371 ' notificationtimestamp - Adds timestamp of when the user was last notified about the edit',
374 'Show only items that meet this criteria.',
375 "For example, to see only minor edits done by logged-in users, set {$this->getModulePrefix()}show=minor|!anon"
377 'owner' => 'The name of the user whose watchlist you\'d like to access',
378 'token' => 'Give a security token (settable in preferences) to allow access to another user\'s watchlist'
382 public function getDescription() {
383 return "Get all recent changes to pages in the logged in user's watchlist";
386 public function getPossibleErrors() {
387 return array_merge( parent
::getPossibleErrors(), array(
388 array( 'code' => 'bad_wlowner', 'info' => 'Specified user does not exist' ),
389 array( 'code' => 'bad_wltoken', 'info' => 'Incorrect watchlist token provided -- please set a correct token in Special:Preferences' ),
390 array( 'code' => 'notloggedin', 'info' => 'You must be logged-in to have a watchlist' ),
391 array( 'code' => 'patrol', 'info' => 'patrol property is not available' ),
393 array( 'code' => 'permissiondenied', 'info' => 'You need the patrol right to request the patrolled flag' ),
394 array( 'code' => 'user-excludeuser', 'info' => 'user and excludeuser cannot be used together' ),
398 protected function getExamples() {
400 'api.php?action=query&list=watchlist',
401 'api.php?action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment',
402 'api.php?action=query&list=watchlist&wlallrev&wlprop=ids|title|timestamp|user|comment',
403 'api.php?action=query&generator=watchlist&prop=info',
404 'api.php?action=query&generator=watchlist&gwlallrev&prop=revisions&rvprop=timestamp|user',
405 'api.php?action=query&list=watchlist&wlowner=Bob_Smith&wltoken=d8d562e9725ea1512894cdab28e5ceebc7f20237'
409 public function getVersion() {
410 return __CLASS__
. ': $Id$';