mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Echo
synced 2024-11-28 01:30:15 +00:00
Merge "Rip general cross-wiki API request helpers out of ApiEchoNotifications"
This commit is contained in:
commit
5992e88f6e
|
@ -4,6 +4,7 @@
|
|||
global $wgAutoloadClasses;
|
||||
|
||||
$wgAutoloadClasses += [
|
||||
'ApiCrossWikiBase' => __DIR__ . '/includes/api/ApiCrossWikiBase.php',
|
||||
'ApiEchoMarkRead' => __DIR__ . '/includes/api/ApiEchoMarkRead.php',
|
||||
'ApiEchoMarkReadTest' => __DIR__ . '/tests/phpunit/api/ApiEchoMarkReadTest.php',
|
||||
'ApiEchoMarkSeen' => __DIR__ . '/includes/api/ApiEchoMarkSeen.php',
|
||||
|
|
170
includes/api/ApiCrossWikiBase.php
Normal file
170
includes/api/ApiCrossWikiBase.php
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
use MediaWiki\Logger\LoggerFactory;
|
||||
|
||||
abstract class ApiCrossWikiBase extends ApiQueryBase {
|
||||
/**
|
||||
* @var EchoForeignNotifications
|
||||
*/
|
||||
protected $foreignNotifications;
|
||||
|
||||
/**
|
||||
* @param ApiQuery $queryModule
|
||||
* @param string $moduleName
|
||||
* @param string $paramPrefix
|
||||
*/
|
||||
public function __construct( ApiQuery $queryModule, $moduleName, $paramPrefix = '' ) {
|
||||
parent::__construct( $queryModule, $moduleName, $paramPrefix );
|
||||
|
||||
$this->foreignNotifications = new EchoForeignNotifications( $this->getUser() );
|
||||
}
|
||||
|
||||
/**
|
||||
* This will turn the current API call (with all of it's params) and execute
|
||||
* it on all foreign wikis, returning an array of results per wiki.
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getFromForeign() {
|
||||
$reqs = $this->getForeignRequestParams( $this->getForeignWikis() );
|
||||
|
||||
return $this->foreignRequests( $reqs );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function allowCrossWikiNotifications() {
|
||||
global $wgEchoCrossWikiNotifications;
|
||||
return $wgEchoCrossWikiNotifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array Wiki names
|
||||
*/
|
||||
protected function getForeignWikis() {
|
||||
if ( !$this->allowCrossWikiNotifications() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$params = $this->extractRequestParams();
|
||||
return array_diff( $params['wikis'], array( wfWikiId() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return string
|
||||
*/
|
||||
protected function getCentralAuthToken( User $user ) {
|
||||
$context = new RequestContext;
|
||||
$context->setRequest( new FauxRequest( array( 'action' => 'centralauthtoken' ) ) );
|
||||
$context->setUser( $user );
|
||||
|
||||
$api = new ApiMain( $context );
|
||||
$api->execute();
|
||||
|
||||
return $api->getResult()->getResultData( array( 'centralauthtoken', 'centralauthtoken' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $wikis Wiki names
|
||||
* @return array
|
||||
*/
|
||||
protected function getForeignRequestParams( array $wikis ) {
|
||||
$apis = $this->foreignNotifications->getApiEndpoints( $wikis );
|
||||
if ( !$apis ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$reqs = array();
|
||||
foreach ( $apis as $wiki => $api ) {
|
||||
$reqs[$wiki] = array(
|
||||
'method' => 'GET',
|
||||
'url' => $api['url'],
|
||||
'query' => $this->getForeignQueryParams( $wiki ),
|
||||
);
|
||||
}
|
||||
|
||||
return $reqs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $wiki Wiki name
|
||||
* @return array
|
||||
*/
|
||||
protected function getForeignQueryParams( $wiki ) {
|
||||
// use original request params, to forward them to individual wikis
|
||||
$params = $this->getRequest()->getValues();
|
||||
|
||||
return array(
|
||||
'centralauthtoken' => $this->getCentralAuthToken( $this->getUser() ),
|
||||
// once all the results are gathered & merged, they'll be output in the
|
||||
// user requested format
|
||||
// but this is going to be an internal request & we don't want those
|
||||
// results in the format the user requested but in a fixed format that
|
||||
// we can interpret here
|
||||
'format' => 'json',
|
||||
// Only request data from that specific wiki, or they'd all spawn
|
||||
// cross-wiki api requests...
|
||||
$this->getModulePrefix() . 'wikis' => $wiki,
|
||||
) + $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $reqs API request params
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function foreignRequests( array $reqs ) {
|
||||
$http = new MultiHttpClient( array() );
|
||||
$responses = $http->runMulti( $reqs );
|
||||
|
||||
$results = array();
|
||||
foreach ( $responses as $wiki => $response ) {
|
||||
$statusCode = $response['response']['code'];
|
||||
|
||||
if ( $statusCode >= 200 && $statusCode <= 299 ) {
|
||||
$parsed = json_decode( $response['response']['body'], true );
|
||||
if ( $parsed ) {
|
||||
$results[$wiki] = $parsed;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isset( $results[$wiki] ) ) {
|
||||
LoggerFactory::getInstance( 'Echo' )->warning(
|
||||
'Failed to fetch notifications from {wiki}. Response: {code} {response}',
|
||||
array(
|
||||
'wiki' => $wiki,
|
||||
'code' => $response['response']['code'],
|
||||
'response' => $response['response']['body'],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowedParams() {
|
||||
global $wgConf;
|
||||
|
||||
$params = array();
|
||||
|
||||
if ( $this->allowCrossWikiNotifications() ) {
|
||||
$params += array(
|
||||
// fetch notifications from multiple wikis
|
||||
'wikis' => array(
|
||||
ApiBase::PARAM_ISMULTI => true,
|
||||
ApiBase::PARAM_DFLT => wfWikiId(),
|
||||
ApiBase::PARAM_TYPE => array_unique( array_merge( $wgConf->wikis, array( wfWikiId() ) ) ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
|
@ -1,13 +1,6 @@
|
|||
<?php
|
||||
|
||||
use MediaWiki\Logger\LoggerFactory;
|
||||
|
||||
class ApiEchoNotifications extends ApiQueryBase {
|
||||
/**
|
||||
* @var EchoForeignNotifications
|
||||
*/
|
||||
protected $foreignNotifications;
|
||||
|
||||
class ApiEchoNotifications extends ApiCrossWikiBase {
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -18,7 +11,6 @@ class ApiEchoNotifications extends ApiQueryBase {
|
|||
}
|
||||
|
||||
public function execute() {
|
||||
global $wgEchoCrossWikiNotifications;
|
||||
// To avoid API warning, register the parameter used to bust browser cache
|
||||
$this->getMain()->getVal( '_' );
|
||||
|
||||
|
@ -42,24 +34,22 @@ class ApiEchoNotifications extends ApiQueryBase {
|
|||
);
|
||||
}
|
||||
|
||||
if ( $wgEchoCrossWikiNotifications ) {
|
||||
$this->foreignNotifications = new EchoForeignNotifications( $this->getUser() );
|
||||
if ( $this->allowCrossWikiNotifications() ) {
|
||||
$this->crossWikiSummary = $params['crosswikisummary'];
|
||||
$wikis = $params['wikis'];
|
||||
} else {
|
||||
$wikis = array( wfWikiId() );
|
||||
}
|
||||
|
||||
$results = array();
|
||||
if ( in_array( wfWikiId(), $wikis ) ) {
|
||||
if ( !$this->allowCrossWikiNotifications() || in_array( wfWikiId(), $params['wikis'] ) ) {
|
||||
$results[wfWikiId()] = $this->getLocalNotifications( $params );
|
||||
}
|
||||
|
||||
$foreignWikis = array_diff( $wikis, array( wfWikiId() ) );
|
||||
if ( !empty( $foreignWikis ) ) {
|
||||
// get original request params, to forward them to individual wikis
|
||||
$requestParams = $this->getRequest()->getValues();
|
||||
$results += $this->getForeignNotifications( $foreignWikis, $requestParams );
|
||||
if ( $this->getForeignWikis() ) {
|
||||
$foreignResults = $this->getFromForeign();
|
||||
foreach ( $foreignResults as $wiki => $result ) {
|
||||
if ( isset( $result['query']['notifications'] ) ) {
|
||||
$results[$wiki] = $result['query']['notifications'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// after getting local & foreign results, merge them all together
|
||||
|
@ -333,74 +323,16 @@ class ApiEchoNotifications extends ApiQueryBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return string
|
||||
*/
|
||||
protected function getCentralAuthToken( User $user ) {
|
||||
$context = new RequestContext;
|
||||
$context->setRequest( new FauxRequest( array( 'action' => 'centralauthtoken' ) ) );
|
||||
$context->setUser( $user );
|
||||
|
||||
$api = new ApiMain( $context );
|
||||
$api->execute();
|
||||
|
||||
return $api->getResult()->getResultData( array( 'centralauthtoken', 'centralauthtoken' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $wikis
|
||||
* @param array $params
|
||||
* @param string $wiki Wiki name
|
||||
* @return array
|
||||
*/
|
||||
protected function getForeignNotifications( array $wikis, array $params ) {
|
||||
$apis = $this->foreignNotifications->getApiEndpoints( $wikis );
|
||||
if ( !$apis ) {
|
||||
return array();
|
||||
}
|
||||
protected function getForeignQueryParams( $wiki ) {
|
||||
$params = parent::getForeignQueryParams( $wiki );
|
||||
|
||||
// Don't request cross-wiki notifications
|
||||
// don't request cross-wiki notification summaries
|
||||
unset( $params['notcrosswikisummary'] );
|
||||
$params['format'] = 'json';
|
||||
|
||||
$reqs = array();
|
||||
foreach ( $apis as $wiki => $api ) {
|
||||
$reqs[$wiki] = array(
|
||||
'method' => 'GET',
|
||||
'url' => $api['url'],
|
||||
// Only request data from that specific wiki, or they'd all spawn
|
||||
// cross-wiki api requests...
|
||||
'query' => array_merge( $params, array(
|
||||
'notwikis' => $wiki,
|
||||
'centralauthtoken' => $this->getCentralAuthToken( $this->getUser() )
|
||||
) ),
|
||||
);
|
||||
}
|
||||
|
||||
$http = new MultiHttpClient( array() );
|
||||
$responses = $http->runMulti( $reqs );
|
||||
|
||||
$results = array();
|
||||
foreach ( $responses as $wiki => $response ) {
|
||||
$statusCode = $response['response']['code'];
|
||||
if ( $statusCode >= 200 && $statusCode <= 299 ) {
|
||||
$parsed = json_decode( $response['response']['body'], true );
|
||||
if ( $parsed && isset( $parsed['query']['notifications'] ) ) {
|
||||
$results[$wiki] = $parsed['query']['notifications'];
|
||||
}
|
||||
}
|
||||
if ( !isset( $results[$wiki] ) ) {
|
||||
LoggerFactory::getInstance( 'Echo' )->warning(
|
||||
"Failed to fetch notifications from {wiki}. Response: {code} {response}",
|
||||
array(
|
||||
'wiki' => $wiki,
|
||||
'code' => $response['response']['code'],
|
||||
'response' => $response['response']['body'],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -495,10 +427,10 @@ class ApiEchoNotifications extends ApiQueryBase {
|
|||
}
|
||||
|
||||
public function getAllowedParams() {
|
||||
global $wgConf, $wgEchoCrossWikiNotifications;
|
||||
|
||||
$sections = EchoAttributeManager::$sections;
|
||||
$params = array(
|
||||
|
||||
$params = parent::getAllowedParams();
|
||||
$params += array(
|
||||
'filter' => array(
|
||||
ApiBase::PARAM_ISMULTI => true,
|
||||
ApiBase::PARAM_DFLT => 'read|!read',
|
||||
|
@ -557,14 +489,8 @@ class ApiEchoNotifications extends ApiQueryBase {
|
|||
);
|
||||
}
|
||||
|
||||
if ( $wgEchoCrossWikiNotifications ) {
|
||||
if ( $this->allowCrossWikiNotifications() ) {
|
||||
$params += array(
|
||||
// fetch notifications from multiple wikis
|
||||
'wikis' => array(
|
||||
ApiBase::PARAM_ISMULTI => true,
|
||||
ApiBase::PARAM_DFLT => wfWikiId(),
|
||||
ApiBase::PARAM_TYPE => array_unique( array_merge( $wgConf->wikis, array( wfWikiId() ) ) ),
|
||||
),
|
||||
// create "x notifications from y wikis" notification bundle &
|
||||
// include unread counts from other wikis in prop=count results
|
||||
'crosswikisummary' => array(
|
||||
|
|
Loading…
Reference in a new issue