MediaWiki
REL1_24
|
00001 <?php 00032 class ApiQueryInfo extends ApiQueryBase { 00033 00034 private $fld_protection = false, $fld_talkid = false, 00035 $fld_subjectid = false, $fld_url = false, 00036 $fld_readable = false, $fld_watched = false, $fld_watchers = false, 00037 $fld_notificationtimestamp = false, 00038 $fld_preload = false, $fld_displaytitle = false; 00039 00040 private $params, $titles, $missing, $everything, $pageCounter; 00041 00042 private $pageRestrictions, $pageIsRedir, $pageIsNew, $pageTouched, 00043 $pageLatest, $pageLength; 00044 00045 private $protections, $watched, $watchers, $notificationtimestamps, 00046 $talkids, $subjectids, $displaytitles; 00047 private $showZeroWatchers = false; 00048 00049 private $tokenFunctions; 00050 00051 public function __construct( ApiQuery $query, $moduleName ) { 00052 parent::__construct( $query, $moduleName, 'in' ); 00053 } 00054 00059 public function requestExtraData( $pageSet ) { 00060 $pageSet->requestField( 'page_restrictions' ); 00061 // when resolving redirects, no page will have this field 00062 if ( !$pageSet->isResolvingRedirects() ) { 00063 $pageSet->requestField( 'page_is_redirect' ); 00064 } 00065 $pageSet->requestField( 'page_is_new' ); 00066 $config = $this->getConfig(); 00067 if ( !$config->get( 'DisableCounters' ) ) { 00068 $pageSet->requestField( 'page_counter' ); 00069 } 00070 $pageSet->requestField( 'page_touched' ); 00071 $pageSet->requestField( 'page_latest' ); 00072 $pageSet->requestField( 'page_len' ); 00073 if ( $config->get( 'ContentHandlerUseDB' ) ) { 00074 $pageSet->requestField( 'page_content_model' ); 00075 } 00076 } 00077 00085 protected function getTokenFunctions() { 00086 // Don't call the hooks twice 00087 if ( isset( $this->tokenFunctions ) ) { 00088 return $this->tokenFunctions; 00089 } 00090 00091 // If we're in JSON callback mode, no tokens can be obtained 00092 if ( !is_null( $this->getMain()->getRequest()->getVal( 'callback' ) ) ) { 00093 return array(); 00094 } 00095 00096 $this->tokenFunctions = array( 00097 'edit' => array( 'ApiQueryInfo', 'getEditToken' ), 00098 'delete' => array( 'ApiQueryInfo', 'getDeleteToken' ), 00099 'protect' => array( 'ApiQueryInfo', 'getProtectToken' ), 00100 'move' => array( 'ApiQueryInfo', 'getMoveToken' ), 00101 'block' => array( 'ApiQueryInfo', 'getBlockToken' ), 00102 'unblock' => array( 'ApiQueryInfo', 'getUnblockToken' ), 00103 'email' => array( 'ApiQueryInfo', 'getEmailToken' ), 00104 'import' => array( 'ApiQueryInfo', 'getImportToken' ), 00105 'watch' => array( 'ApiQueryInfo', 'getWatchToken' ), 00106 ); 00107 wfRunHooks( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) ); 00108 00109 return $this->tokenFunctions; 00110 } 00111 00112 static protected $cachedTokens = array(); 00113 00117 public static function resetTokenCache() { 00118 ApiQueryInfo::$cachedTokens = array(); 00119 } 00120 00124 public static function getEditToken( $pageid, $title ) { 00125 // We could check for $title->userCan('edit') here, 00126 // but that's too expensive for this purpose 00127 // and would break caching 00128 global $wgUser; 00129 if ( !$wgUser->isAllowed( 'edit' ) ) { 00130 return false; 00131 } 00132 00133 // The token is always the same, let's exploit that 00134 if ( !isset( ApiQueryInfo::$cachedTokens['edit'] ) ) { 00135 ApiQueryInfo::$cachedTokens['edit'] = $wgUser->getEditToken(); 00136 } 00137 00138 return ApiQueryInfo::$cachedTokens['edit']; 00139 } 00140 00144 public static function getDeleteToken( $pageid, $title ) { 00145 global $wgUser; 00146 if ( !$wgUser->isAllowed( 'delete' ) ) { 00147 return false; 00148 } 00149 00150 // The token is always the same, let's exploit that 00151 if ( !isset( ApiQueryInfo::$cachedTokens['delete'] ) ) { 00152 ApiQueryInfo::$cachedTokens['delete'] = $wgUser->getEditToken(); 00153 } 00154 00155 return ApiQueryInfo::$cachedTokens['delete']; 00156 } 00157 00161 public static function getProtectToken( $pageid, $title ) { 00162 global $wgUser; 00163 if ( !$wgUser->isAllowed( 'protect' ) ) { 00164 return false; 00165 } 00166 00167 // The token is always the same, let's exploit that 00168 if ( !isset( ApiQueryInfo::$cachedTokens['protect'] ) ) { 00169 ApiQueryInfo::$cachedTokens['protect'] = $wgUser->getEditToken(); 00170 } 00171 00172 return ApiQueryInfo::$cachedTokens['protect']; 00173 } 00174 00178 public static function getMoveToken( $pageid, $title ) { 00179 global $wgUser; 00180 if ( !$wgUser->isAllowed( 'move' ) ) { 00181 return false; 00182 } 00183 00184 // The token is always the same, let's exploit that 00185 if ( !isset( ApiQueryInfo::$cachedTokens['move'] ) ) { 00186 ApiQueryInfo::$cachedTokens['move'] = $wgUser->getEditToken(); 00187 } 00188 00189 return ApiQueryInfo::$cachedTokens['move']; 00190 } 00191 00195 public static function getBlockToken( $pageid, $title ) { 00196 global $wgUser; 00197 if ( !$wgUser->isAllowed( 'block' ) ) { 00198 return false; 00199 } 00200 00201 // The token is always the same, let's exploit that 00202 if ( !isset( ApiQueryInfo::$cachedTokens['block'] ) ) { 00203 ApiQueryInfo::$cachedTokens['block'] = $wgUser->getEditToken(); 00204 } 00205 00206 return ApiQueryInfo::$cachedTokens['block']; 00207 } 00208 00212 public static function getUnblockToken( $pageid, $title ) { 00213 // Currently, this is exactly the same as the block token 00214 return self::getBlockToken( $pageid, $title ); 00215 } 00216 00220 public static function getEmailToken( $pageid, $title ) { 00221 global $wgUser; 00222 if ( !$wgUser->canSendEmail() || $wgUser->isBlockedFromEmailUser() ) { 00223 return false; 00224 } 00225 00226 // The token is always the same, let's exploit that 00227 if ( !isset( ApiQueryInfo::$cachedTokens['email'] ) ) { 00228 ApiQueryInfo::$cachedTokens['email'] = $wgUser->getEditToken(); 00229 } 00230 00231 return ApiQueryInfo::$cachedTokens['email']; 00232 } 00233 00237 public static function getImportToken( $pageid, $title ) { 00238 global $wgUser; 00239 if ( !$wgUser->isAllowedAny( 'import', 'importupload' ) ) { 00240 return false; 00241 } 00242 00243 // The token is always the same, let's exploit that 00244 if ( !isset( ApiQueryInfo::$cachedTokens['import'] ) ) { 00245 ApiQueryInfo::$cachedTokens['import'] = $wgUser->getEditToken(); 00246 } 00247 00248 return ApiQueryInfo::$cachedTokens['import']; 00249 } 00250 00254 public static function getWatchToken( $pageid, $title ) { 00255 global $wgUser; 00256 if ( !$wgUser->isLoggedIn() ) { 00257 return false; 00258 } 00259 00260 // The token is always the same, let's exploit that 00261 if ( !isset( ApiQueryInfo::$cachedTokens['watch'] ) ) { 00262 ApiQueryInfo::$cachedTokens['watch'] = $wgUser->getEditToken( 'watch' ); 00263 } 00264 00265 return ApiQueryInfo::$cachedTokens['watch']; 00266 } 00267 00271 public static function getOptionsToken( $pageid, $title ) { 00272 global $wgUser; 00273 if ( !$wgUser->isLoggedIn() ) { 00274 return false; 00275 } 00276 00277 // The token is always the same, let's exploit that 00278 if ( !isset( ApiQueryInfo::$cachedTokens['options'] ) ) { 00279 ApiQueryInfo::$cachedTokens['options'] = $wgUser->getEditToken(); 00280 } 00281 00282 return ApiQueryInfo::$cachedTokens['options']; 00283 } 00284 00285 public function execute() { 00286 $this->params = $this->extractRequestParams(); 00287 if ( !is_null( $this->params['prop'] ) ) { 00288 $prop = array_flip( $this->params['prop'] ); 00289 $this->fld_protection = isset( $prop['protection'] ); 00290 $this->fld_watched = isset( $prop['watched'] ); 00291 $this->fld_watchers = isset( $prop['watchers'] ); 00292 $this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] ); 00293 $this->fld_talkid = isset( $prop['talkid'] ); 00294 $this->fld_subjectid = isset( $prop['subjectid'] ); 00295 $this->fld_url = isset( $prop['url'] ); 00296 $this->fld_readable = isset( $prop['readable'] ); 00297 $this->fld_preload = isset( $prop['preload'] ); 00298 $this->fld_displaytitle = isset( $prop['displaytitle'] ); 00299 } 00300 00301 $pageSet = $this->getPageSet(); 00302 $this->titles = $pageSet->getGoodTitles(); 00303 $this->missing = $pageSet->getMissingTitles(); 00304 $this->everything = $this->titles + $this->missing; 00305 $result = $this->getResult(); 00306 00307 uasort( $this->everything, array( 'Title', 'compare' ) ); 00308 if ( !is_null( $this->params['continue'] ) ) { 00309 // Throw away any titles we're gonna skip so they don't 00310 // clutter queries 00311 $cont = explode( '|', $this->params['continue'] ); 00312 $this->dieContinueUsageIf( count( $cont ) != 2 ); 00313 $conttitle = Title::makeTitleSafe( $cont[0], $cont[1] ); 00314 foreach ( $this->everything as $pageid => $title ) { 00315 if ( Title::compare( $title, $conttitle ) >= 0 ) { 00316 break; 00317 } 00318 unset( $this->titles[$pageid] ); 00319 unset( $this->missing[$pageid] ); 00320 unset( $this->everything[$pageid] ); 00321 } 00322 } 00323 00324 $this->pageRestrictions = $pageSet->getCustomField( 'page_restrictions' ); 00325 // when resolving redirects, no page will have this field 00326 $this->pageIsRedir = !$pageSet->isResolvingRedirects() 00327 ? $pageSet->getCustomField( 'page_is_redirect' ) 00328 : array(); 00329 $this->pageIsNew = $pageSet->getCustomField( 'page_is_new' ); 00330 00331 if ( !$this->getConfig()->get( 'DisableCounters' ) ) { 00332 $this->pageCounter = $pageSet->getCustomField( 'page_counter' ); 00333 } 00334 $this->pageTouched = $pageSet->getCustomField( 'page_touched' ); 00335 $this->pageLatest = $pageSet->getCustomField( 'page_latest' ); 00336 $this->pageLength = $pageSet->getCustomField( 'page_len' ); 00337 00338 // Get protection info if requested 00339 if ( $this->fld_protection ) { 00340 $this->getProtectionInfo(); 00341 } 00342 00343 if ( $this->fld_watched || $this->fld_notificationtimestamp ) { 00344 $this->getWatchedInfo(); 00345 } 00346 00347 if ( $this->fld_watchers ) { 00348 $this->getWatcherInfo(); 00349 } 00350 00351 // Run the talkid/subjectid query if requested 00352 if ( $this->fld_talkid || $this->fld_subjectid ) { 00353 $this->getTSIDs(); 00354 } 00355 00356 if ( $this->fld_displaytitle ) { 00357 $this->getDisplayTitle(); 00358 } 00359 00361 foreach ( $this->everything as $pageid => $title ) { 00362 $pageInfo = $this->extractPageInfo( $pageid, $title ); 00363 $fit = $result->addValue( array( 00364 'query', 00365 'pages' 00366 ), $pageid, $pageInfo ); 00367 if ( !$fit ) { 00368 $this->setContinueEnumParameter( 'continue', 00369 $title->getNamespace() . '|' . 00370 $title->getText() ); 00371 break; 00372 } 00373 } 00374 } 00375 00382 private function extractPageInfo( $pageid, $title ) { 00383 $pageInfo = array(); 00384 // $title->exists() needs pageid, which is not set for all title objects 00385 $titleExists = $pageid > 0; 00386 $ns = $title->getNamespace(); 00387 $dbkey = $title->getDBkey(); 00388 00389 $pageInfo['contentmodel'] = $title->getContentModel(); 00390 $pageInfo['pagelanguage'] = $title->getPageLanguage()->getCode(); 00391 00392 if ( $titleExists ) { 00393 $pageInfo['touched'] = wfTimestamp( TS_ISO_8601, $this->pageTouched[$pageid] ); 00394 $pageInfo['lastrevid'] = intval( $this->pageLatest[$pageid] ); 00395 $pageInfo['counter'] = $this->getConfig()->get( 'DisableCounters' ) 00396 ? '' 00397 : intval( $this->pageCounter[$pageid] ); 00398 $pageInfo['length'] = intval( $this->pageLength[$pageid] ); 00399 00400 if ( isset( $this->pageIsRedir[$pageid] ) && $this->pageIsRedir[$pageid] ) { 00401 $pageInfo['redirect'] = ''; 00402 } 00403 if ( $this->pageIsNew[$pageid] ) { 00404 $pageInfo['new'] = ''; 00405 } 00406 } 00407 00408 if ( !is_null( $this->params['token'] ) ) { 00409 $tokenFunctions = $this->getTokenFunctions(); 00410 $pageInfo['starttimestamp'] = wfTimestamp( TS_ISO_8601, time() ); 00411 foreach ( $this->params['token'] as $t ) { 00412 $val = call_user_func( $tokenFunctions[$t], $pageid, $title ); 00413 if ( $val === false ) { 00414 $this->setWarning( "Action '$t' is not allowed for the current user" ); 00415 } else { 00416 $pageInfo[$t . 'token'] = $val; 00417 } 00418 } 00419 } 00420 00421 if ( $this->fld_protection ) { 00422 $pageInfo['protection'] = array(); 00423 if ( isset( $this->protections[$ns][$dbkey] ) ) { 00424 $pageInfo['protection'] = 00425 $this->protections[$ns][$dbkey]; 00426 } 00427 $this->getResult()->setIndexedTagName( $pageInfo['protection'], 'pr' ); 00428 } 00429 00430 if ( $this->fld_watched && isset( $this->watched[$ns][$dbkey] ) ) { 00431 $pageInfo['watched'] = ''; 00432 } 00433 00434 if ( $this->fld_watchers ) { 00435 if ( isset( $this->watchers[$ns][$dbkey] ) ) { 00436 $pageInfo['watchers'] = $this->watchers[$ns][$dbkey]; 00437 } elseif ( $this->showZeroWatchers ) { 00438 $pageInfo['watchers'] = 0; 00439 } 00440 } 00441 00442 if ( $this->fld_notificationtimestamp ) { 00443 $pageInfo['notificationtimestamp'] = ''; 00444 if ( isset( $this->notificationtimestamps[$ns][$dbkey] ) ) { 00445 $pageInfo['notificationtimestamp'] = 00446 wfTimestamp( TS_ISO_8601, $this->notificationtimestamps[$ns][$dbkey] ); 00447 } 00448 } 00449 00450 if ( $this->fld_talkid && isset( $this->talkids[$ns][$dbkey] ) ) { 00451 $pageInfo['talkid'] = $this->talkids[$ns][$dbkey]; 00452 } 00453 00454 if ( $this->fld_subjectid && isset( $this->subjectids[$ns][$dbkey] ) ) { 00455 $pageInfo['subjectid'] = $this->subjectids[$ns][$dbkey]; 00456 } 00457 00458 if ( $this->fld_url ) { 00459 $pageInfo['fullurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ); 00460 $pageInfo['editurl'] = wfExpandUrl( $title->getFullURL( 'action=edit' ), PROTO_CURRENT ); 00461 $pageInfo['canonicalurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CANONICAL ); 00462 } 00463 if ( $this->fld_readable && $title->userCan( 'read', $this->getUser() ) ) { 00464 $pageInfo['readable'] = ''; 00465 } 00466 00467 if ( $this->fld_preload ) { 00468 if ( $titleExists ) { 00469 $pageInfo['preload'] = ''; 00470 } else { 00471 $text = null; 00472 wfRunHooks( 'EditFormPreloadText', array( &$text, &$title ) ); 00473 00474 $pageInfo['preload'] = $text; 00475 } 00476 } 00477 00478 if ( $this->fld_displaytitle ) { 00479 if ( isset( $this->displaytitles[$pageid] ) ) { 00480 $pageInfo['displaytitle'] = $this->displaytitles[$pageid]; 00481 } else { 00482 $pageInfo['displaytitle'] = $title->getPrefixedText(); 00483 } 00484 } 00485 00486 return $pageInfo; 00487 } 00488 00492 private function getProtectionInfo() { 00493 global $wgContLang; 00494 $this->protections = array(); 00495 $db = $this->getDB(); 00496 00497 // Get normal protections for existing titles 00498 if ( count( $this->titles ) ) { 00499 $this->resetQueryParams(); 00500 $this->addTables( 'page_restrictions' ); 00501 $this->addFields( array( 'pr_page', 'pr_type', 'pr_level', 00502 'pr_expiry', 'pr_cascade' ) ); 00503 $this->addWhereFld( 'pr_page', array_keys( $this->titles ) ); 00504 00505 $res = $this->select( __METHOD__ ); 00506 foreach ( $res as $row ) { 00508 $title = $this->titles[$row->pr_page]; 00509 $a = array( 00510 'type' => $row->pr_type, 00511 'level' => $row->pr_level, 00512 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ) 00513 ); 00514 if ( $row->pr_cascade ) { 00515 $a['cascade'] = ''; 00516 } 00517 $this->protections[$title->getNamespace()][$title->getDBkey()][] = $a; 00518 } 00519 // Also check old restrictions 00520 foreach ( $this->titles as $pageId => $title ) { 00521 if ( $this->pageRestrictions[$pageId] ) { 00522 $namespace = $title->getNamespace(); 00523 $dbKey = $title->getDBkey(); 00524 $restrictions = explode( ':', trim( $this->pageRestrictions[$pageId] ) ); 00525 foreach ( $restrictions as $restrict ) { 00526 $temp = explode( '=', trim( $restrict ) ); 00527 if ( count( $temp ) == 1 ) { 00528 // old old format should be treated as edit/move restriction 00529 $restriction = trim( $temp[0] ); 00530 00531 if ( $restriction == '' ) { 00532 continue; 00533 } 00534 $this->protections[$namespace][$dbKey][] = array( 00535 'type' => 'edit', 00536 'level' => $restriction, 00537 'expiry' => 'infinity', 00538 ); 00539 $this->protections[$namespace][$dbKey][] = array( 00540 'type' => 'move', 00541 'level' => $restriction, 00542 'expiry' => 'infinity', 00543 ); 00544 } else { 00545 $restriction = trim( $temp[1] ); 00546 if ( $restriction == '' ) { 00547 continue; 00548 } 00549 $this->protections[$namespace][$dbKey][] = array( 00550 'type' => $temp[0], 00551 'level' => $restriction, 00552 'expiry' => 'infinity', 00553 ); 00554 } 00555 } 00556 } 00557 } 00558 } 00559 00560 // Get protections for missing titles 00561 if ( count( $this->missing ) ) { 00562 $this->resetQueryParams(); 00563 $lb = new LinkBatch( $this->missing ); 00564 $this->addTables( 'protected_titles' ); 00565 $this->addFields( array( 'pt_title', 'pt_namespace', 'pt_create_perm', 'pt_expiry' ) ); 00566 $this->addWhere( $lb->constructSet( 'pt', $db ) ); 00567 $res = $this->select( __METHOD__ ); 00568 foreach ( $res as $row ) { 00569 $this->protections[$row->pt_namespace][$row->pt_title][] = array( 00570 'type' => 'create', 00571 'level' => $row->pt_create_perm, 00572 'expiry' => $wgContLang->formatExpiry( $row->pt_expiry, TS_ISO_8601 ) 00573 ); 00574 } 00575 } 00576 00577 // Cascading protections 00578 $images = $others = array(); 00579 foreach ( $this->everything as $title ) { 00580 if ( $title->getNamespace() == NS_FILE ) { 00581 $images[] = $title->getDBkey(); 00582 } else { 00583 $others[] = $title; 00584 } 00585 } 00586 00587 if ( count( $others ) ) { 00588 // Non-images: check templatelinks 00589 $lb = new LinkBatch( $others ); 00590 $this->resetQueryParams(); 00591 $this->addTables( array( 'page_restrictions', 'page', 'templatelinks' ) ); 00592 $this->addFields( array( 'pr_type', 'pr_level', 'pr_expiry', 00593 'page_title', 'page_namespace', 00594 'tl_title', 'tl_namespace' ) ); 00595 $this->addWhere( $lb->constructSet( 'tl', $db ) ); 00596 $this->addWhere( 'pr_page = page_id' ); 00597 $this->addWhere( 'pr_page = tl_from' ); 00598 $this->addWhereFld( 'pr_cascade', 1 ); 00599 00600 $res = $this->select( __METHOD__ ); 00601 foreach ( $res as $row ) { 00602 $source = Title::makeTitle( $row->page_namespace, $row->page_title ); 00603 $this->protections[$row->tl_namespace][$row->tl_title][] = array( 00604 'type' => $row->pr_type, 00605 'level' => $row->pr_level, 00606 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ), 00607 'source' => $source->getPrefixedText() 00608 ); 00609 } 00610 } 00611 00612 if ( count( $images ) ) { 00613 // Images: check imagelinks 00614 $this->resetQueryParams(); 00615 $this->addTables( array( 'page_restrictions', 'page', 'imagelinks' ) ); 00616 $this->addFields( array( 'pr_type', 'pr_level', 'pr_expiry', 00617 'page_title', 'page_namespace', 'il_to' ) ); 00618 $this->addWhere( 'pr_page = page_id' ); 00619 $this->addWhere( 'pr_page = il_from' ); 00620 $this->addWhereFld( 'pr_cascade', 1 ); 00621 $this->addWhereFld( 'il_to', $images ); 00622 00623 $res = $this->select( __METHOD__ ); 00624 foreach ( $res as $row ) { 00625 $source = Title::makeTitle( $row->page_namespace, $row->page_title ); 00626 $this->protections[NS_FILE][$row->il_to][] = array( 00627 'type' => $row->pr_type, 00628 'level' => $row->pr_level, 00629 'expiry' => $wgContLang->formatExpiry( $row->pr_expiry, TS_ISO_8601 ), 00630 'source' => $source->getPrefixedText() 00631 ); 00632 } 00633 } 00634 } 00635 00640 private function getTSIDs() { 00641 $getTitles = $this->talkids = $this->subjectids = array(); 00642 00644 foreach ( $this->everything as $t ) { 00645 if ( MWNamespace::isTalk( $t->getNamespace() ) ) { 00646 if ( $this->fld_subjectid ) { 00647 $getTitles[] = $t->getSubjectPage(); 00648 } 00649 } elseif ( $this->fld_talkid ) { 00650 $getTitles[] = $t->getTalkPage(); 00651 } 00652 } 00653 if ( !count( $getTitles ) ) { 00654 return; 00655 } 00656 00657 $db = $this->getDB(); 00658 00659 // Construct a custom WHERE clause that matches 00660 // all titles in $getTitles 00661 $lb = new LinkBatch( $getTitles ); 00662 $this->resetQueryParams(); 00663 $this->addTables( 'page' ); 00664 $this->addFields( array( 'page_title', 'page_namespace', 'page_id' ) ); 00665 $this->addWhere( $lb->constructSet( 'page', $db ) ); 00666 $res = $this->select( __METHOD__ ); 00667 foreach ( $res as $row ) { 00668 if ( MWNamespace::isTalk( $row->page_namespace ) ) { 00669 $this->talkids[MWNamespace::getSubject( $row->page_namespace )][$row->page_title] = 00670 intval( $row->page_id ); 00671 } else { 00672 $this->subjectids[MWNamespace::getTalk( $row->page_namespace )][$row->page_title] = 00673 intval( $row->page_id ); 00674 } 00675 } 00676 } 00677 00678 private function getDisplayTitle() { 00679 $this->displaytitles = array(); 00680 00681 $pageIds = array_keys( $this->titles ); 00682 00683 if ( !count( $pageIds ) ) { 00684 return; 00685 } 00686 00687 $this->resetQueryParams(); 00688 $this->addTables( 'page_props' ); 00689 $this->addFields( array( 'pp_page', 'pp_value' ) ); 00690 $this->addWhereFld( 'pp_page', $pageIds ); 00691 $this->addWhereFld( 'pp_propname', 'displaytitle' ); 00692 $res = $this->select( __METHOD__ ); 00693 00694 foreach ( $res as $row ) { 00695 $this->displaytitles[$row->pp_page] = $row->pp_value; 00696 } 00697 } 00698 00703 private function getWatchedInfo() { 00704 $user = $this->getUser(); 00705 00706 if ( $user->isAnon() || count( $this->everything ) == 0 00707 || !$user->isAllowed( 'viewmywatchlist' ) 00708 ) { 00709 return; 00710 } 00711 00712 $this->watched = array(); 00713 $this->notificationtimestamps = array(); 00714 $db = $this->getDB(); 00715 00716 $lb = new LinkBatch( $this->everything ); 00717 00718 $this->resetQueryParams(); 00719 $this->addTables( array( 'watchlist' ) ); 00720 $this->addFields( array( 'wl_title', 'wl_namespace' ) ); 00721 $this->addFieldsIf( 'wl_notificationtimestamp', $this->fld_notificationtimestamp ); 00722 $this->addWhere( array( 00723 $lb->constructSet( 'wl', $db ), 00724 'wl_user' => $user->getID() 00725 ) ); 00726 00727 $res = $this->select( __METHOD__ ); 00728 00729 foreach ( $res as $row ) { 00730 if ( $this->fld_watched ) { 00731 $this->watched[$row->wl_namespace][$row->wl_title] = true; 00732 } 00733 if ( $this->fld_notificationtimestamp ) { 00734 $this->notificationtimestamps[$row->wl_namespace][$row->wl_title] = 00735 $row->wl_notificationtimestamp; 00736 } 00737 } 00738 } 00739 00743 private function getWatcherInfo() { 00744 if ( count( $this->everything ) == 0 ) { 00745 return; 00746 } 00747 00748 $user = $this->getUser(); 00749 $canUnwatchedpages = $user->isAllowed( 'unwatchedpages' ); 00750 $unwatchedPageThreshold = $this->getConfig()->get( 'UnwatchedPageThreshold' ); 00751 if ( !$canUnwatchedpages && !is_int( $unwatchedPageThreshold ) ) { 00752 return; 00753 } 00754 00755 $this->watchers = array(); 00756 $this->showZeroWatchers = $canUnwatchedpages; 00757 $db = $this->getDB(); 00758 00759 $lb = new LinkBatch( $this->everything ); 00760 00761 $this->resetQueryParams(); 00762 $this->addTables( array( 'watchlist' ) ); 00763 $this->addFields( array( 'wl_title', 'wl_namespace', 'count' => 'COUNT(*)' ) ); 00764 $this->addWhere( array( 00765 $lb->constructSet( 'wl', $db ) 00766 ) ); 00767 $this->addOption( 'GROUP BY', array( 'wl_namespace', 'wl_title' ) ); 00768 if ( !$canUnwatchedpages ) { 00769 $this->addOption( 'HAVING', "COUNT(*) >= $unwatchedPageThreshold" ); 00770 } 00771 00772 $res = $this->select( __METHOD__ ); 00773 00774 foreach ( $res as $row ) { 00775 $this->watchers[$row->wl_namespace][$row->wl_title] = (int)$row->count; 00776 } 00777 } 00778 00779 public function getCacheMode( $params ) { 00780 $publicProps = array( 00781 'protection', 00782 'talkid', 00783 'subjectid', 00784 'url', 00785 'preload', 00786 'displaytitle', 00787 ); 00788 if ( !is_null( $params['prop'] ) ) { 00789 foreach ( $params['prop'] as $prop ) { 00790 if ( !in_array( $prop, $publicProps ) ) { 00791 return 'private'; 00792 } 00793 } 00794 } 00795 if ( !is_null( $params['token'] ) ) { 00796 return 'private'; 00797 } 00798 00799 return 'public'; 00800 } 00801 00802 public function getAllowedParams() { 00803 return array( 00804 'prop' => array( 00805 ApiBase::PARAM_DFLT => null, 00806 ApiBase::PARAM_ISMULTI => true, 00807 ApiBase::PARAM_TYPE => array( 00808 'protection', 00809 'talkid', 00810 'watched', # private 00811 'watchers', # private 00812 'notificationtimestamp', # private 00813 'subjectid', 00814 'url', 00815 'readable', # private 00816 'preload', 00817 'displaytitle', 00818 // If you add more properties here, please consider whether they 00819 // need to be added to getCacheMode() 00820 ) ), 00821 'token' => array( 00822 ApiBase::PARAM_DEPRECATED => true, 00823 ApiBase::PARAM_DFLT => null, 00824 ApiBase::PARAM_ISMULTI => true, 00825 ApiBase::PARAM_TYPE => array_keys( $this->getTokenFunctions() ) 00826 ), 00827 'continue' => null, 00828 ); 00829 } 00830 00831 public function getParamDescription() { 00832 return array( 00833 'prop' => array( 00834 'Which additional properties to get:', 00835 ' protection - List the protection level of each page', 00836 ' talkid - The page ID of the talk page for each non-talk page', 00837 ' watched - List the watched status of each page', 00838 ' watchers - The number of watchers, if allowed', 00839 ' notificationtimestamp - The watchlist notification timestamp of each page', 00840 ' subjectid - The page ID of the parent page for each talk page', 00841 ' url - Gives a full URL, an edit URL, and the canonical URL for each page', 00842 ' readable - Whether the user can read this page', 00843 ' preload - Gives the text returned by EditFormPreloadText', 00844 ' displaytitle - Gives the way the page title is actually displayed', 00845 ), 00846 'token' => 'Request a token to perform a data-modifying action on a page', 00847 'continue' => 'When more results are available, use this to continue', 00848 ); 00849 } 00850 00851 public function getDescription() { 00852 return 'Get basic page information such as namespace, title, last touched date, ...'; 00853 } 00854 00855 public function getExamples() { 00856 return array( 00857 'api.php?action=query&prop=info&titles=Main%20Page', 00858 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page' 00859 ); 00860 } 00861 00862 public function getHelpUrls() { 00863 return 'https://www.mediawiki.org/wiki/API:Properties#info_.2F_in'; 00864 } 00865 }