Separate 'seen time' for alerts and messages

Bug: T111285
Change-Id: I277f94ae705d3323ac8612111d7fd704b36793cb
This commit is contained in:
Moriel Schottlender 2015-09-02 18:11:10 -07:00
parent e6e507a9ee
commit e650df6644
6 changed files with 68 additions and 26 deletions

View file

@ -638,8 +638,13 @@ class EchoHooks {
$msgNotificationTimestamp = $notifUser->getLastUnreadMessageTime();
$alertNotificationTimestamp = $notifUser->getLastUnreadAlertTime();
$seenTime = EchoSeenTime::newFromUser( $user )->getTime();
$sk->getOutput()->addJsConfigVars( 'wgEchoSeenTime', $seenTime );
$seenAlertTime = EchoSeenTime::newFromUser( $user )->getTime( 'alert' );
$seenMsgTime = EchoSeenTime::newFromUser( $user )->getTime( 'message' );
$sk->getOutput()->addJsConfigVars( 'wgEchoSeenTime', array(
'alert' => $seenAlertTime,
'message' => $seenMsgTime
) );
$msgText = EchoNotificationController::formatNotificationCount( $msgCount );
$alertText = EchoNotificationController::formatNotificationCount( $alertCount );
@ -652,7 +657,7 @@ class EchoHooks {
if (
$msgCount != 0 && // no unread notifications
$msgNotificationTimestamp !== false && // should already always be false if count === 0
( $seenTime === null || $seenTime < $msgNotificationTimestamp->getTimestamp( TS_MW ) ) // there are no unseen notifications
( $seenMsgTime === null || $seenMsgTime < $msgNotificationTimestamp->getTimestamp( TS_MW ) ) // there are no unseen notifications
) {
$msgLinkClasses[] = 'mw-echo-unseen-notifications';
}
@ -661,7 +666,7 @@ class EchoHooks {
if (
$alertCount != 0 && // no unread notifications
$alertNotificationTimestamp !== false && // should already always be false if count === 0
( $seenTime === null || $seenTime < $alertNotificationTimestamp->getTimestamp( TS_MW ) ) // all notifications have already been seen
( $seenAlertTime === null || $seenAlertTime < $alertNotificationTimestamp->getTimestamp( TS_MW ) ) // all notifications have already been seen
) {
$alertLinkClasses[] = 'mw-echo-unseen-notifications';
$alertIcon = "bellOn";

View file

@ -121,7 +121,8 @@
"apihelp-echomarkread-example-1": "Mark notification 8 as read",
"apihelp-echomarkread-example-2": "Mark all notifications as read",
"apihelp-echomarkseen-description": "Mark notifications as seen for the current user.",
"apihelp-echomarkseen-example-1": "Mark notifications as seen",
"apihelp-echomarkseen-example-1": "Mark notifications of all types as seen",
"apihelp-echomarkseen-param-type": "Type of notifications to mark as seen: 'alert', 'message' or 'all'.",
"apihelp-query+notifications-description": "Get notifications waiting for the current user.",
"apihelp-query+notifications-param-prop": "Details to request.",
"apihelp-query+notifications-param-sections": "The notification sections to query.",

View file

@ -142,6 +142,7 @@
"apihelp-echomarkread-example-1": "{{doc-apihelp-example|echomarkread}}",
"apihelp-echomarkread-example-2": "{{doc-apihelp-example|echomarkread}}",
"apihelp-echomarkseen-description": "{{doc-apihelp-description|echomarkseen}}",
"apihelp-echomarkseen-param-type": "{{doc-apihelp-param|query+notifications|type}}",
"apihelp-echomarkseen-example-1": "{{doc-apihelp-example|echomarkseen}}",
"apihelp-query+notifications-description": "{{doc-apihelp-description|query+notifications}}",
"apihelp-query+notifications-param-prop": "{{doc-apihelp-param|query+notifications|prop}}",

View file

@ -6,16 +6,17 @@
*/
class EchoSeenTime {
/**
* Allowed notification types
* @var array
*/
private static $allowedTypes = array( 'alert', 'message' );
/**
* @var User
*/
private $user;
/**
* @var string
*/
private $key;
/**
* @var BagOStuff
*/
@ -26,7 +27,6 @@ class EchoSeenTime {
*/
private function __construct( User $user ) {
$this->user = $user;
$this->key = wfMemcKey( 'echo', 'seen', 'time', $user->getId() );
$this->cache = ObjectCache::getInstance( 'db-replicated' );
}
@ -42,18 +42,48 @@ class EchoSeenTime {
* @param int $flags BagOStuff::READ_LATEST to use the master
* @return string|bool false if no stored time
*/
public function getTime( $flags = 0 ) {
$cas = 0; // Unused, but we have to pass something by reference
$data = $this->cache->get( $this->key, $cas, $flags );
if ( $data === false ) {
// Check if the user still has it set in their preferences
$data = $this->user->getOption( 'echo-seen-time', false );
public function getTime( $type = 'all', $flags = 0 ) {
$vals = array();
if ( $type === 'all' ) {
foreach ( self::$allowedTypes as $allowed ) {
$vals[] = $this->getTime( $allowed );
}
return max( $vals );
}
if ( $this->validateType( $type ) ) {
$key = wfMemcKey( 'echo', 'seen', $type, 'time', $this->user->getId() );
$cas = 0; // Unused, but we have to pass something by reference
$data = $this->cache->get( $key, $cas, $flags );
if ( $data === false ) {
// Check if the user still has it set in their preferences
$data = $this->user->getOption( 'echo-seen-time', false );
}
}
return $data;
}
public function setTime( $time ) {
return $this->cache->set( $this->key, $time );
public function setTime( $time, $type = 'all' ) {
if ( $type === 'all' ) {
foreach ( self::$allowedTypes as $allowed ) {
$this->setTime( $time, $allowed );
}
} else {
if ( $this->validateType( $type ) ) {
$key = wfMemcKey( 'echo', 'seen', $type, 'time', $this->user->getId() );
return $this->cache->set( $key, $time );
}
}
}
/**
* Validate the given type, make sure it is allowed.
*
* @param string $type Given type
* @return bool Type is allowed
*/
private function validateType( $type ) {
return in_array( $type, self::$allowedTypes );
}
}

View file

@ -11,9 +11,10 @@ class ApiEchoMarkSeen extends ApiBase {
$this->dieUsage( 'Login is required', 'login-required' );
}
$params = $this->extractRequestParams();
$timestamp = wfTimestamp( TS_MW );
$seenTime = EchoSeenTime::newFromUser( $user );
$seenTime->setTime( $timestamp );
$seenTime->setTime( $timestamp, $params['type'] );
$this->getResult()->addValue( 'query', $this->getModuleName(), array(
'result' => 'success',
@ -26,6 +27,10 @@ class ApiEchoMarkSeen extends ApiBase {
'token' => array(
ApiBase::PARAM_REQUIRED => true,
),
'type' => array(
ApiBase::PARAM_REQUIRED => true,
ApiBase::PARAM_TYPE => array( 'alert', 'message', 'all' ),
)
);
}
@ -75,7 +80,7 @@ class ApiEchoMarkSeen extends ApiBase {
*/
protected function getExamplesMessages() {
return array(
'action=echomarkseen' => 'apihelp-echomarkseen-example-1',
'action=echomarkseen&type=all' => 'apihelp-echomarkseen-example-1',
);
}

View file

@ -152,7 +152,7 @@
* @param {string} Mediawiki seen timestamp in Mediawiki timestamp format
*/
mw.echo.dm.NotificationsModel.prototype.setSeenTime = function ( time ) {
this.seenTime = time;
this.seenTime[this.type] = time;
};
/**
@ -161,7 +161,7 @@
* @return {string} Mediawiki seen timestamp in Mediawiki timestamp format
*/
mw.echo.dm.NotificationsModel.prototype.getSeenTime = function () {
return this.seenTime;
return this.seenTime[this.type];
};
/**
@ -183,7 +183,8 @@
var model = this;
return this.api.postWithToken( 'edit', {
action: 'echomarkseen'
action: 'echomarkseen',
type: this.type
} ).then( function ( data ) {
var i, len,
items = model.unseenNotifications.getItems(),
@ -191,7 +192,6 @@
// update wgEchoSeenTime value in JS (where it wouldn't
// otherwise propagate until page reload)
mw.config.set( 'wgEchoSeenTime', time );
model.setSeenTime( time );
// Update the notifications seen status
@ -200,7 +200,7 @@
}
model.unseenNotifications.clearItems();
model.emit( 'updateSeenTime' );
model.emit( 'updateSeenTime', model.getSeenTime() );
} );
};