From: Geoffrey Mon Date: Sat, 9 Jan 2016 03:14:12 +0000 (-0500) Subject: Expose visitingwatchers to API through action=query&prop=info X-Git-Tag: 1.31.0-rc.0~8185 X-Git-Url: http://git.cyclocoop.org/%22%2C%20generer_url_ecrire%28?a=commitdiff_plain;h=5cd57713f23a52fc9812a94087d9aa2756a97331;p=lhc%2Fweb%2Fwiklou.git Expose visitingwatchers to API through action=query&prop=info Bug: T105392 Change-Id: I87059dd77dd0e280b02e9d9b638ba2725ff71762 --- diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php index 6f1e2e5bc7..286c18e159 100644 --- a/includes/api/ApiQueryInfo.php +++ b/includes/api/ApiQueryInfo.php @@ -33,7 +33,8 @@ class ApiQueryInfo extends ApiQueryBase { private $fld_protection = false, $fld_talkid = false, $fld_subjectid = false, $fld_url = false, - $fld_readable = false, $fld_watched = false, $fld_watchers = false, + $fld_readable = false, $fld_watched = false, + $fld_watchers = false, $fld_visitingwatchers = false, $fld_notificationtimestamp = false, $fld_preload = false, $fld_displaytitle = false; @@ -42,8 +43,8 @@ class ApiQueryInfo extends ApiQueryBase { private $pageRestrictions, $pageIsRedir, $pageIsNew, $pageTouched, $pageLatest, $pageLength; - private $protections, $restrictionTypes, $watched, $watchers, $notificationtimestamps, - $talkids, $subjectids, $displaytitles; + private $protections, $restrictionTypes, $watched, $watchers, $visitingwatchers, + $notificationtimestamps, $talkids, $subjectids, $displaytitles; private $showZeroWatchers = false; private $tokenFunctions; @@ -292,6 +293,7 @@ class ApiQueryInfo extends ApiQueryBase { $this->fld_protection = isset( $prop['protection'] ); $this->fld_watched = isset( $prop['watched'] ); $this->fld_watchers = isset( $prop['watchers'] ); + $this->fld_visitingwatchers = isset( $prop['visitingwatchers'] ); $this->fld_notificationtimestamp = isset( $prop['notificationtimestamp'] ); $this->fld_talkid = isset( $prop['talkid'] ); $this->fld_subjectid = isset( $prop['subjectid'] ); @@ -348,6 +350,10 @@ class ApiQueryInfo extends ApiQueryBase { $this->getWatcherInfo(); } + if ( $this->fld_visitingwatchers ) { + $this->getVisitingWatcherInfo(); + } + // Run the talkid/subjectid query if requested if ( $this->fld_talkid || $this->fld_subjectid ) { $this->getTSIDs(); @@ -447,6 +453,14 @@ class ApiQueryInfo extends ApiQueryBase { } } + if ( $this->fld_visitingwatchers ) { + if ( isset( $this->visitingwatchers[$ns][$dbkey] ) ) { + $pageInfo['visitingwatchers'] = $this->visitingwatchers[$ns][$dbkey]; + } elseif ( $this->showZeroWatchers ) { + $pageInfo['visitingwatchers'] = 0; + } + } + if ( $this->fld_notificationtimestamp ) { $pageInfo['notificationtimestamp'] = ''; if ( isset( $this->notificationtimestamps[$ns][$dbkey] ) ) { @@ -802,6 +816,98 @@ class ApiQueryInfo extends ApiQueryBase { } } + /** + * Get the count of watchers who have visited recent edits and put it in + * $this->visitingwatchers + * + * Based on InfoAction::pageCounts + */ + private function getVisitingWatcherInfo() { + $config = $this->getConfig(); + $user = $this->getUser(); + $db = $this->getDB(); + + $canUnwatchedpages = $user->isAllowed( 'unwatchedpages' ); + $unwatchedPageThreshold = $this->getConfig()->get( 'UnwatchedPageThreshold' ); + if ( !$canUnwatchedpages && !is_int( $unwatchedPageThreshold ) ) { + return; + } + + $this->showZeroWatchers = $canUnwatchedpages; + + // Assemble a WHERE condition to find: + // * if the page exists, number of users watching who have + // visited the page recently + // * if the page doesn't exist, number of users that have + // the page on their watchlist + $whereStrings = array(); + + // For pages that exist + if ( $this->titles ) { + $lb = new LinkBatch( $this->titles ); + + // Fetch last edit timestamps for pages + $this->resetQueryParams(); + $this->addTables( array( 'page', 'revision' ) ); + $this->addFields( array( 'page_namespace', 'page_title', 'rev_timestamp' ) ); + $this->addWhere( array( + 'page_latest = rev_id', + $lb->constructSet( 'page', $db ), + ) ); + $this->addOption( 'GROUP BY', array( 'page_namespace', 'page_title' ) ); + $timestampRes = $this->select( __METHOD__ ); + + // Assemble SQL WHERE condition to find number of page watchers who also + // visited a "recent" edit (last visited about 26 weeks before latest edit) + $age = $config->get( 'WatchersMaxAge' ); + $timestamps = array(); + foreach ( $timestampRes as $row ) { + $revTimestamp = wfTimestamp( TS_UNIX, (int)$row->rev_timestamp ); + $threshold = $db->timestamp( $revTimestamp - $age ); + $timestamps[$row->page_namespace][$row->page_title] = $threshold; + } + + foreach ( $timestamps as $ns_key => $namespace ) { + $pageStrings = array(); + foreach ( $namespace as $pg_key => $threshold ) { + $pageStrings[] = "wl_title = '$pg_key' AND" . + ' (wl_notificationtimestamp >= ' . + $db->addQuotes( $threshold ) . + ' OR wl_notificationtimestamp IS NULL)'; + } + $whereStrings[] = "wl_namespace = '$ns_key' AND (" . + $db->makeList( $pageStrings, LIST_OR ) . ')'; + } + } + + // For nonexistant pages + if ( $this->missing ) { + $lb = new LinkBatch( $this->missing ); + $whereStrings[] = $lb->constructSet( 'wl', $db ); + } + + // Make the actual string and do the query + $whereString = $db->makeList( $whereStrings, LIST_OR ); + + $this->resetQueryParams(); + $this->addTables( array( 'watchlist' ) ); + $this->addFields( array( + 'wl_namespace', + 'wl_title', + 'count' => 'COUNT(*)' + ) ); + $this->addWhere( array( $whereString ) ); + $this->addOption( 'GROUP BY', array( 'wl_namespace', 'wl_title' ) ); + if ( !$canUnwatchedpages ) { + $this->addOption( 'HAVING', "COUNT(*) >= $unwatchedPageThreshold" ); + } + + $res = $this->select( __METHOD__ ); + foreach ( $res as $row ) { + $this->visitingwatchers[$row->wl_namespace][$row->wl_title] = (int)$row->count; + } + } + public function getCacheMode( $params ) { // Other props depend on something about the current user $publicProps = array( @@ -837,6 +943,7 @@ class ApiQueryInfo extends ApiQueryBase { 'talkid', 'watched', # private 'watchers', # private + 'visitingwatchers', # private 'notificationtimestamp', # private 'subjectid', 'url', diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json index 55baa476c7..1af53fa7d6 100644 --- a/includes/api/i18n/en.json +++ b/includes/api/i18n/en.json @@ -804,6 +804,7 @@ "apihelp-query+info-paramvalue-prop-talkid": "The page ID of the talk page for each non-talk page.", "apihelp-query+info-paramvalue-prop-watched": "List the watched status of each page.", "apihelp-query+info-paramvalue-prop-watchers": "The number of watchers, if allowed.", + "apihelp-query+info-paramvalue-prop-visitingwatchers": "The number of watchers of each page who have visited recent edits to that page, if allowed.", "apihelp-query+info-paramvalue-prop-notificationtimestamp": "The watchlist notification timestamp of each page.", "apihelp-query+info-paramvalue-prop-subjectid": "The page ID of the parent page for each talk page.", "apihelp-query+info-paramvalue-prop-url": "Gives a full URL, an edit URL, and the canonical URL for each page.", diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json index 67056586bf..4d4614c3f4 100644 --- a/includes/api/i18n/qqq.json +++ b/includes/api/i18n/qqq.json @@ -752,6 +752,7 @@ "apihelp-query+info-paramvalue-prop-talkid": "{{doc-apihelp-paramvalue|query+info|prop|talkid}}", "apihelp-query+info-paramvalue-prop-watched": "{{doc-apihelp-paramvalue|query+info|prop|watched}}", "apihelp-query+info-paramvalue-prop-watchers": "{{doc-apihelp-paramvalue|query+info|prop|watchers}}", + "apihelp-query+info-paramvalue-prop-visitingwatchers": "{{doc-apihelp-paramvalue|query+info|prop|visitingwatchers}}", "apihelp-query+info-paramvalue-prop-notificationtimestamp": "{{doc-apihelp-paramvalue|query+info|prop|notificationtimestamp}}", "apihelp-query+info-paramvalue-prop-subjectid": "{{doc-apihelp-paramvalue|query+info|prop|subjectid}}", "apihelp-query+info-paramvalue-prop-url": "{{doc-apihelp-paramvalue|query+info|prop|url}}",