mediawiki-extensions-Echo/includes/api/ApiCrossWikiBase.php
Roan Kattouw 792de35994 Gracefully handle outdated echo_unread_wikis rows
Adds $wgEchoSectionTransition and $wgEchoBundleTransition.
If either of these settings is enabled, we will disbelieve
the alert/message counts in the euw table and obtain them
using server-side cross-wiki API queries instead.

This affects both ApiEchoNotifications (for generating the cross-wiki
summary entry) and the count and timestamp computation in NotifUser.

In bundle transition mode, we trust that notifications are classified
correctly between alerts and messages, but we don't trust the
counts in the table. In section transition mode, we trust that
the sum of the alert and message counts is the correct count,
but we don't trust the alert and message counts individually.
If both modes are enabled, we mistrust anything that's mistrusted
by either mode and only trust what's trusted by both modes.
In any event, we do trust that only the wikis with rows in the
euw table have unread notifications.

Bug: T132954
Change-Id: Ibcc8ac102dac3cf06916d67427b42457fdb93db6
2016-06-20 16:21:03 +01:00

127 lines
3.5 KiB
PHP

<?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.
*
* @param array $wikis List of wikis to query. Defaults to the result of getRequestedForeignWikis().
* @param array $paramOverrides Request parameter overrides
* @return array
* @throws Exception
*/
protected function getFromForeign( $wikis = null, array $paramOverrides = array() ) {
$foreignReq = new EchoForeignWikiRequest(
$this->getUser(),
$paramOverrides + $this->getForeignQueryParams(),
$wikis !== null ? $wikis : $this->getRequestedForeignWikis(),
$this->getModulePrefix() . 'wikis'
);
return $foreignReq->execute();
}
/**
* Get the query parameters to use for the foreign API requests.
* Subclasses should override this if they need to customize the
* parameters.
* @return array Query parameters
*/
protected function getForeignQueryParams() {
return $this->getRequest()->getValues();
}
/**
* @return bool
*/
protected function allowCrossWikiNotifications() {
global $wgEchoCrossWikiNotifications;
return $wgEchoCrossWikiNotifications;
}
/**
* This is basically equivalent to $params['wikis'], but some added checks:
* - `*` will expand to "all wikis with unread notifications"
* - if `$wgEchoCrossWikiNotifications` is off, foreign wikis will be excluded
*
* @return array
*/
protected function getRequestedWikis() {
$params = $this->extractRequestParams();
// if wiki is omitted from params, that's because crosswiki is/was not
// available, and it'll default to current wiki
$wikis = isset( $params['wikis'] ) ? $params['wikis'] : array( wfWikiID() );
if ( array_search( '*', $wikis ) !== false ) {
// expand `*` to all foreign wikis with unread notifications + local
$wikis = array_merge(
array( wfWikiID() ),
$this->getForeignWikisWithUnreadNotifications()
);
}
if ( !$this->allowCrossWikiNotifications() ) {
// exclude foreign wikis if x-wiki is not enabled
$wikis = array_intersect_key( array( wfWikiID() ), $wikis );
}
return $wikis;
}
/**
* @return array Wiki names
*/
protected function getRequestedForeignWikis() {
return array_diff( $this->getRequestedWikis(), array( wfWikiId() ) );
}
/**
* @return array Wiki names
*/
protected function getForeignWikisWithUnreadNotifications() {
return $this->foreignNotifications->getWikis();
}
/**
* @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(),
// `*` will let you immediately fetch from all wikis that have
// unread notifications, without having to look them up first
ApiBase::PARAM_TYPE => array_unique( array_merge( $wgConf->wikis, array( wfWikiId(), '*' ) ) ),
),
);
}
return $params;
}
}