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