]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/api/ApiQueryWatchlist.php
MediaWiki 1.16.0
[autoinstalls/mediawiki.git] / includes / api / ApiQueryWatchlist.php
1 <?php
2
3 /*
4  * Created on Sep 25, 2006
5  *
6  * API for MediaWiki 1.8+
7  *
8  * Copyright (C) 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
9  *
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.
14  *
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.
19  *
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  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  * http://www.gnu.org/copyleft/gpl.html
24  */
25
26 if ( !defined( 'MEDIAWIKI' ) ) {
27         // Eclipse helper - will be ignored in production
28         require_once ( 'ApiQueryBase.php' );
29 }
30
31 /**
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.
34  *
35  * @ingroup API
36  */
37 class ApiQueryWatchlist extends ApiQueryGeneratorBase {
38
39         public function __construct( $query, $moduleName ) {
40                 parent :: __construct( $query, $moduleName, 'wl' );
41         }
42
43         public function execute() {
44                 $this->run();
45         }
46
47         public function executeGenerator( $resultPageSet ) {
48                 $this->run( $resultPageSet );
49         }
50
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;
54
55         private function run( $resultPageSet = null ) {
56                 global $wgUser;
57
58                 $this->selectNamedDB( 'watchlist', DB_SLAVE, 'watchlist' );
59
60                 $params = $this->extractRequestParams();
61
62                 if ( !is_null( $params['owner'] ) && !is_null( $params['token'] ) ) {
63                         $user = User::newFromName( $params['owner'], false );
64                         if ( !$user->getId() ) {
65                                 $this->dieUsage( 'Specified user does not exist', 'bad_wlowner' );
66                         }
67                         $token = $user->getOption( 'watchlisttoken' );
68                         if ( $token == '' || $token != $params['token'] ) {
69                                 $this->dieUsage( 'Incorrect watchlist token provided -- please set a correct token in Special:Preferences', 'bad_wltoken' );
70                         }
71                 } elseif ( !$wgUser->isLoggedIn() ) {
72                         $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
73                 } else {
74                         $user = $wgUser;
75                 }
76
77                 if ( !is_null( $params['prop'] ) && is_null( $resultPageSet ) ) {
78
79                         $prop = array_flip( $params['prop'] );
80
81                         $this->fld_ids = isset( $prop['ids'] );
82                         $this->fld_title = isset( $prop['title'] );
83                         $this->fld_flags = isset( $prop['flags'] );
84                         $this->fld_user = isset( $prop['user'] );
85                         $this->fld_comment = isset( $prop['comment'] );
86                         $this->fld_parsedcomment = isset ( $prop['parsedcomment'] );
87                         $this->fld_timestamp = isset( $prop['timestamp'] );
88                         $this->fld_sizes = isset( $prop['sizes'] );
89                         $this->fld_patrol = isset( $prop['patrol'] );
90                         $this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] );
91
92                         if ( $this->fld_patrol ) {
93                                 if ( !$user->useRCPatrol() && !$user->useNPPatrol() )
94                                         $this->dieUsage( 'patrol property is not available', 'patrol' );
95                         }
96                 }
97         
98                 $this->addFields( array (
99                         'rc_namespace',
100                         'rc_title',
101                         'rc_timestamp'
102                 ) );
103
104                 if ( is_null( $resultPageSet ) ) {
105                         $this->addFields( array (
106                                 'rc_cur_id',
107                                 'rc_this_oldid'
108                         ) );
109
110                         $this->addFieldsIf( 'rc_new', $this->fld_flags );
111                         $this->addFieldsIf( 'rc_minor', $this->fld_flags );
112                         $this->addFieldsIf( 'rc_bot', $this->fld_flags );
113                         $this->addFieldsIf( 'rc_user', $this->fld_user );
114                         $this->addFieldsIf( 'rc_user_text', $this->fld_user );
115                         $this->addFieldsIf( 'rc_comment', $this->fld_comment || $this->fld_parsedcomment );
116                         $this->addFieldsIf( 'rc_patrolled', $this->fld_patrol );
117                         $this->addFieldsIf( 'rc_old_len', $this->fld_sizes );
118                         $this->addFieldsIf( 'rc_new_len', $this->fld_sizes );
119                         $this->addFieldsIf( 'wl_notificationtimestamp', $this->fld_notificationtimestamp );
120                 } elseif ( $params['allrev'] ) {
121                         $this->addFields( 'rc_this_oldid' );
122                 } else {
123                         $this->addFields( 'rc_cur_id' );
124                 }
125
126                 $this->addTables( array (
127                         'watchlist',
128                         'page',
129                         'recentchanges'
130                 ) );
131
132                 $userId = $user->getId();
133                 $this->addWhere( array (
134                         'wl_namespace = rc_namespace',
135                         'wl_title = rc_title',
136                         'rc_cur_id = page_id',
137                         'wl_user' => $userId,
138                         'rc_deleted' => 0,
139                 ) );
140
141                 $this->addWhereRange( 'rc_timestamp', $params['dir'], $params['start'], $params['end'] );
142                 $this->addWhereFld( 'wl_namespace', $params['namespace'] );
143                 $this->addWhereIf( 'rc_this_oldid=page_latest', !$params['allrev'] );
144
145                 if ( !is_null( $params['show'] ) ) {
146                         $show = array_flip( $params['show'] );
147
148                         /* Check for conflicting parameters. */
149                         if ( ( isset ( $show['minor'] ) && isset ( $show['!minor'] ) )
150                                         || ( isset ( $show['bot'] ) && isset ( $show['!bot'] ) )
151                                         || ( isset ( $show['anon'] ) && isset ( $show['!anon'] ) )
152                                         || ( isset ( $show['patrolled'] ) && isset ( $show['!patrolled'] ) ) ) {
153
154                                 $this->dieUsageMsg( array( 'show' ) );
155                         }
156                         
157                         // Check permissions.
158                         if ( ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) && !$wgUser->useRCPatrol() && !$wgUser->useNPPatrol() )
159                                 $this->dieUsage( "You need the patrol right to request the patrolled flag", 'permissiondenied' );
160
161                         /* Add additional conditions to query depending upon parameters. */
162                         $this->addWhereIf( 'rc_minor = 0', isset ( $show['!minor'] ) );
163                         $this->addWhereIf( 'rc_minor != 0', isset ( $show['minor'] ) );
164                         $this->addWhereIf( 'rc_bot = 0', isset ( $show['!bot'] ) );
165                         $this->addWhereIf( 'rc_bot != 0', isset ( $show['bot'] ) );
166                         $this->addWhereIf( 'rc_user = 0', isset ( $show['anon'] ) );
167                         $this->addWhereIf( 'rc_user != 0', isset ( $show['!anon'] ) );
168                         $this->addWhereIf( 'rc_patrolled = 0', isset( $show['!patrolled'] ) );
169                         $this->addWhereIf( 'rc_patrolled != 0', isset( $show['patrolled'] ) );
170                 }
171
172                 if ( !is_null( $params['user'] ) && !is_null( $params['excludeuser'] ) )
173                         $this->dieUsage( 'user and excludeuser cannot be used together', 'user-excludeuser' );
174                 if ( !is_null( $params['user'] ) )
175                         $this->addWhereFld( 'rc_user_text', $params['user'] );
176                 if ( !is_null( $params['excludeuser'] ) )
177                         $this->addWhere( 'rc_user_text != ' . $this->getDB()->addQuotes( $params['excludeuser'] ) );
178
179                 $db = $this->getDB();
180                         
181                 // This is an index optimization for mysql, as done in the Special:Watchlist page
182                 $this->addWhereIf( "rc_timestamp > ''", !isset ( $params['start'] ) && !isset ( $params['end'] ) && $db->getType() == 'mysql' );
183
184                 $this->addOption( 'LIMIT', $params['limit'] + 1 );
185
186                 $ids = array ();
187                 $count = 0;
188                 $res = $this->select( __METHOD__ );
189
190                 while ( $row = $db->fetchObject( $res ) ) {
191                         if ( ++ $count > $params['limit'] ) {
192                                 // We've reached the one extra which shows that there are additional pages to be had. Stop here...
193                                 $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->rc_timestamp ) );
194                                 break;
195                         }
196
197                         if ( is_null( $resultPageSet ) ) {
198                                 $vals = $this->extractRowInfo( $row );
199                                 $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ), null, $vals );
200                                 if ( !$fit )
201                                 {
202                                         $this->setContinueEnumParameter( 'start',
203                                                         wfTimestamp( TS_ISO_8601, $row->rc_timestamp ) );
204                                         break;
205                                 }
206                         } else {
207                                 if ( $params['allrev'] ) {
208                                         $ids[] = intval( $row->rc_this_oldid );
209                                 } else {
210                                         $ids[] = intval( $row->rc_cur_id );
211                                 }
212                         }
213                 }
214
215                 $db->freeResult( $res );
216
217                 if ( is_null( $resultPageSet ) ) {
218                         $this->getResult()->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'item' );
219                 }
220                 elseif ( $params['allrev'] ) {
221                         $resultPageSet->populateFromRevisionIDs( $ids );
222                 } else {
223                         $resultPageSet->populateFromPageIDs( $ids );
224                 }
225         }
226
227         private function extractRowInfo( $row ) {
228
229                 $vals = array ();
230
231                 if ( $this->fld_ids ) {
232                         $vals['pageid'] = intval( $row->rc_cur_id );
233                         $vals['revid'] = intval( $row->rc_this_oldid );
234                 }
235
236                 $title = Title::makeTitle( $row->rc_namespace, $row->rc_title );
237
238                 if ( $this->fld_title )
239                         ApiQueryBase::addTitleInfo( $vals, $title );
240
241                 if ( $this->fld_user ) {
242                         $vals['user'] = $row->rc_user_text;
243                         if ( !$row->rc_user )
244                                 $vals['anon'] = '';
245                 }
246
247                 if ( $this->fld_flags ) {
248                         if ( $row->rc_new )
249                                 $vals['new'] = '';
250                         if ( $row->rc_minor )
251                                 $vals['minor'] = '';
252                         if ( $row->rc_bot )
253                                 $vals['bot'] = '';
254                 }
255
256                 if ( $this->fld_patrol && isset( $row->rc_patrolled ) )
257                         $vals['patrolled'] = '';
258
259                 if ( $this->fld_timestamp )
260                         $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $row->rc_timestamp );
261
262                 if ( $this->fld_sizes ) {
263                         $vals['oldlen'] = intval( $row->rc_old_len );
264                         $vals['newlen'] = intval( $row->rc_new_len );
265                 }
266                 
267                 if ( $this->fld_notificationtimestamp )
268                         $vals['notificationtimestamp'] = ( $row->wl_notificationtimestamp == null ) ? '' : wfTimestamp( TS_ISO_8601, $row->wl_notificationtimestamp );
269
270                 if ( $this->fld_comment && isset( $row->rc_comment ) )
271                         $vals['comment'] = $row->rc_comment;
272                         
273                 if ( $this->fld_parsedcomment && isset( $row->rc_comment ) ) {
274                         global $wgUser;
275                         $vals['parsedcomment'] = $wgUser->getSkin()->formatComment( $row->rc_comment, $title );
276                 }
277
278                 return $vals;
279         }
280
281         public function getAllowedParams() {
282                 return array (
283                         'allrev' => false,
284                         'start' => array (
285                                 ApiBase :: PARAM_TYPE => 'timestamp'
286                         ),
287                         'end' => array (
288                                 ApiBase :: PARAM_TYPE => 'timestamp'
289                         ),
290                         'namespace' => array (
291                                 ApiBase :: PARAM_ISMULTI => true,
292                                 ApiBase :: PARAM_TYPE => 'namespace'
293                         ),
294                         'user' => array(
295                                 ApiBase :: PARAM_TYPE => 'user',
296                         ),
297                         'excludeuser' => array(
298                                 ApiBase :: PARAM_TYPE => 'user',
299                         ),
300                         'dir' => array (
301                                 ApiBase :: PARAM_DFLT => 'older',
302                                 ApiBase :: PARAM_TYPE => array (
303                                         'newer',
304                                         'older'
305                                 )
306                         ),
307                         'limit' => array (
308                                 ApiBase :: PARAM_DFLT => 10,
309                                 ApiBase :: PARAM_TYPE => 'limit',
310                                 ApiBase :: PARAM_MIN => 1,
311                                 ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
312                                 ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
313                         ),
314                         'prop' => array (
315                                 APIBase :: PARAM_ISMULTI => true,
316                                 APIBase :: PARAM_DFLT => 'ids|title|flags',
317                                 APIBase :: PARAM_TYPE => array (
318                                         'ids',
319                                         'title',
320                                         'flags',
321                                         'user',
322                                         'comment',
323                                         'parsedcomment',
324                                         'timestamp',
325                                         'patrol',
326                                         'sizes',
327                                         'notificationtimestamp'
328                                 )
329                         ),
330                         'show' => array (
331                                 ApiBase :: PARAM_ISMULTI => true,
332                                 ApiBase :: PARAM_TYPE => array (
333                                         'minor',
334                                         '!minor',
335                                         'bot',
336                                         '!bot',
337                                         'anon',
338                                         '!anon',
339                                         'patrolled',
340                                         '!patrolled',
341                                 )
342                         ),
343                         'owner' => array (
344                                 ApiBase :: PARAM_TYPE => 'user'
345                         ),
346                         'token' => array (
347                                 ApiBase :: PARAM_TYPE => 'string'
348                         )
349                 );
350         }
351
352         public function getParamDescription() {
353                 return array (
354                         'allrev' => 'Include multiple revisions of the same page within given timeframe.',
355                         'start' => 'The timestamp to start enumerating from.',
356                         'end' => 'The timestamp to end enumerating.',
357                         'namespace' => 'Filter changes to only the given namespace(s).',
358                         'user' => 'Only list changes by this user',
359                         'excludeuser' => 'Don\'t list changes by this user',
360                         'dir' => 'In which direction to enumerate pages.',
361                         'limit' => 'How many total results to return per request.',
362                         'prop' => 'Which additional items to get (non-generator mode only).',
363                         'show' => array (
364                                 'Show only items that meet this criteria.',
365                                 'For example, to see only minor edits done by logged-in users, set show=minor|!anon'
366                         ),
367                         'owner' => "The name of the user whose watchlist you'd like to access",
368                         'token' => "Give a security token (settable in preferences) to allow access to another user's watchlist"
369                 );
370         }
371
372         public function getDescription() {
373                 return "Get all recent changes to pages in the logged in user's watchlist";
374         }
375         
376         public function getPossibleErrors() {
377                 return array_merge( parent::getPossibleErrors(), array(
378                         array( 'code' => 'bad_wlowner', 'info' => 'Specified user does not exist' ),
379                         array( 'code' => 'bad_wltoken', 'info' => 'Incorrect watchlist token provided -- please set a correct token in Special:Preferences' ),
380                         array( 'code' => 'notloggedin', 'info' => 'You must be logged-in to have a watchlist' ),
381                         array( 'code' => 'patrol', 'info' => 'patrol property is not available' ),
382                         array( 'show' ),
383                         array( 'code' => 'permissiondenied', 'info' => 'You need the patrol right to request the patrolled flag' ),
384                         array( 'code' => 'user-excludeuser', 'info' => 'user and excludeuser cannot be used together' ),
385                 ) );
386         }
387
388         protected function getExamples() {
389                 return array (
390                         'api.php?action=query&list=watchlist',
391                         'api.php?action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment',
392                         'api.php?action=query&list=watchlist&wlallrev&wlprop=ids|title|timestamp|user|comment',
393                         'api.php?action=query&generator=watchlist&prop=info',
394                         'api.php?action=query&generator=watchlist&gwlallrev&prop=revisions&rvprop=timestamp|user',
395                         'api.php?action=query&list=watchlist&wlowner=Bob_Smith&wltoken=d8d562e9725ea1512894cdab28e5ceebc7f20237'
396                 );
397         }
398
399         public function getVersion() {
400                 return __CLASS__ . ': $Id: ApiQueryWatchlist.php 69932 2010-07-26 08:03:21Z tstarling $';
401         }
402 }