64 parent::__construct(
$query, $moduleName,
'in' );
72 $pageSet->requestField(
'page_restrictions' );
76 $pageSet->requestField(
'page_is_redirect' );
77 $pageSet->requestField(
'page_is_new' );
79 $pageSet->requestField(
'page_touched' );
80 $pageSet->requestField(
'page_latest' );
81 $pageSet->requestField(
'page_len' );
82 if ( $config->get(
'ContentHandlerUseDB' ) ) {
83 $pageSet->requestField(
'page_content_model' );
85 if ( $config->get(
'PageLanguageUseDB' ) ) {
86 $pageSet->requestField(
'page_lang' );
99 if ( isset( $this->tokenFunctions ) ) {
109 $this->tokenFunctions = [
110 'edit' => [
'ApiQueryInfo',
'getEditToken' ],
111 'delete' => [
'ApiQueryInfo',
'getDeleteToken' ],
112 'protect' => [
'ApiQueryInfo',
'getProtectToken' ],
113 'move' => [
'ApiQueryInfo',
'getMoveToken' ],
114 'block' => [
'ApiQueryInfo',
'getBlockToken' ],
115 'unblock' => [
'ApiQueryInfo',
'getUnblockToken' ],
116 'email' => [
'ApiQueryInfo',
'getEmailToken' ],
117 'import' => [
'ApiQueryInfo',
'getImportToken' ],
118 'watch' => [
'ApiQueryInfo',
'getWatchToken' ],
120 Hooks::run(
'APIQueryInfoTokens', [ &$this->tokenFunctions ] );
142 if ( !
$wgUser->isAllowed(
'edit' ) ) {
159 if ( !
$wgUser->isAllowed(
'delete' ) ) {
176 if ( !
$wgUser->isAllowed(
'protect' ) ) {
193 if ( !
$wgUser->isAllowed(
'move' ) ) {
210 if ( !
$wgUser->isAllowed(
'block' ) ) {
235 if ( !
$wgUser->canSendEmail() ||
$wgUser->isBlockedFromEmailuser() ) {
252 if ( !
$wgUser->isAllowedAny(
'import',
'importupload' ) ) {
269 if ( !
$wgUser->isLoggedIn() ) {
286 if ( !
$wgUser->isLoggedIn() ) {
300 if ( !is_null( $this->params[
'prop'] ) ) {
301 $prop = array_flip( $this->params[
'prop'] );
302 $this->fld_protection = isset( $prop[
'protection'] );
303 $this->fld_watched = isset( $prop[
'watched'] );
304 $this->fld_watchers = isset( $prop[
'watchers'] );
305 $this->fld_visitingwatchers = isset( $prop[
'visitingwatchers'] );
306 $this->fld_notificationtimestamp = isset( $prop[
'notificationtimestamp'] );
307 $this->fld_talkid = isset( $prop[
'talkid'] );
308 $this->fld_subjectid = isset( $prop[
'subjectid'] );
309 $this->fld_url = isset( $prop[
'url'] );
310 $this->fld_readable = isset( $prop[
'readable'] );
311 $this->fld_preload = isset( $prop[
'preload'] );
312 $this->fld_displaytitle = isset( $prop[
'displaytitle'] );
316 $this->titles = $pageSet->getGoodTitles();
317 $this->missing = $pageSet->getMissingTitles();
321 uasort( $this->everything, [
'Title',
'compare' ] );
322 if ( !is_null( $this->params[
'continue'] ) ) {
325 $cont = explode(
'|', $this->params[
'continue'] );
328 foreach ( $this->everything
as $pageid =>
$title ) {
332 unset( $this->titles[$pageid] );
333 unset( $this->missing[$pageid] );
334 unset( $this->everything[$pageid] );
338 $this->pageRestrictions = $pageSet->getCustomField(
'page_restrictions' );
340 $this->pageIsRedir = !$pageSet->isResolvingRedirects()
341 ? $pageSet->getCustomField(
'page_is_redirect' )
343 $this->pageIsNew = $pageSet->getCustomField(
'page_is_new' );
345 $this->pageTouched = $pageSet->getCustomField(
'page_touched' );
346 $this->pageLatest = $pageSet->getCustomField(
'page_latest' );
347 $this->pageLength = $pageSet->getCustomField(
'page_len' );
350 if ( $this->fld_protection ) {
354 if ( $this->fld_watched || $this->fld_notificationtimestamp ) {
358 if ( $this->fld_watchers ) {
362 if ( $this->fld_visitingwatchers ) {
367 if ( $this->fld_talkid || $this->fld_subjectid ) {
371 if ( $this->fld_displaytitle ) {
376 foreach ( $this->everything
as $pageid =>
$title ) {
378 $fit = $pageInfo !==
null &&
$result->addValue( [
381 ], $pageid, $pageInfo );
384 $title->getNamespace() .
'|' .
400 $titleExists = $pageid > 0;
401 $ns =
$title->getNamespace();
402 $dbkey =
$title->getDBkey();
404 $pageInfo[
'contentmodel'] =
$title->getContentModel();
406 $pageLanguage =
$title->getPageLanguage();
407 $pageInfo[
'pagelanguage'] = $pageLanguage->getCode();
408 $pageInfo[
'pagelanguagehtmlcode'] = $pageLanguage->getHtmlCode();
409 $pageInfo[
'pagelanguagedir'] = $pageLanguage->getDir();
411 if ( $titleExists ) {
412 $pageInfo[
'touched'] =
wfTimestamp( TS_ISO_8601, $this->pageTouched[$pageid] );
413 $pageInfo[
'lastrevid'] = intval( $this->pageLatest[$pageid] );
414 $pageInfo[
'length'] = intval( $this->pageLength[$pageid] );
416 if ( isset( $this->pageIsRedir[$pageid] ) && $this->pageIsRedir[$pageid] ) {
417 $pageInfo[
'redirect'] =
true;
419 if ( $this->pageIsNew[$pageid] ) {
420 $pageInfo[
'new'] =
true;
424 if ( !is_null( $this->params[
'token'] ) ) {
426 $pageInfo[
'starttimestamp'] =
wfTimestamp( TS_ISO_8601, time() );
427 foreach ( $this->params[
'token']
as $t ) {
429 if ( $val ===
false ) {
430 $this->
addWarning( [
'apiwarn-tokennotallowed', $t ] );
432 $pageInfo[
$t .
'token'] = $val;
437 if ( $this->fld_protection ) {
438 $pageInfo[
'protection'] = [];
439 if ( isset( $this->protections[$ns][$dbkey] ) ) {
440 $pageInfo[
'protection'] =
441 $this->protections[$ns][$dbkey];
445 $pageInfo[
'restrictiontypes'] = [];
446 if ( isset( $this->restrictionTypes[$ns][$dbkey] ) ) {
447 $pageInfo[
'restrictiontypes'] =
448 $this->restrictionTypes[$ns][$dbkey];
453 if ( $this->fld_watched && $this->watched !==
null ) {
454 $pageInfo[
'watched'] = $this->watched[$ns][$dbkey];
457 if ( $this->fld_watchers ) {
458 if ( $this->watchers !==
null && $this->watchers[$ns][$dbkey] !== 0 ) {
459 $pageInfo[
'watchers'] = $this->watchers[$ns][$dbkey];
460 } elseif ( $this->showZeroWatchers ) {
461 $pageInfo[
'watchers'] = 0;
465 if ( $this->fld_visitingwatchers ) {
466 if ( $this->visitingwatchers !==
null && $this->visitingwatchers[$ns][$dbkey] !== 0 ) {
467 $pageInfo[
'visitingwatchers'] = $this->visitingwatchers[$ns][$dbkey];
468 } elseif ( $this->showZeroWatchers ) {
469 $pageInfo[
'visitingwatchers'] = 0;
473 if ( $this->fld_notificationtimestamp ) {
474 $pageInfo[
'notificationtimestamp'] =
'';
475 if ( $this->notificationtimestamps[$ns][$dbkey] ) {
476 $pageInfo[
'notificationtimestamp'] =
477 wfTimestamp( TS_ISO_8601, $this->notificationtimestamps[$ns][$dbkey] );
481 if ( $this->fld_talkid && isset( $this->talkids[$ns][$dbkey] ) ) {
482 $pageInfo[
'talkid'] = $this->talkids[$ns][$dbkey];
485 if ( $this->fld_subjectid && isset( $this->subjectids[$ns][$dbkey] ) ) {
486 $pageInfo[
'subjectid'] = $this->subjectids[$ns][$dbkey];
489 if ( $this->fld_url ) {
494 if ( $this->fld_readable ) {
495 $pageInfo[
'readable'] =
$title->userCan(
'read', $this->
getUser() );
498 if ( $this->fld_preload ) {
499 if ( $titleExists ) {
500 $pageInfo[
'preload'] =
'';
505 $pageInfo[
'preload'] = $text;
509 if ( $this->fld_displaytitle ) {
510 if ( isset( $this->displaytitles[$pageid] ) ) {
511 $pageInfo[
'displaytitle'] = $this->displaytitles[$pageid];
513 $pageInfo[
'displaytitle'] =
$title->getPrefixedText();
517 if ( $this->params[
'testactions'] ) {
519 if ( $this->countTestedActions >=
$limit ) {
524 $pageInfo[
'actions'] = [];
525 foreach ( $this->params[
'testactions']
as $action ) {
526 $this->countTestedActions++;
527 $pageInfo[
'actions'][$action] =
$title->userCan( $action,
$user );
538 $this->protections = [];
539 $db = $this->
getDB();
542 if (
count( $this->titles ) ) {
545 $this->
addFields( [
'pr_page',
'pr_type',
'pr_level',
546 'pr_expiry',
'pr_cascade' ] );
547 $this->
addWhereFld(
'pr_page', array_keys( $this->titles ) );
550 foreach (
$res as $row ) {
552 $title = $this->titles[$row->pr_page];
554 'type' => $row->pr_type,
555 'level' => $row->pr_level,
558 if ( $row->pr_cascade ) {
559 $a[
'cascade'] =
true;
561 $this->protections[
$title->getNamespace()][
$title->getDBkey()][] = $a;
564 foreach ( $this->titles
as $pageId =>
$title ) {
565 if ( $this->pageRestrictions[$pageId] ) {
566 $namespace =
$title->getNamespace();
567 $dbKey =
$title->getDBkey();
568 $restrictions = explode(
':', trim( $this->pageRestrictions[$pageId] ) );
569 foreach ( $restrictions
as $restrict ) {
570 $temp = explode(
'=', trim( $restrict ) );
571 if (
count( $temp ) == 1 ) {
573 $restriction = trim( $temp[0] );
575 if ( $restriction ==
'' ) {
578 $this->protections[$namespace][$dbKey][] = [
580 'level' => $restriction,
581 'expiry' =>
'infinity',
583 $this->protections[$namespace][$dbKey][] = [
585 'level' => $restriction,
586 'expiry' =>
'infinity',
589 $restriction = trim( $temp[1] );
590 if ( $restriction ==
'' ) {
593 $this->protections[$namespace][$dbKey][] = [
595 'level' => $restriction,
596 'expiry' =>
'infinity',
605 if (
count( $this->missing ) ) {
609 $this->
addFields( [
'pt_title',
'pt_namespace',
'pt_create_perm',
'pt_expiry' ] );
610 $this->
addWhere( $lb->constructSet(
'pt', $db ) );
612 foreach (
$res as $row ) {
613 $this->protections[$row->pt_namespace][$row->pt_title][] = [
615 'level' => $row->pt_create_perm,
623 $images = $others = [];
624 foreach ( $this->everything
as $title ) {
626 $images[] =
$title->getDBkey();
631 $this->restrictionTypes[
$title->getNamespace()][
$title->getDBkey()] =
632 array_values(
$title->getRestrictionTypes() );
635 if (
count( $others ) ) {
639 $this->
addTables( [
'page_restrictions',
'page',
'templatelinks' ] );
640 $this->
addFields( [
'pr_type',
'pr_level',
'pr_expiry',
641 'page_title',
'page_namespace',
642 'tl_title',
'tl_namespace' ] );
643 $this->
addWhere( $lb->constructSet(
'tl', $db ) );
644 $this->
addWhere(
'pr_page = page_id' );
645 $this->
addWhere(
'pr_page = tl_from' );
649 foreach (
$res as $row ) {
651 $this->protections[$row->tl_namespace][$row->tl_title][] = [
652 'type' => $row->pr_type,
653 'level' => $row->pr_level,
655 'source' =>
$source->getPrefixedText()
660 if (
count( $images ) ) {
663 $this->
addTables( [
'page_restrictions',
'page',
'imagelinks' ] );
664 $this->
addFields( [
'pr_type',
'pr_level',
'pr_expiry',
665 'page_title',
'page_namespace',
'il_to' ] );
666 $this->
addWhere(
'pr_page = page_id' );
667 $this->
addWhere(
'pr_page = il_from' );
672 foreach (
$res as $row ) {
674 $this->protections[
NS_FILE][$row->il_to][] = [
675 'type' => $row->pr_type,
676 'level' => $row->pr_level,
678 'source' =>
$source->getPrefixedText()
689 $getTitles = $this->talkids = $this->subjectids = [];
692 foreach ( $this->everything
as $t ) {
694 if ( $this->fld_subjectid ) {
695 $getTitles[] =
$t->getSubjectPage();
697 } elseif ( $this->fld_talkid ) {
698 $getTitles[] =
$t->getTalkPage();
701 if ( !
count( $getTitles ) ) {
705 $db = $this->
getDB();
712 $this->
addFields( [
'page_title',
'page_namespace',
'page_id' ] );
713 $this->
addWhere( $lb->constructSet(
'page', $db ) );
715 foreach (
$res as $row ) {
718 intval( $row->page_id );
721 intval( $row->page_id );
727 $this->displaytitles = [];
729 $pageIds = array_keys( $this->titles );
731 if ( !
count( $pageIds ) ) {
737 $this->
addFields( [
'pp_page',
'pp_value' ] );
739 $this->
addWhereFld(
'pp_propname',
'displaytitle' );
742 foreach (
$res as $row ) {
743 $this->displaytitles[$row->pp_page] = $row->pp_value;
754 if (
$user->isAnon() ||
count( $this->everything ) == 0
755 || !
$user->isAllowed(
'viewmywatchlist' )
761 $this->notificationtimestamps = [];
763 $store = MediaWikiServices::getInstance()->getWatchedItemStore();
764 $timestamps = $store->getNotificationTimestampsBatch(
$user, $this->everything );
766 if ( $this->fld_watched ) {
767 foreach ( $timestamps
as $namespaceId => $dbKeys ) {
768 $this->watched[$namespaceId] = array_map(
776 if ( $this->fld_notificationtimestamp ) {
777 $this->notificationtimestamps = $timestamps;
785 if (
count( $this->everything ) == 0 ) {
790 $canUnwatchedpages =
$user->isAllowed(
'unwatchedpages' );
791 $unwatchedPageThreshold = $this->
getConfig()->get(
'UnwatchedPageThreshold' );
792 if ( !$canUnwatchedpages && !is_int( $unwatchedPageThreshold ) ) {
796 $this->showZeroWatchers = $canUnwatchedpages;
799 if ( !$canUnwatchedpages ) {
800 $countOptions[
'minimumWatchers'] = $unwatchedPageThreshold;
803 $this->watchers = MediaWikiServices::getInstance()->getWatchedItemStore()->countWatchersMultiple(
818 $db = $this->
getDB();
820 $canUnwatchedpages =
$user->isAllowed(
'unwatchedpages' );
821 $unwatchedPageThreshold = $this->
getConfig()->get(
'UnwatchedPageThreshold' );
822 if ( !$canUnwatchedpages && !is_int( $unwatchedPageThreshold ) ) {
826 $this->showZeroWatchers = $canUnwatchedpages;
828 $titlesWithThresholds = [];
829 if ( $this->titles ) {
834 $this->
addTables( [
'page',
'revision' ] );
835 $this->
addFields( [
'page_namespace',
'page_title',
'rev_timestamp' ] );
837 'page_latest = rev_id',
838 $lb->constructSet(
'page', $db ),
840 $this->
addOption(
'GROUP BY', [
'page_namespace',
'page_title' ] );
841 $timestampRes = $this->
select( __METHOD__ );
843 $age = $config->get(
'WatchersMaxAge' );
845 foreach ( $timestampRes
as $row ) {
846 $revTimestamp =
wfTimestamp( TS_UNIX, (
int)$row->rev_timestamp );
847 $timestamps[$row->page_namespace][$row->page_title] = $revTimestamp - $age;
849 $titlesWithThresholds = array_map(
859 if ( $this->missing ) {
860 $titlesWithThresholds = array_merge(
861 $titlesWithThresholds,
864 return [ $target, null ];
870 $store = MediaWikiServices::getInstance()->getWatchedItemStore();
871 $this->visitingwatchers = $store->countVisitingWatchersMultiple(
872 $titlesWithThresholds,
873 !$canUnwatchedpages ? $unwatchedPageThreshold :
null
887 if ( array_diff( (
array)
$params[
'prop'], $publicProps ) ) {
892 if (
$params[
'testactions'] ) {
896 if ( !is_null(
$params[
'token'] ) ) {
911 'watchers', #
private
912 'visitingwatchers', #
private
913 'notificationtimestamp', #
private
916 'readable', #
private
941 'action=query&prop=info&titles=Main%20Page'
942 =>
'apihelp-query+info-example-simple',
943 'action=query&prop=info&inprop=protection&titles=Main%20Page'
944 =>
'apihelp-query+info-example-protection',
949 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Info';