mediawiki-extensions-Echo/api/ApiEchoNotifications.php
bsitu c130197682 Add extra security check to Echo API to prevent vandalism
1. Only trigger mark as read if the unread notification count is > 0
1. Add a limit to the number of notification that can be marked as read
2. Only update those records with read_timestamp = null

Change-Id: I12456c504787f45f594ef9283e98d98692956935
2013-05-04 19:58:37 -07:00

240 lines
7.1 KiB
PHP

<?php
class ApiEchoNotifications extends ApiQueryBase {
public function __construct( $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'not' );
}
public function execute() {
$user = $this->getUser();
if ( $user->isAnon() ) {
$this->dieUsage( 'Login is required', 'login-required' );
}
$params = $this->extractRequestParams();
// There is no need to trigger markRead if all notifications are read
if ( EchoNotificationController::getNotificationCount( $user ) > 0 ) {
if ( count( $params['markread'] ) ) {
// Make sure there is a limit to the update
EchoNotificationController::markRead( $user, array_slice( $params['markread'], 0, ApiBase::LIMIT_SML2 ) );
} elseif ( $params['markallread'] ) {
EchoNotificationController::markAllRead( $user );
}
}
$prop = $params['prop'];
$result = array();
if ( in_array( 'list', $prop ) ) {
$result['list'] = self::getNotifications( $user, $params['format'], $params['limit'] + 1, $params['timestamp'], $params['offset'] );
// check if there is more elements than we request
if ( count( $result['list'] ) > $params['limit'] ) {
array_pop( $result['list'] );
$result['more'] = '1';
} else {
$result['more'] = '0';
}
$this->getResult()->setIndexedTagName( $result['list'], 'notification' );
}
if ( in_array( 'count', $prop ) ) {
$result['count'] = EchoNotificationController::getFormattedNotificationCount( $user );
}
if ( in_array( 'index', $prop ) ) {
$result['index'] = array();
foreach ( array_keys( $result['list'] ) as $key ) {
// Don't include the XML tag name ('_element' key)
if ( $key != '_element' ) {
$result['index'][] = $key;
}
}
$this->getResult()->setIndexedTagName( $result['index'], 'id' );
}
$this->getResult()->setIndexedTagName( $result, 'notification' );
$this->getResult()->addValue( 'query', $this->getModuleName(), $result );
}
/**
* Get a list of notifications based on the passed parameters
*
* @param $user User the user to get notifications for
* @param $format string/bool false to not format any notifications, string to a specific output format
* @param $limit int The maximum number of notifications to return
* @param $timestamp int The timestamp to start from
* @param $offset int The notification event id to start from
* @return array
*/
public static function getNotifications( $user, $format = false, $limit = 20, $timestamp = 0, $offset = 0 ) {
global $wgEchoBackend;
$output = array();
// TODO: Make 'web' based on a new API param?
$res = $wgEchoBackend->loadNotifications( $user, $limit, $timestamp, $offset, 'web' );
foreach ( $res as $row ) {
$event = EchoEvent::newFromRow( $row );
if ( $row->notification_bundle_base && $row->notification_bundle_display_hash ) {
$event->setBundleHash( $row->notification_bundle_display_hash );
}
$timestamp = new MWTimestamp( $row->notification_timestamp );
$timestampUnix = $timestamp->getTimestamp( TS_UNIX );
$timestampMw = $timestamp->getTimestamp( TS_MW );
// start creating date section header
$today = wfTimestamp( TS_MW );
$yesterday = wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $today ) - 24 * 3600 );
if ( substr( $today, 4, 4 ) === substr( $timestampMw, 4, 4 ) ) {
$date = wfMessage( 'echo-date-today' )->escaped();
} elseif ( substr( $yesterday, 4, 4 ) === substr( $timestampMw, 4, 4 ) ) {
$date = wfMessage( 'echo-date-yesterday' )->escaped();
} else {
$month = array(
'01' => 'january-gen',
'02' => 'february-gen',
'03' => 'march-gen',
'04' => 'april-gen',
'05' => 'may-gen',
'06' => 'june-gen',
'07' => 'july-gen',
'08' => 'august-gen',
'09' => 'september-gen',
'10' => 'october-gen',
'11' => 'november-gen',
'12' => 'december-gen'
);
$headerMonth = wfMessage( $month[substr( $timestampMw, 4, 2 )] )->text();
$headerDate = substr( $timestampMw, 6, 2 );
$date = wfMessage( 'echo-date-header' )->params( $headerMonth )->numParams( $headerDate )->escaped();
}
// end creating date section header
$thisEvent = array(
'id' => $event->getId(),
'type' => $event->getType(),
'category' => $event->getCategory(),
'timestamp' => array(
'unix' => $timestampUnix,
'mw' => $timestampMw,
'date' => $date
),
);
if ( $event->getVariant() ) {
$thisEvent['variant'] = $event->getVariant();
}
if ( $event->getTitle() ) {
$thisEvent['title'] = array(
'full' => $event->getTitle()->getPrefixedText(),
'namespace' => $event->getTitle()->getNSText(),
'namespace-key' => $event->getTitle()->getNamespace(),
'text' => $event->getTitle()->getText(),
);
}
if ( $event->getAgent() ) {
$thisEvent['agent'] = array(
'id' => $event->getAgent()->getId(),
'name' => $event->getAgent()->getName(),
);
}
if ( $row->notification_read_timestamp ) {
$thisEvent['read'] = $row->notification_read_timestamp;
}
if ( $format ) {
$thisEvent['*'] = EchoNotificationController::formatNotification(
$event, $user, $format );
}
$output[$event->getID()] = $thisEvent;
}
return $output;
}
public function getAllowedParams() {
return array(
'prop' => array(
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => array(
'list',
'count',
'index',
),
ApiBase::PARAM_DFLT => 'list',
),
'markread' => array(
ApiBase::PARAM_ISMULTI => true,
),
'markallread' => array(
ApiBase::PARAM_REQUIRED => false,
ApiBase::PARAM_TYPE => 'boolean'
),
'format' => array(
ApiBase::PARAM_TYPE => array(
'text',
'flyout',
'html',
),
),
'limit' => array(
ApiBase::PARAM_TYPE => 'limit',
ApiBase::PARAM_DFLT => 20,
ApiBase::PARAM_MIN => 1,
ApiBase::PARAM_MAX => ApiBase::LIMIT_SML1,
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_SML2,
),
'index' => false,
'offset' => array(
ApiBase::PARAM_TYPE => 'integer',
),
'timestamp' => array(
ApiBase::PARAM_TYPE => 'integer',
),
);
}
public function getParamDescription() {
return array(
'prop' => 'Details to request.',
'markread' => 'A list of notification IDs to mark as read',
'markallread' => "If set to true, marks all of a user's notifications as read",
'format' => 'If specified, notifications will be returned formatted this way.',
'index' => 'If specified, a list of notification IDs, in order, will be returned.',
'limit' => 'The maximum number of notifications to return.',
'offset' => 'Notification event id to start from (requires timestamp param to be passed as well)',
'timestamp' => 'Timestamp to start from',
);
}
public function getDescription() {
return 'Get notifications waiting for the current user';
}
public function getExamples() {
return array(
'api.php?action=query&meta=notifications',
'api.php?action=query&meta=notifications&notprop=count',
'api.php?action=query&meta=notifications&notmarkread=8',
);
}
public function getHelpUrls() {
return 'https://www.mediawiki.org/wiki/Echo_(notifications)/API';
}
public function getVersion() {
return __CLASS__ . '-0.1';
}
}