2012-04-27 15:14:24 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
class ApiEchoNotifications extends ApiQueryBase {
|
2013-12-02 23:11:59 +00:00
|
|
|
|
2012-04-27 15:14:24 +00:00
|
|
|
public function __construct( $query, $moduleName ) {
|
|
|
|
parent::__construct( $query, $moduleName, 'not' );
|
|
|
|
}
|
|
|
|
|
|
|
|
public function execute() {
|
2013-07-12 22:46:37 +00:00
|
|
|
// To avoid API warning, register the parameter used to bust browser cache
|
|
|
|
$this->getMain()->getVal( '_' );
|
|
|
|
|
2012-07-26 17:23:18 +00:00
|
|
|
$user = $this->getUser();
|
2012-12-07 01:08:33 +00:00
|
|
|
if ( $user->isAnon() ) {
|
|
|
|
$this->dieUsage( 'Login is required', 'login-required' );
|
|
|
|
}
|
2012-06-01 10:57:09 +00:00
|
|
|
|
2012-12-07 01:08:33 +00:00
|
|
|
$params = $this->extractRequestParams();
|
2012-04-27 15:14:24 +00:00
|
|
|
$prop = $params['prop'];
|
|
|
|
|
2012-12-07 01:08:33 +00:00
|
|
|
$result = array();
|
2012-08-30 16:04:39 +00:00
|
|
|
if ( in_array( 'list', $prop ) ) {
|
2014-08-05 21:50:54 +00:00
|
|
|
// Group notification results by section
|
|
|
|
if ( $params['groupbysection'] ) {
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileIn( __METHOD__ . '-group-by-section' );
|
2014-08-05 21:50:54 +00:00
|
|
|
foreach ( $params['sections'] as $section ) {
|
|
|
|
$result[$section] = $this->getSectionPropList(
|
|
|
|
$user, $section, $params['limit'],
|
2014-08-14 00:01:35 +00:00
|
|
|
$params[$section . 'continue'], $params['format'], $params[$section . 'unreadfirst']
|
2014-08-05 21:50:54 +00:00
|
|
|
);
|
|
|
|
$this->getResult()->setIndexedTagName( $result[$section]['list'], 'notification' );
|
|
|
|
// 'index' is built on top of 'list'
|
|
|
|
if ( in_array( 'index', $prop ) ) {
|
|
|
|
$result[$section]['index'] = $this->getPropIndex( $result[$section]['list'] );
|
|
|
|
$this->getResult()->setIndexedTagName( $result[$section]['index'], 'id' );
|
|
|
|
}
|
|
|
|
}
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-group-by-section' );
|
2014-08-05 21:50:54 +00:00
|
|
|
} else {
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileIn( __METHOD__ . '-group-by-none' );
|
2014-08-05 21:50:54 +00:00
|
|
|
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
|
|
|
$result = $this->getPropList(
|
|
|
|
$user,
|
|
|
|
$attributeManager->getUserEnabledEventsbySections( $user, 'web', $params['sections'] ),
|
|
|
|
$params['limit'], $params['continue'], $params['format']
|
|
|
|
);
|
|
|
|
$this->getResult()->setIndexedTagName( $result['list'], 'notification' );
|
|
|
|
// 'index' is built on top of 'list'
|
|
|
|
if ( in_array( 'index', $prop ) ) {
|
|
|
|
$result['index'] = $this->getPropIndex( $result['list'] );
|
|
|
|
$this->getResult()->setIndexedTagName( $result['index'], 'id' );
|
|
|
|
}
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-group-by-none' );
|
2014-07-30 22:09:22 +00:00
|
|
|
}
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2012-08-30 16:04:39 +00:00
|
|
|
if ( in_array( 'count', $prop ) ) {
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileIn( __METHOD__ . '-count' );
|
2014-08-14 18:46:26 +00:00
|
|
|
$result = array_merge_recursive(
|
|
|
|
$result,
|
|
|
|
$this->getPropcount( $user, $params['sections'], $params['groupbysection'] )
|
|
|
|
);
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-count' );
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 01:08:33 +00:00
|
|
|
$this->getResult()->setIndexedTagName( $result, 'notification' );
|
|
|
|
$this->getResult()->addValue( 'query', $this->getModuleName(), $result );
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2014-07-30 22:09:22 +00:00
|
|
|
/**
|
2014-08-05 21:50:54 +00:00
|
|
|
* Internal method for getting the property 'list' data for individual section
|
|
|
|
* @param User $user
|
|
|
|
* @param string $section
|
|
|
|
* @param int $limit
|
|
|
|
* @param string $continue
|
|
|
|
* @param string $format
|
2014-08-14 00:01:35 +00:00
|
|
|
* @param boolean $unreadFirst
|
2014-08-05 21:50:54 +00:00
|
|
|
* @return array
|
|
|
|
*/
|
2014-08-14 00:01:35 +00:00
|
|
|
protected function getSectionPropList( User $user, $section, $limit, $continue, $format, $unreadFirst = false ) {
|
2014-07-30 22:09:22 +00:00
|
|
|
$notifUser = MWEchoNotifUser::newFromUser( $user );
|
2014-08-05 21:50:54 +00:00
|
|
|
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
|
|
|
$sectionEvents = $attributeManager->getUserEnabledEventsbySections( $user, 'web', array( $section ) );
|
|
|
|
// Some section like 'message' only has flow notifications, which most wikis and
|
|
|
|
// users don't have, we should skip the query in such case
|
|
|
|
if ( !$sectionEvents || !$notifUser->shouldQuerySectionData( $section ) ) {
|
|
|
|
$result = array(
|
|
|
|
'list' => array(),
|
|
|
|
'continue' => null
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$result = $this->getPropList(
|
2014-08-14 00:01:35 +00:00
|
|
|
$user, $sectionEvents, $limit, $continue, $format, $unreadFirst
|
2014-08-05 21:50:54 +00:00
|
|
|
);
|
|
|
|
// If events exist for applicable section we should set the section status
|
|
|
|
// in cache to check whether a query should be triggered in later request.
|
|
|
|
// This is mostly for users who don't have 'message' notifications
|
|
|
|
if ( $sectionEvents ) {
|
|
|
|
$notifUser->setSectionStatusCache( $section, count( $result['list'] ) );
|
|
|
|
}
|
|
|
|
}
|
2014-07-30 22:09:22 +00:00
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-08-05 21:50:54 +00:00
|
|
|
* Internal helper method for getting property 'list' data, this is based
|
|
|
|
* on the event types specified in the arguments and it could be event types
|
|
|
|
* of a set of sections or a single section
|
|
|
|
* @param User $user
|
2014-08-14 00:01:35 +00:00
|
|
|
* @param string[] $eventTypes
|
2014-08-05 21:50:54 +00:00
|
|
|
* @param int $limit
|
|
|
|
* @param string $continue
|
|
|
|
* @param string $format
|
2014-08-14 00:01:35 +00:00
|
|
|
* @param boolean $unreadFirst
|
2014-08-05 21:50:54 +00:00
|
|
|
* @return array
|
2014-07-30 22:09:22 +00:00
|
|
|
*/
|
2014-08-14 00:01:35 +00:00
|
|
|
protected function getPropList( User $user, array $eventTypes, $limit, $continue, $format, $unreadFirst = false ) {
|
2014-07-30 22:09:22 +00:00
|
|
|
$result = array(
|
|
|
|
'list' => array(),
|
|
|
|
'continue' => null
|
|
|
|
);
|
|
|
|
|
2014-08-14 18:46:26 +00:00
|
|
|
$notifMapper = new EchoNotificationMapper();
|
2014-08-14 00:01:35 +00:00
|
|
|
|
2014-09-23 00:24:03 +00:00
|
|
|
// Prefer unread notifications. We don't care about next offset in this case
|
2014-08-14 00:01:35 +00:00
|
|
|
if ( $unreadFirst ) {
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileIn( __METHOD__ . '-fetch-data-unread-first' );
|
2014-08-14 00:01:35 +00:00
|
|
|
$notifs = $notifMapper->fetchUnreadByUser( $user, $limit, $eventTypes );
|
|
|
|
// If there are less unread notifications than we requested,
|
|
|
|
// then fill the result with some read notifications
|
|
|
|
$count = count( $notifs );
|
|
|
|
if ( $count < $limit ) {
|
2014-09-23 00:24:03 +00:00
|
|
|
// Query planner should be smart enough that passing a short list of ids to exclude
|
|
|
|
// will only visit at most that number of extra rows.
|
|
|
|
$mixedNotifs = $notifMapper->fetchByUser(
|
|
|
|
$user,
|
|
|
|
$limit - $count,
|
|
|
|
null,
|
|
|
|
$eventTypes,
|
|
|
|
array_keys( $notifs )
|
|
|
|
);
|
2014-08-14 00:01:35 +00:00
|
|
|
foreach ( $mixedNotifs as $notif ) {
|
2014-09-23 00:24:03 +00:00
|
|
|
$notifs[$notif->getEvent()->getId()] = $notif;
|
2014-08-14 00:01:35 +00:00
|
|
|
}
|
|
|
|
}
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-fetch-data-unread-first' );
|
2014-08-14 00:01:35 +00:00
|
|
|
} else {
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileIn( __METHOD__ . '-fetch-data' );
|
2014-08-14 00:01:35 +00:00
|
|
|
$notifs = $notifMapper->fetchByUser( $user, $limit + 1, $continue, $eventTypes );
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-fetch-data' );
|
2014-08-14 00:01:35 +00:00
|
|
|
}
|
2014-08-27 23:59:49 +00:00
|
|
|
|
|
|
|
wfProfileIn( __METHOD__ . '-formatting' );
|
2014-07-30 22:09:22 +00:00
|
|
|
foreach ( $notifs as $notif ) {
|
|
|
|
$result['list'][$notif->getEvent()->getID()] = EchoDataOutputFormatter::formatOutput( $notif, $format, $user );
|
|
|
|
}
|
2014-08-27 23:59:49 +00:00
|
|
|
wfProfileOut( __METHOD__ . '-formatting' );
|
2014-07-30 22:09:22 +00:00
|
|
|
|
2014-08-26 20:07:11 +00:00
|
|
|
// Generate offset if necessary
|
|
|
|
if ( !$unreadFirst ) {
|
|
|
|
if ( count( $result['list'] ) > $limit ) {
|
|
|
|
$lastItem = array_pop( $result['list'] );
|
|
|
|
$result['continue'] = $lastItem['timestamp']['utcunix'] . '|' . $lastItem['id'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-30 22:09:22 +00:00
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
/**
|
|
|
|
* Internal helper method for getting property 'count' data
|
|
|
|
* @param User $user
|
|
|
|
* @param string[] $sections
|
|
|
|
* @param boolean $groupBySection
|
|
|
|
* @return aray
|
|
|
|
*/
|
|
|
|
protected function getPropCount( User $user, array $sections, $groupBySection ) {
|
|
|
|
$result = array();
|
|
|
|
$notifUser = MWEchoNotifUser::newFromUser( $user );
|
|
|
|
// Always get total count
|
|
|
|
$rawCount = $notifUser->getNotificationCount();
|
|
|
|
$result['rawcount'] = $rawCount;
|
|
|
|
$result['count'] = EchoNotificationController::formatNotificationCount( $rawCount );
|
|
|
|
|
|
|
|
if ( $groupBySection ) {
|
|
|
|
foreach ( $sections as $section ) {
|
|
|
|
$rawCount = $notifUser->getNotificationCount( /* $tryCache = */true, DB_SLAVE, $section );
|
|
|
|
$result[$section]['rawcount'] = $rawCount;
|
|
|
|
$result[$section]['count'] = EchoNotificationController::formatNotificationCount( $rawCount );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2014-07-30 22:09:22 +00:00
|
|
|
/**
|
|
|
|
* Internal helper method for getting property 'index' data
|
2014-08-05 21:50:54 +00:00
|
|
|
* @param array $list
|
|
|
|
* @return array
|
2014-07-30 22:09:22 +00:00
|
|
|
*/
|
|
|
|
protected function getPropIndex( $list ) {
|
|
|
|
$result = array();
|
|
|
|
foreach ( array_keys( $list ) as $key ) {
|
|
|
|
// Don't include the XML tag name ('_element' key)
|
|
|
|
if ( $key != '_element' ) {
|
|
|
|
$result[] = $key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2012-04-27 15:14:24 +00:00
|
|
|
public function getAllowedParams() {
|
2014-08-05 21:50:54 +00:00
|
|
|
$sections = EchoAttributeManager::$sections;
|
|
|
|
$params = array(
|
2012-04-27 15:14:24 +00:00
|
|
|
'prop' => array(
|
|
|
|
ApiBase::PARAM_ISMULTI => true,
|
|
|
|
ApiBase::PARAM_TYPE => array(
|
2012-08-31 21:50:46 +00:00
|
|
|
'list',
|
|
|
|
'count',
|
|
|
|
'index',
|
|
|
|
),
|
2012-04-27 15:14:24 +00:00
|
|
|
ApiBase::PARAM_DFLT => 'list',
|
|
|
|
),
|
2014-08-05 21:50:54 +00:00
|
|
|
'sections' => array(
|
|
|
|
ApiBase::PARAM_DFLT => implode( '|', $sections ),
|
|
|
|
ApiBase::PARAM_TYPE => $sections,
|
|
|
|
ApiBase::PARAM_ISMULTI => true,
|
|
|
|
),
|
2014-08-14 00:01:35 +00:00
|
|
|
'groupbysection' => array(
|
|
|
|
ApiBase::PARAM_TYPE => 'boolean',
|
|
|
|
ApiBase::PARAM_DFLT => false,
|
|
|
|
),
|
2012-04-27 15:14:24 +00:00
|
|
|
'format' => array(
|
|
|
|
ApiBase::PARAM_TYPE => array(
|
2012-08-31 21:50:46 +00:00
|
|
|
'text',
|
2013-01-07 22:44:58 +00:00
|
|
|
'flyout',
|
2012-08-31 21:50:46 +00:00
|
|
|
'html',
|
|
|
|
),
|
2012-04-27 15:14:24 +00:00
|
|
|
),
|
2012-08-01 19:53:05 +00:00
|
|
|
'limit' => array(
|
2013-05-02 17:56:46 +00:00
|
|
|
ApiBase::PARAM_TYPE => 'limit',
|
2012-08-01 19:53:05 +00:00
|
|
|
ApiBase::PARAM_DFLT => 20,
|
|
|
|
ApiBase::PARAM_MIN => 1,
|
2013-05-02 17:56:46 +00:00
|
|
|
ApiBase::PARAM_MAX => ApiBase::LIMIT_SML1,
|
|
|
|
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_SML2,
|
2012-08-01 19:53:05 +00:00
|
|
|
),
|
2012-06-01 10:57:09 +00:00
|
|
|
'index' => false,
|
2014-10-28 19:42:41 +00:00
|
|
|
'continue' => array(
|
|
|
|
/** @todo Once support for MediaWiki < 1.25 is dropped, just use ApiBase::PARAM_HELP_MSG directly */
|
|
|
|
constant( 'ApiBase::PARAM_HELP_MSG' ) ?: '' => 'api-help-param-continue',
|
|
|
|
),
|
2012-04-27 15:14:24 +00:00
|
|
|
);
|
2014-08-05 21:50:54 +00:00
|
|
|
foreach ( $sections as $section ) {
|
|
|
|
$params[$section . 'continue'] = null;
|
2014-08-14 00:01:35 +00:00
|
|
|
$params[$section . 'unreadfirst'] = array(
|
|
|
|
ApiBase::PARAM_TYPE => 'boolean',
|
|
|
|
ApiBase::PARAM_DFLT => false,
|
|
|
|
);
|
2014-08-05 21:50:54 +00:00
|
|
|
}
|
|
|
|
return $params;
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 19:42:41 +00:00
|
|
|
/**
|
|
|
|
* @deprecated since MediaWiki core 1.25
|
|
|
|
*/
|
2012-04-27 15:14:24 +00:00
|
|
|
public function getParamDescription() {
|
|
|
|
return array(
|
2012-06-01 10:57:09 +00:00
|
|
|
'prop' => 'Details to request.',
|
2014-08-05 21:50:54 +00:00
|
|
|
'sections' => 'The notification sections to query.',
|
|
|
|
'groupbysection' => 'Whether to group the result by section, each section is fetched separately if set',
|
2012-06-01 10:57:09 +00:00
|
|
|
'format' => 'If specified, notifications will be returned formatted this way.',
|
|
|
|
'index' => 'If specified, a list of notification IDs, in order, will be returned.',
|
2012-12-07 01:08:33 +00:00
|
|
|
'limit' => 'The maximum number of notifications to return.',
|
2014-08-05 21:50:54 +00:00
|
|
|
'continue' => 'When more results are available, use this to continue, this is used only when groupbysection is not set.',
|
|
|
|
'alertcontinue' => 'When more alert results are available, use this to continue.',
|
|
|
|
'messagecontinue' => 'When more message results are available, use this to continue.',
|
2014-08-14 00:01:35 +00:00
|
|
|
'alertunreadfirst' => 'Whether to show unread message notifications first',
|
|
|
|
'messageunreadfirst' => 'Whether to show unread alert notifications first'
|
2012-04-27 15:14:24 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-10-28 19:42:41 +00:00
|
|
|
/**
|
|
|
|
* @deprecated since MediaWiki core 1.25
|
|
|
|
*/
|
2012-04-27 15:14:24 +00:00
|
|
|
public function getDescription() {
|
|
|
|
return 'Get notifications waiting for the current user';
|
|
|
|
}
|
|
|
|
|
2014-10-28 19:42:41 +00:00
|
|
|
/**
|
|
|
|
* @deprecated since MediaWiki core 1.25
|
|
|
|
*/
|
2012-04-27 15:14:24 +00:00
|
|
|
public function getExamples() {
|
|
|
|
return array(
|
|
|
|
'api.php?action=query&meta=notifications',
|
2014-08-05 21:50:54 +00:00
|
|
|
'api.php?action=query&meta=notifications¬prop=count¬sections=alert|message¬groupbysection=1',
|
2012-04-27 15:14:24 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-10-28 19:42:41 +00:00
|
|
|
/**
|
|
|
|
* @see ApiBase::getExamplesMessages()
|
|
|
|
*/
|
|
|
|
protected function getExamplesMessages() {
|
|
|
|
return array(
|
|
|
|
'action=query&meta=notifications'
|
|
|
|
=> 'apihelp-query+notifications-example-1',
|
|
|
|
'action=query&meta=notifications¬prop=count¬sections=alert|message¬groupbysection=1'
|
|
|
|
=> 'apihelp-query+notifications-example-2',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-04-27 15:14:24 +00:00
|
|
|
public function getHelpUrls() {
|
2014-08-14 21:33:23 +00:00
|
|
|
return 'https://www.mediawiki.org/wiki/Echo_(Notifications)/API';
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
2012-07-26 17:23:18 +00:00
|
|
|
}
|