MediaWiki  REL1_23
ApiQueryWatchlist.php
Go to the documentation of this file.
00001 <?php
00033 class ApiQueryWatchlist extends ApiQueryGeneratorBase {
00034 
00035     public function __construct( $query, $moduleName ) {
00036         parent::__construct( $query, $moduleName, 'wl' );
00037     }
00038 
00039     public function execute() {
00040         $this->run();
00041     }
00042 
00043     public function executeGenerator( $resultPageSet ) {
00044         $this->run( $resultPageSet );
00045     }
00046 
00047     private $fld_ids = false, $fld_title = false, $fld_patrol = false,
00048         $fld_flags = false, $fld_timestamp = false, $fld_user = false,
00049         $fld_comment = false, $fld_parsedcomment = false, $fld_sizes = false,
00050         $fld_notificationtimestamp = false, $fld_userid = false,
00051         $fld_loginfo = false;
00052 
00057     private function run( $resultPageSet = null ) {
00058         $this->selectNamedDB( 'watchlist', DB_SLAVE, 'watchlist' );
00059 
00060         $params = $this->extractRequestParams();
00061 
00062         $user = $this->getUser();
00063         $wlowner = $this->getWatchlistUser( $params );
00064 
00065         if ( !is_null( $params['prop'] ) && is_null( $resultPageSet ) ) {
00066             $prop = array_flip( $params['prop'] );
00067 
00068             $this->fld_ids = isset( $prop['ids'] );
00069             $this->fld_title = isset( $prop['title'] );
00070             $this->fld_flags = isset( $prop['flags'] );
00071             $this->fld_user = isset( $prop['user'] );
00072             $this->fld_userid = isset( $prop['userid'] );
00073             $this->fld_comment = isset( $prop['comment'] );
00074             $this->fld_parsedcomment = isset( $prop['parsedcomment'] );
00075             $this->fld_timestamp = isset( $prop['timestamp'] );
00076             $this->fld_sizes = isset( $prop['sizes'] );
00077             $this->fld_patrol = isset( $prop['patrol'] );
00078             $this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] );
00079             $this->fld_loginfo = isset( $prop['loginfo'] );
00080 
00081             if ( $this->fld_patrol ) {
00082                 if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
00083                     $this->dieUsage( 'patrol property is not available', 'patrol' );
00084                 }
00085             }
00086         }
00087 
00088         $this->addFields( array(
00089             'rc_id',
00090             'rc_namespace',
00091             'rc_title',
00092             'rc_timestamp',
00093             'rc_type',
00094             'rc_deleted',
00095         ) );
00096 
00097         if ( is_null( $resultPageSet ) ) {
00098             $this->addFields( array(
00099                 'rc_cur_id',
00100                 'rc_this_oldid',
00101                 'rc_last_oldid',
00102             ) );
00103 
00104             $this->addFieldsIf( array( 'rc_type', 'rc_minor', 'rc_bot' ), $this->fld_flags );
00105             $this->addFieldsIf( 'rc_user', $this->fld_user || $this->fld_userid );
00106             $this->addFieldsIf( 'rc_user_text', $this->fld_user );
00107             $this->addFieldsIf( 'rc_comment', $this->fld_comment || $this->fld_parsedcomment );
00108             $this->addFieldsIf( 'rc_patrolled', $this->fld_patrol );
00109             $this->addFieldsIf( array( 'rc_old_len', 'rc_new_len' ), $this->fld_sizes );
00110             $this->addFieldsIf( 'wl_notificationtimestamp', $this->fld_notificationtimestamp );
00111             $this->addFieldsIf(
00112                 array( 'rc_logid', 'rc_log_type', 'rc_log_action', 'rc_params' ),
00113                 $this->fld_loginfo
00114             );
00115         } elseif ( $params['allrev'] ) {
00116             $this->addFields( 'rc_this_oldid' );
00117         } else {
00118             $this->addFields( 'rc_cur_id' );
00119         }
00120 
00121         $this->addTables( array(
00122             'recentchanges',
00123             'watchlist',
00124         ) );
00125 
00126         $userId = $wlowner->getId();
00127         $this->addJoinConds( array( 'watchlist' => array( 'INNER JOIN',
00128             array(
00129                 'wl_user' => $userId,
00130                 'wl_namespace=rc_namespace',
00131                 'wl_title=rc_title'
00132             )
00133         ) ) );
00134 
00135         $db = $this->getDB();
00136 
00137         $this->addTimestampWhereRange( 'rc_timestamp', $params['dir'],
00138             $params['start'], $params['end'] );
00139         // Include in ORDER BY for uniqueness
00140         $this->addWhereRange( 'rc_id', $params['dir'], null, null );
00141 
00142         if ( !is_null( $params['continue'] ) ) {
00143             $cont = explode( '|', $params['continue'] );
00144             $this->dieContinueUsageIf( count( $cont ) != 2 );
00145             $op = ( $params['dir'] === 'newer' ? '>' : '<' );
00146             $continueTimestamp = $db->addQuotes( $db->timestamp( $cont[0] ) );
00147             $continueId = (int)$cont[1];
00148             $this->dieContinueUsageIf( $continueId != $cont[1] );
00149             $this->addWhere( "rc_timestamp $op $continueTimestamp OR " .
00150                 "(rc_timestamp = $continueTimestamp AND " .
00151                 "rc_id $op= $continueId)"
00152             );
00153         }
00154 
00155         $this->addWhereFld( 'wl_namespace', $params['namespace'] );
00156 
00157         if ( !$params['allrev'] ) {
00158             $this->addTables( 'page' );
00159             $this->addJoinConds( array( 'page' => array( 'LEFT JOIN', 'rc_cur_id=page_id' ) ) );
00160             $this->addWhere( 'rc_this_oldid=page_latest OR rc_type=' . RC_LOG );
00161         }
00162 
00163         if ( !is_null( $params['show'] ) ) {
00164             $show = array_flip( $params['show'] );
00165 
00166             /* Check for conflicting parameters. */
00167             if ( ( isset( $show['minor'] ) && isset( $show['!minor'] ) )
00168                 || ( isset( $show['bot'] ) && isset( $show['!bot'] ) )
00169                 || ( isset( $show['anon'] ) && isset( $show['!anon'] ) )
00170                 || ( isset( $show['patrolled'] ) && isset( $show['!patrolled'] ) )
00171             ) {
00172                 $this->dieUsageMsg( 'show' );
00173             }
00174 
00175             // Check permissions.
00176             if ( isset( $show['patrolled'] ) || isset( $show['!patrolled'] ) ) {
00177                 if ( !$user->useRCPatrol() && !$user->useNPPatrol() ) {
00178                     $this->dieUsage(
00179                         'You need the patrol right to request the patrolled flag',
00180                         'permissiondenied'
00181                     );
00182                 }
00183             }
00184 
00185             /* Add additional conditions to query depending upon parameters. */
00186             $this->addWhereIf( 'rc_minor = 0', isset( $show['!minor'] ) );
00187             $this->addWhereIf( 'rc_minor != 0', isset( $show['minor'] ) );
00188             $this->addWhereIf( 'rc_bot = 0', isset( $show['!bot'] ) );
00189             $this->addWhereIf( 'rc_bot != 0', isset( $show['bot'] ) );
00190             $this->addWhereIf( 'rc_user = 0', isset( $show['anon'] ) );
00191             $this->addWhereIf( 'rc_user != 0', isset( $show['!anon'] ) );
00192             $this->addWhereIf( 'rc_patrolled = 0', isset( $show['!patrolled'] ) );
00193             $this->addWhereIf( 'rc_patrolled != 0', isset( $show['patrolled'] ) );
00194         }
00195 
00196         if ( !is_null( $params['type'] ) ) {
00197             $this->addWhereFld( 'rc_type', $this->parseRCType( $params['type'] ) );
00198         }
00199 
00200         if ( !is_null( $params['user'] ) && !is_null( $params['excludeuser'] ) ) {
00201             $this->dieUsage( 'user and excludeuser cannot be used together', 'user-excludeuser' );
00202         }
00203         if ( !is_null( $params['user'] ) ) {
00204             $this->addWhereFld( 'rc_user_text', $params['user'] );
00205         }
00206         if ( !is_null( $params['excludeuser'] ) ) {
00207             $this->addWhere( 'rc_user_text != ' . $db->addQuotes( $params['excludeuser'] ) );
00208         }
00209 
00210         // This is an index optimization for mysql, as done in the Special:Watchlist page
00211         $this->addWhereIf(
00212             "rc_timestamp > ''",
00213             !isset( $params['start'] ) && !isset( $params['end'] ) && $db->getType() == 'mysql'
00214         );
00215 
00216         // Paranoia: avoid brute force searches (bug 17342)
00217         if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) {
00218             if ( !$user->isAllowed( 'deletedhistory' ) ) {
00219                 $bitmask = Revision::DELETED_USER;
00220             } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
00221                 $bitmask = Revision::DELETED_USER | Revision::DELETED_RESTRICTED;
00222             } else {
00223                 $bitmask = 0;
00224             }
00225             if ( $bitmask ) {
00226                 $this->addWhere( $this->getDB()->bitAnd( 'rc_deleted', $bitmask ) . " != $bitmask" );
00227             }
00228         }
00229 
00230         // LogPage::DELETED_ACTION hides the affected page, too. So hide those
00231         // entirely from the watchlist, or someone could guess the title.
00232         if ( !$user->isAllowed( 'deletedhistory' ) ) {
00233             $bitmask = LogPage::DELETED_ACTION;
00234         } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
00235             $bitmask = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED;
00236         } else {
00237             $bitmask = 0;
00238         }
00239         if ( $bitmask ) {
00240             $this->addWhere( $this->getDB()->makeList( array(
00241                 'rc_type != ' . RC_LOG,
00242                 $this->getDB()->bitAnd( 'rc_deleted', $bitmask ) . " != $bitmask",
00243             ), LIST_OR ) );
00244         }
00245 
00246         $this->addOption( 'LIMIT', $params['limit'] + 1 );
00247 
00248         $ids = array();
00249         $count = 0;
00250         $res = $this->select( __METHOD__ );
00251 
00252         foreach ( $res as $row ) {
00253             if ( ++$count > $params['limit'] ) {
00254                 // We've reached the one extra which shows that there are
00255                 // additional pages to be had. Stop here...
00256                 $this->setContinueEnumParameter( 'continue', "$row->rc_timestamp|$row->rc_id" );
00257                 break;
00258             }
00259 
00260             if ( is_null( $resultPageSet ) ) {
00261                 $vals = $this->extractRowInfo( $row );
00262                 $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ), null, $vals );
00263                 if ( !$fit ) {
00264                     $this->setContinueEnumParameter( 'continue', "$row->rc_timestamp|$row->rc_id" );
00265                     break;
00266                 }
00267             } else {
00268                 if ( $params['allrev'] ) {
00269                     $ids[] = intval( $row->rc_this_oldid );
00270                 } else {
00271                     $ids[] = intval( $row->rc_cur_id );
00272                 }
00273             }
00274         }
00275 
00276         if ( is_null( $resultPageSet ) ) {
00277             $this->getResult()->setIndexedTagName_internal(
00278                 array( 'query', $this->getModuleName() ),
00279                 'item'
00280             );
00281         } elseif ( $params['allrev'] ) {
00282             $resultPageSet->populateFromRevisionIDs( $ids );
00283         } else {
00284             $resultPageSet->populateFromPageIDs( $ids );
00285         }
00286     }
00287 
00288     private function extractRowInfo( $row ) {
00289         /* Determine the title of the page that has been changed. */
00290         $title = Title::makeTitle( $row->rc_namespace, $row->rc_title );
00291         $user = $this->getUser();
00292 
00293         /* Our output data. */
00294         $vals = array();
00295 
00296         $type = intval( $row->rc_type );
00297 
00298         /* Determine what kind of change this was. */
00299         switch ( $type ) {
00300             case RC_EDIT:
00301                 $vals['type'] = 'edit';
00302                 break;
00303             case RC_NEW:
00304                 $vals['type'] = 'new';
00305                 break;
00306             case RC_MOVE:
00307                 $vals['type'] = 'move';
00308                 break;
00309             case RC_LOG:
00310                 $vals['type'] = 'log';
00311                 break;
00312             case RC_EXTERNAL:
00313                 $vals['type'] = 'external';
00314                 break;
00315             case RC_MOVE_OVER_REDIRECT:
00316                 $vals['type'] = 'move over redirect';
00317                 break;
00318             default:
00319                 $vals['type'] = $type;
00320         }
00321 
00322         $anyHidden = false;
00323 
00324         /* Create a new entry in the result for the title. */
00325         if ( $this->fld_title || $this->fld_ids ) {
00326             // These should already have been filtered out of the query, but just in case.
00327             if ( $type === RC_LOG && ( $row->rc_deleted & LogPage::DELETED_ACTION ) ) {
00328                 $vals['actionhidden'] = '';
00329                 $anyHidden = true;
00330             }
00331             if ( $type !== RC_LOG ||
00332                 LogEventsList::userCanBitfield( $row->rc_deleted, LogPage::DELETED_ACTION, $user )
00333             ) {
00334                 if ( $this->fld_title ) {
00335                     ApiQueryBase::addTitleInfo( $vals, $title );
00336                 }
00337                 if ( $this->fld_ids ) {
00338                     $vals['pageid'] = intval( $row->rc_cur_id );
00339                     $vals['revid'] = intval( $row->rc_this_oldid );
00340                     $vals['old_revid'] = intval( $row->rc_last_oldid );
00341                 }
00342             }
00343         }
00344 
00345         /* Add user data and 'anon' flag, if user is anonymous. */
00346         if ( $this->fld_user || $this->fld_userid ) {
00347             if ( $row->rc_deleted & Revision::DELETED_USER ) {
00348                 $vals['userhidden'] = '';
00349                 $anyHidden = true;
00350             }
00351             if ( Revision::userCanBitfield( $row->rc_deleted, Revision::DELETED_USER, $user ) ) {
00352                 if ( $this->fld_userid ) {
00353                     $vals['userid'] = $row->rc_user;
00354                     // for backwards compatibility
00355                     $vals['user'] = $row->rc_user;
00356                 }
00357 
00358                 if ( $this->fld_user ) {
00359                     $vals['user'] = $row->rc_user_text;
00360                 }
00361 
00362                 if ( !$row->rc_user ) {
00363                     $vals['anon'] = '';
00364                 }
00365             }
00366         }
00367 
00368         /* Add flags, such as new, minor, bot. */
00369         if ( $this->fld_flags ) {
00370             if ( $row->rc_bot ) {
00371                 $vals['bot'] = '';
00372             }
00373             if ( $row->rc_type == RC_NEW ) {
00374                 $vals['new'] = '';
00375             }
00376             if ( $row->rc_minor ) {
00377                 $vals['minor'] = '';
00378             }
00379         }
00380 
00381         /* Add sizes of each revision. (Only available on 1.10+) */
00382         if ( $this->fld_sizes ) {
00383             $vals['oldlen'] = intval( $row->rc_old_len );
00384             $vals['newlen'] = intval( $row->rc_new_len );
00385         }
00386 
00387         /* Add the timestamp. */
00388         if ( $this->fld_timestamp ) {
00389             $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $row->rc_timestamp );
00390         }
00391 
00392         if ( $this->fld_notificationtimestamp ) {
00393             $vals['notificationtimestamp'] = ( $row->wl_notificationtimestamp == null )
00394                 ? ''
00395                 : wfTimestamp( TS_ISO_8601, $row->wl_notificationtimestamp );
00396         }
00397 
00398         /* Add edit summary / log summary. */
00399         if ( $this->fld_comment || $this->fld_parsedcomment ) {
00400             if ( $row->rc_deleted & Revision::DELETED_COMMENT ) {
00401                 $vals['commenthidden'] = '';
00402                 $anyHidden = true;
00403             }
00404             if ( Revision::userCanBitfield( $row->rc_deleted, Revision::DELETED_COMMENT, $user ) ) {
00405                 if ( $this->fld_comment && isset( $row->rc_comment ) ) {
00406                     $vals['comment'] = $row->rc_comment;
00407                 }
00408 
00409                 if ( $this->fld_parsedcomment && isset( $row->rc_comment ) ) {
00410                     $vals['parsedcomment'] = Linker::formatComment( $row->rc_comment, $title );
00411                 }
00412             }
00413         }
00414 
00415         /* Add the patrolled flag */
00416         if ( $this->fld_patrol && $row->rc_patrolled == 1 ) {
00417             $vals['patrolled'] = '';
00418         }
00419 
00420         if ( $this->fld_patrol && ChangesList::isUnpatrolled( $row, $user ) ) {
00421             $vals['unpatrolled'] = '';
00422         }
00423 
00424         if ( $this->fld_loginfo && $row->rc_type == RC_LOG ) {
00425             if ( $row->rc_deleted & LogPage::DELETED_ACTION ) {
00426                 $vals['actionhidden'] = '';
00427                 $anyHidden = true;
00428             }
00429             if ( LogEventsList::userCanBitfield( $row->rc_deleted, LogPage::DELETED_ACTION, $user ) ) {
00430                 $vals['logid'] = intval( $row->rc_logid );
00431                 $vals['logtype'] = $row->rc_log_type;
00432                 $vals['logaction'] = $row->rc_log_action;
00433                 $logEntry = DatabaseLogEntry::newFromRow( (array)$row );
00434                 ApiQueryLogEvents::addLogParams(
00435                     $this->getResult(),
00436                     $vals,
00437                     $logEntry->getParameters(),
00438                     $logEntry->getType(),
00439                     $logEntry->getSubtype(),
00440                     $logEntry->getTimestamp()
00441                 );
00442             }
00443         }
00444 
00445         if ( $anyHidden && ( $row->rc_deleted & Revision::DELETED_RESTRICTED ) ) {
00446             $vals['suppressed'] = '';
00447         }
00448 
00449         return $vals;
00450     }
00451 
00457     private function parseRCType( $type ) {
00458         if ( is_array( $type ) ) {
00459             $retval = array();
00460             foreach ( $type as $t ) {
00461                 $retval[] = $this->parseRCType( $t );
00462             }
00463 
00464             return $retval;
00465         }
00466 
00467         switch ( $type ) {
00468             case 'edit':
00469                 return RC_EDIT;
00470             case 'new':
00471                 return RC_NEW;
00472             case 'log':
00473                 return RC_LOG;
00474             case 'external':
00475                 return RC_EXTERNAL;
00476             default:
00477                 ApiBase::dieDebug( __METHOD__, "Unknown type '$type'" );
00478         }
00479     }
00480 
00481     public function getAllowedParams() {
00482         return array(
00483             'allrev' => false,
00484             'start' => array(
00485                 ApiBase::PARAM_TYPE => 'timestamp'
00486             ),
00487             'end' => array(
00488                 ApiBase::PARAM_TYPE => 'timestamp'
00489             ),
00490             'namespace' => array(
00491                 ApiBase::PARAM_ISMULTI => true,
00492                 ApiBase::PARAM_TYPE => 'namespace'
00493             ),
00494             'user' => array(
00495                 ApiBase::PARAM_TYPE => 'user',
00496             ),
00497             'excludeuser' => array(
00498                 ApiBase::PARAM_TYPE => 'user',
00499             ),
00500             'dir' => array(
00501                 ApiBase::PARAM_DFLT => 'older',
00502                 ApiBase::PARAM_TYPE => array(
00503                     'newer',
00504                     'older'
00505                 )
00506             ),
00507             'limit' => array(
00508                 ApiBase::PARAM_DFLT => 10,
00509                 ApiBase::PARAM_TYPE => 'limit',
00510                 ApiBase::PARAM_MIN => 1,
00511                 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
00512                 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
00513             ),
00514             'prop' => array(
00515                 ApiBase::PARAM_ISMULTI => true,
00516                 ApiBase::PARAM_DFLT => 'ids|title|flags',
00517                 ApiBase::PARAM_TYPE => array(
00518                     'ids',
00519                     'title',
00520                     'flags',
00521                     'user',
00522                     'userid',
00523                     'comment',
00524                     'parsedcomment',
00525                     'timestamp',
00526                     'patrol',
00527                     'sizes',
00528                     'notificationtimestamp',
00529                     'loginfo',
00530                 )
00531             ),
00532             'show' => array(
00533                 ApiBase::PARAM_ISMULTI => true,
00534                 ApiBase::PARAM_TYPE => array(
00535                     'minor',
00536                     '!minor',
00537                     'bot',
00538                     '!bot',
00539                     'anon',
00540                     '!anon',
00541                     'patrolled',
00542                     '!patrolled',
00543                 )
00544             ),
00545             'type' => array(
00546                 ApiBase::PARAM_ISMULTI => true,
00547                 ApiBase::PARAM_TYPE => array(
00548                     'edit',
00549                     'external',
00550                     'new',
00551                     'log',
00552                 )
00553             ),
00554             'owner' => array(
00555                 ApiBase::PARAM_TYPE => 'user'
00556             ),
00557             'token' => array(
00558                 ApiBase::PARAM_TYPE => 'string'
00559             ),
00560             'continue' => null,
00561         );
00562     }
00563 
00564     public function getParamDescription() {
00565         $p = $this->getModulePrefix();
00566 
00567         return array(
00568             'allrev' => 'Include multiple revisions of the same page within given timeframe',
00569             'start' => 'The timestamp to start enumerating from',
00570             'end' => 'The timestamp to end enumerating',
00571             'namespace' => 'Filter changes to only the given namespace(s)',
00572             'user' => 'Only list changes by this user',
00573             'excludeuser' => 'Don\'t list changes by this user',
00574             'dir' => $this->getDirectionDescription( $p ),
00575             'limit' => 'How many total results to return per request',
00576             'prop' => array(
00577                 'Which additional items to get (non-generator mode only).',
00578                 ' ids                    - Adds revision ids and page ids',
00579                 ' title                  - Adds title of the page',
00580                 ' flags                  - Adds flags for the edit',
00581                 ' user                   - Adds the user who made the edit',
00582                 ' userid                 - Adds user id of whom made the edit',
00583                 ' comment                - Adds comment of the edit',
00584                 ' parsedcomment          - Adds parsed comment of the edit',
00585                 ' timestamp              - Adds timestamp of the edit',
00586                 ' patrol                 - Tags edits that are patrolled',
00587                 ' sizes                  - Adds the old and new lengths of the page',
00588                 ' notificationtimestamp  - Adds timestamp of when the user was last notified about the edit',
00589                 ' loginfo                - Adds log information where appropriate',
00590             ),
00591             'show' => array(
00592                 'Show only items that meet this criteria.',
00593                 "For example, to see only minor edits done by logged-in users, set {$p}show=minor|!anon"
00594             ),
00595             'type' => array(
00596                 'Which types of changes to show',
00597                 ' edit           - Regular page edits',
00598                 ' external       - External changes',
00599                 ' new            - Page creations',
00600                 ' log            - Log entries',
00601             ),
00602             'owner' => 'The name of the user whose watchlist you\'d like to access',
00603             'token' => 'Give a security token (settable in preferences) to ' .
00604                 'allow access to another user\'s watchlist',
00605             'continue' => 'When more results are available, use this to continue',
00606         );
00607     }
00608 
00609     public function getResultProperties() {
00610         global $wgLogTypes;
00611 
00612         return array(
00613             '' => array(
00614                 'type' => array(
00615                     ApiBase::PROP_TYPE => array(
00616                         'edit',
00617                         'new',
00618                         'move',
00619                         'log',
00620                         'move over redirect'
00621                     )
00622                 )
00623             ),
00624             'ids' => array(
00625                 'pageid' => 'integer',
00626                 'revid' => 'integer',
00627                 'old_revid' => 'integer'
00628             ),
00629             'title' => array(
00630                 'ns' => 'namespace',
00631                 'title' => 'string'
00632             ),
00633             'user' => array(
00634                 'user' => 'string',
00635                 'anon' => 'boolean'
00636             ),
00637             'userid' => array(
00638                 'userid' => 'integer',
00639                 'anon' => 'boolean'
00640             ),
00641             'flags' => array(
00642                 'new' => 'boolean',
00643                 'minor' => 'boolean',
00644                 'bot' => 'boolean'
00645             ),
00646             'patrol' => array(
00647                 'patrolled' => 'boolean'
00648             ),
00649             'timestamp' => array(
00650                 'timestamp' => 'timestamp'
00651             ),
00652             'sizes' => array(
00653                 'oldlen' => 'integer',
00654                 'newlen' => 'integer'
00655             ),
00656             'notificationtimestamp' => array(
00657                 'notificationtimestamp' => array(
00658                     ApiBase::PROP_TYPE => 'timestamp',
00659                     ApiBase::PROP_NULLABLE => true
00660                 )
00661             ),
00662             'comment' => array(
00663                 'comment' => array(
00664                     ApiBase::PROP_TYPE => 'string',
00665                     ApiBase::PROP_NULLABLE => true
00666                 )
00667             ),
00668             'parsedcomment' => array(
00669                 'parsedcomment' => array(
00670                     ApiBase::PROP_TYPE => 'string',
00671                     ApiBase::PROP_NULLABLE => true
00672                 )
00673             ),
00674             'loginfo' => array(
00675                 'logid' => array(
00676                     ApiBase::PROP_TYPE => 'integer',
00677                     ApiBase::PROP_NULLABLE => true
00678                 ),
00679                 'logtype' => array(
00680                     ApiBase::PROP_TYPE => $wgLogTypes,
00681                     ApiBase::PROP_NULLABLE => true
00682                 ),
00683                 'logaction' => array(
00684                     ApiBase::PROP_TYPE => 'string',
00685                     ApiBase::PROP_NULLABLE => true
00686                 )
00687             )
00688         );
00689     }
00690 
00691     public function getDescription() {
00692         return "Get all recent changes to pages in the logged in user's watchlist.";
00693     }
00694 
00695     public function getPossibleErrors() {
00696         return array_merge( parent::getPossibleErrors(), array(
00697             array( 'code' => 'bad_wlowner', 'info' => 'Specified user does not exist' ),
00698             array(
00699                 'code' => 'bad_wltoken',
00700                 'info' => 'Incorrect watchlist token provided -- ' .
00701                     'please set a correct token in Special:Preferences'
00702             ),
00703             array( 'code' => 'notloggedin', 'info' => 'You must be logged-in to have a watchlist' ),
00704             array( 'code' => 'patrol', 'info' => 'patrol property is not available' ),
00705             array( 'show' ),
00706             array(
00707                 'code' => 'permissiondenied',
00708                 'info' => 'You need the patrol right to request the patrolled flag'
00709             ),
00710             array( 'code' => 'user-excludeuser', 'info' => 'user and excludeuser cannot be used together' ),
00711         ) );
00712     }
00713 
00714     public function getExamples() {
00715         return array(
00716             'api.php?action=query&list=watchlist',
00717             'api.php?action=query&list=watchlist&wlprop=ids|title|timestamp|user|comment',
00718             'api.php?action=query&list=watchlist&wlallrev=&wlprop=ids|title|timestamp|user|comment',
00719             'api.php?action=query&generator=watchlist&prop=info',
00720             'api.php?action=query&generator=watchlist&gwlallrev=&prop=revisions&rvprop=timestamp|user',
00721             'api.php?action=query&list=watchlist&wlowner=Bob_Smith&wltoken=123ABC'
00722         );
00723     }
00724 
00725     public function getHelpUrls() {
00726         return 'https://www.mediawiki.org/wiki/API:Watchlist';
00727     }
00728 }