2013-05-24 22:51:47 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Entity that represents a notification target user
|
|
|
|
*/
|
|
|
|
class MWEchoNotifUser {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification target user
|
|
|
|
* @var User
|
|
|
|
*/
|
|
|
|
private $mUser;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Object cache
|
|
|
|
* @var BagOStuff
|
|
|
|
*/
|
|
|
|
private $cache;
|
|
|
|
|
|
|
|
/**
|
2014-07-18 03:58:21 +00:00
|
|
|
* Database access gateway
|
|
|
|
* @var EchoUserNotificationGateway
|
2013-05-24 22:51:47 +00:00
|
|
|
*/
|
2014-07-18 03:58:21 +00:00
|
|
|
private $userNotifGateway;
|
2013-05-24 22:51:47 +00:00
|
|
|
|
2014-08-13 22:00:25 +00:00
|
|
|
/**
|
|
|
|
* Notification mapper
|
|
|
|
* @var EchoNotificationMapper
|
|
|
|
*/
|
|
|
|
private $notifMapper;
|
|
|
|
|
2014-08-07 00:07:34 +00:00
|
|
|
/**
|
|
|
|
* Target page mapper
|
|
|
|
* @var EchoTargetPageMapper
|
|
|
|
*/
|
|
|
|
private $targetPageMapper;
|
|
|
|
|
2015-11-25 04:07:54 +00:00
|
|
|
/**
|
|
|
|
* @var EchoForeignNotifications
|
|
|
|
*/
|
|
|
|
private $foreignNotifications;
|
|
|
|
|
2013-05-24 22:51:47 +00:00
|
|
|
/**
|
2014-08-13 22:00:25 +00:00
|
|
|
* Usually client code doesn't need to initialize the object directly
|
|
|
|
* because it could be obtained from factory method newFromUser()
|
2014-08-07 00:07:34 +00:00
|
|
|
* @param User $user
|
|
|
|
* @param BagOStuff $cache
|
|
|
|
* @param EchoUserNotificationGateway $userNotifGateway
|
|
|
|
* @param EchoNotificationMapper $notifMapper
|
|
|
|
* @param EchoTargetPageMapper $targetPageMapper
|
2013-05-24 22:51:47 +00:00
|
|
|
*/
|
2014-08-13 22:00:25 +00:00
|
|
|
public function __construct(
|
|
|
|
User $user,
|
|
|
|
BagOStuff $cache,
|
|
|
|
EchoUserNotificationGateway $userNotifGateway,
|
2014-08-07 00:07:34 +00:00
|
|
|
EchoNotificationMapper $notifMapper,
|
|
|
|
EchoTargetPageMapper $targetPageMapper
|
2014-08-13 22:00:25 +00:00
|
|
|
) {
|
2013-05-24 22:51:47 +00:00
|
|
|
$this->mUser = $user;
|
2014-07-18 03:58:21 +00:00
|
|
|
$this->userNotifGateway = $userNotifGateway;
|
|
|
|
$this->cache = $cache;
|
2014-08-13 22:00:25 +00:00
|
|
|
$this->notifMapper = $notifMapper;
|
2014-08-07 00:07:34 +00:00
|
|
|
$this->targetPageMapper = $targetPageMapper;
|
2015-11-25 04:07:54 +00:00
|
|
|
$this->foreignNotifications = new EchoForeignNotifications( $user );
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Factory method
|
|
|
|
* @param $user User
|
|
|
|
* @throws MWException
|
|
|
|
* @return MWEchoNotifUser
|
|
|
|
*/
|
|
|
|
public static function newFromUser( User $user ) {
|
|
|
|
if ( $user->isAnon() ) {
|
|
|
|
throw new MWException( 'User must be logged in to view notification!' );
|
|
|
|
}
|
2014-07-18 03:58:21 +00:00
|
|
|
global $wgMemc;
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-07-18 03:58:21 +00:00
|
|
|
return new MWEchoNotifUser(
|
|
|
|
$user, $wgMemc,
|
2014-08-13 22:00:25 +00:00
|
|
|
new EchoUserNotificationGateway( $user, MWEchoDbFactory::newFromDefault() ),
|
2014-08-07 00:07:34 +00:00
|
|
|
new EchoNotificationMapper(),
|
|
|
|
new EchoTargetPageMapper()
|
2014-07-18 03:58:21 +00:00
|
|
|
);
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clear talk page notification when users visit their talk pages. This
|
|
|
|
* only resets if the notification count is less than max notification
|
|
|
|
* count. If the user has 99+ notifications, decrementing 1 bundled talk
|
|
|
|
* page notification would not really affect the count
|
|
|
|
*/
|
|
|
|
public function clearTalkNotification() {
|
|
|
|
// There is no new talk notification
|
|
|
|
if ( $this->cache->get( $this->getTalkNotificationCacheKey() ) === '0' ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do nothing if the count display meets the max 99+
|
|
|
|
if ( $this->notifCountHasReachedMax() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark the talk page notification as read
|
|
|
|
$this->markRead(
|
2014-07-18 03:58:21 +00:00
|
|
|
$this->userNotifGateway->getUnreadNotifications(
|
2013-05-24 22:51:47 +00:00
|
|
|
'edit-user-talk'
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
$this->flagCacheWithNoTalkNotification();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Flag the cache with new talk notification
|
|
|
|
*/
|
|
|
|
public function flagCacheWithNewTalkNotification() {
|
|
|
|
$this->cache->set( $this->getTalkNotificationCacheKey(), '1', 86400 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Flag the cache with no talk notification
|
|
|
|
*/
|
|
|
|
public function flagCacheWithNoTalkNotification() {
|
|
|
|
$this->cache->set( $this->getTalkNotificationCacheKey(), '0', 86400 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Memcache key for talk notification
|
|
|
|
*/
|
|
|
|
public function getTalkNotificationCacheKey() {
|
|
|
|
global $wgEchoConfig;
|
|
|
|
|
|
|
|
return wfMemcKey( 'echo-new-talk-notification', $this->mUser->getId(), $wgEchoConfig['version'] );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the user has more notification count than max count display
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function notifCountHasReachedMax() {
|
|
|
|
global $wgEchoMaxNotificationCount;
|
|
|
|
|
|
|
|
if ( $this->getNotificationCount() > $wgEchoMaxNotificationCount ) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-13 00:54:16 +00:00
|
|
|
/**
|
|
|
|
* Get message count for this user.
|
|
|
|
*
|
|
|
|
* @param boolean $cached Set to false to bypass the cache. (Optional. Defaults to true)
|
|
|
|
* @param int $dbSource Use master or slave database to pull count (Optional. Defaults to DB_SLAVE)
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getMessageCount( $cached = true, $dbSource = DB_SLAVE ) {
|
2015-11-25 04:07:54 +00:00
|
|
|
$count = $this->getNotificationCount( $cached, $dbSource, EchoAttributeManager::MESSAGE );
|
|
|
|
$count += $this->foreignNotifications->getCount( EchoAttributeManager::MESSAGE );
|
|
|
|
|
|
|
|
return $count;
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get alert count for this user.
|
|
|
|
*
|
|
|
|
* @param boolean $cached Set to false to bypass the cache. (Optional. Defaults to true)
|
|
|
|
* @param int $dbSource Use master or slave database to pull count (Optional. Defaults to DB_SLAVE)
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
public function getAlertCount( $cached = true, $dbSource = DB_SLAVE ) {
|
2015-11-25 04:07:54 +00:00
|
|
|
$count = $this->getNotificationCount( $cached, $dbSource, EchoAttributeManager::ALERT );
|
|
|
|
$count += $this->foreignNotifications->getCount( EchoAttributeManager::ALERT );
|
|
|
|
|
|
|
|
return $count;
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the memcache key for 'has ever had messages' value
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
private function getHasMessagesKey() {
|
|
|
|
global $wgEchoConfig;
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2016-01-25 15:33:06 +00:00
|
|
|
$lookup = CentralIdLookup::factory();
|
|
|
|
$id = $lookup->centralIdFromLocalUser( $this->mUser, CentralIdLookup::AUDIENCE_RAW );
|
|
|
|
if ( !$id ) {
|
|
|
|
// local user
|
|
|
|
return wfMemcKey( 'echo', 'user', 'had', 'messages', $this->mUser->getId(), $wgEchoConfig['version'] );
|
|
|
|
} else {
|
|
|
|
// central user: we don't want a per-wiki cache key: as soon as the user
|
|
|
|
// gets a message on another wiki, this cache key should be altered
|
|
|
|
return wfGlobalCacheKey( 'echo', 'user', 'had', 'messages', $id, $wgEchoConfig['version'] );
|
|
|
|
}
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check whether the user has ever had messages.
|
|
|
|
*
|
|
|
|
* @return boolean User has received messages
|
|
|
|
*/
|
2016-02-19 13:55:08 +00:00
|
|
|
public function hasMessages() {
|
2015-08-13 00:54:16 +00:00
|
|
|
$section = EchoAttributeManager::MESSAGE;
|
|
|
|
|
2016-02-19 13:55:08 +00:00
|
|
|
/*
|
|
|
|
* This is a temp "hack" for as long as cross-wiki is in beta. The "real
|
|
|
|
* data" stored to cache should be global, so a change in a wiki where
|
|
|
|
* cross-wiki is disabled is still visible in wikis where it is enabled.
|
|
|
|
* So if cross-wiki is disabled, we can't trust/use the result that is
|
|
|
|
* in getHasMessagesKey.
|
|
|
|
*/
|
|
|
|
if ( !$this->mUser->getOption( 'echo-cross-wiki-notifications' ) ) {
|
|
|
|
global $wgEchoConfig;
|
|
|
|
// key is the same as getHasMessagesKey's single-user case, which is
|
|
|
|
// ok (if there's no centralized user, there'll only be local data
|
|
|
|
// anyway - same as when cross-wiki is disabled)
|
|
|
|
$memcKey = wfMemcKey( 'echo', 'user', 'had', 'messages', $this->mUser->getId(), $wgEchoConfig['version'] );
|
2015-08-13 00:54:16 +00:00
|
|
|
$data = $this->cache->get( $memcKey );
|
|
|
|
if ( $data !== false && $data !== null ) {
|
2016-02-19 13:55:08 +00:00
|
|
|
return $data;
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
2016-02-19 13:55:08 +00:00
|
|
|
|
|
|
|
$result = $this->hasLocal( $section );
|
|
|
|
$this->cache->set( $memcKey, $result, 86400 );
|
|
|
|
|
|
|
|
return $result;
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
2016-02-19 13:55:08 +00:00
|
|
|
$memcKey = $this->getHasMessagesKey();
|
|
|
|
$data = $this->cache->get( $memcKey );
|
|
|
|
if ( $data !== false && $data !== null ) {
|
|
|
|
return (bool) $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
$result = $this->hasGlobal( $section );
|
2015-08-13 00:54:16 +00:00
|
|
|
$this->cache->set( $memcKey, $result, 86400 );
|
|
|
|
|
2016-02-19 13:55:08 +00:00
|
|
|
return $result;
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
2016-02-19 13:55:08 +00:00
|
|
|
/**
|
|
|
|
* Check if user has ever had alerts/messages on this local wiki.
|
|
|
|
*
|
|
|
|
* @param string $section
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
protected function hasLocal( $section ) {
|
|
|
|
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
|
|
|
$eventTypesToLoad = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', array( $section ) );
|
|
|
|
$count = count( $this->notifMapper->fetchByUser( $this->mUser, 1, 0, $eventTypesToLoad ) );
|
2016-01-25 15:33:06 +00:00
|
|
|
|
2016-02-19 13:55:08 +00:00
|
|
|
return $count > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if user has ever had alerts/messages on any wiki (local & foreign).
|
|
|
|
*
|
|
|
|
* @param string $section
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
protected function hasGlobal( $section ) {
|
2016-01-25 15:33:06 +00:00
|
|
|
$uw = EchoUnreadWikis::newFromUser( $this->mUser );
|
|
|
|
if ( $uw === false ) {
|
2016-02-19 13:55:08 +00:00
|
|
|
// there is no centralized user, fall back to checking local wiki
|
|
|
|
return $this->hasLocal( $section );
|
2016-01-25 15:33:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$counts = $uw->getUnreadCounts();
|
|
|
|
foreach ( $counts as $wiki => $data ) {
|
2016-02-19 13:55:08 +00:00
|
|
|
if ( $data[$section]['count'] > 0 ) {
|
2016-01-25 15:33:06 +00:00
|
|
|
// currently has unread notifications
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-19 13:55:08 +00:00
|
|
|
if ( $data[$section]['ts'] !== EchoUnreadWikis::DEFAULT_TS ) {
|
2016-01-25 15:33:06 +00:00
|
|
|
// a timestamp at which notifications were read was recorded,
|
|
|
|
// which means the user must've had messages somewhere, at some point
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-13 00:54:16 +00:00
|
|
|
/**
|
|
|
|
* Cache the fact that the user has messages.
|
|
|
|
* This is used after the user receives a message, making the system skip the actual test
|
|
|
|
* of whether they have messages against the database at all.
|
|
|
|
*/
|
|
|
|
public function cacheHasMessages() {
|
2015-09-04 00:30:01 +00:00
|
|
|
$this->cache->set( $this->getHasMessagesKey(), 1, 86400 );
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
2013-05-24 22:51:47 +00:00
|
|
|
/**
|
|
|
|
* Retrieves number of unread notifications that a user has, would return
|
|
|
|
* $wgEchoMaxNotificationCount + 1 at most
|
|
|
|
*
|
2015-08-13 00:54:16 +00:00
|
|
|
* @param boolean $cached Set to false to bypass the cache. (Optional. Defaults to true)
|
|
|
|
* @param int $dbSource Use master or slave database to pull count (Optional. Defaults to DB_SLAVE)
|
2014-08-05 21:50:54 +00:00
|
|
|
* @param string $section Notification section
|
|
|
|
* @return int
|
2013-05-24 22:51:47 +00:00
|
|
|
*/
|
2014-08-05 21:50:54 +00:00
|
|
|
public function getNotificationCount( $cached = true, $dbSource = DB_SLAVE, $section = EchoAttributeManager::ALL ) {
|
2013-05-24 22:51:47 +00:00
|
|
|
global $wgEchoConfig;
|
|
|
|
|
|
|
|
if ( $this->mUser->isAnon() ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
$memcKey = wfMemcKey(
|
|
|
|
'echo-notification-count' . ( $section === EchoAttributeManager::ALL ? '' : ( '-' . $section ) ),
|
|
|
|
$this->mUser->getId(),
|
|
|
|
$wgEchoConfig['version']
|
|
|
|
);
|
2015-07-21 21:19:12 +00:00
|
|
|
if ( $cached ) {
|
|
|
|
$data = $this->cache->get( $memcKey );
|
2015-08-13 00:54:16 +00:00
|
|
|
if ( $data !== false && $data !== null ) {
|
2015-07-21 21:19:12 +00:00
|
|
|
return (int)$data;
|
|
|
|
}
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
2014-08-05 21:50:54 +00:00
|
|
|
if ( $section === EchoAttributeManager::ALL ) {
|
|
|
|
$eventTypesToLoad = $attributeManager->getUserEnabledEvents( $this->mUser, 'web' );
|
|
|
|
} else {
|
|
|
|
$eventTypesToLoad = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', array( $section ) );
|
|
|
|
}
|
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
$count = $this->userNotifGateway->getNotificationCount( $dbSource, $eventTypesToLoad );
|
2013-05-24 22:51:47 +00:00
|
|
|
$this->cache->set( $memcKey, $count, 86400 );
|
|
|
|
|
|
|
|
return (int)$count;
|
|
|
|
}
|
|
|
|
|
2015-08-13 00:54:16 +00:00
|
|
|
/**
|
|
|
|
* Get the unread timestamp of the latest alert
|
|
|
|
*
|
|
|
|
* @param boolean $cached Set to false to bypass the cache. (Optional. Defaults to true)
|
|
|
|
* @param int $dbSource Use master or slave database to pull count (Optional. Defaults to DB_SLAVE)
|
2015-11-25 04:07:54 +00:00
|
|
|
* @return bool|MWTimestamp
|
2015-08-13 00:54:16 +00:00
|
|
|
*/
|
|
|
|
public function getLastUnreadAlertTime( $cached = true, $dbSource = DB_SLAVE ) {
|
2015-11-25 04:07:54 +00:00
|
|
|
$time = $this->getLastUnreadNotificationTime( $cached, $dbSource, EchoAttributeManager::ALERT );
|
|
|
|
|
|
|
|
$foreignTime = $this->foreignNotifications->getTimestamp( EchoAttributeManager::ALERT );
|
|
|
|
if ( $foreignTime !== false ) {
|
|
|
|
$max = max( $time ? $time->getTimestamp( TS_MW ) : 0, $foreignTime->getTimestamp( TS_MW ) );
|
|
|
|
$time = new MWTimestamp( $max );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $time;
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the unread timestamp of the latest message
|
|
|
|
*
|
|
|
|
* @param boolean $cached Set to false to bypass the cache. (Optional. Defaults to true)
|
|
|
|
* @param int $dbSource Use master or slave database to pull count (Optional. Defaults to DB_SLAVE)
|
2015-11-25 04:07:54 +00:00
|
|
|
* @return bool|MWTimestamp
|
2015-08-13 00:54:16 +00:00
|
|
|
*/
|
|
|
|
public function getLastUnreadMessageTime( $cached = true, $dbSource = DB_SLAVE ) {
|
2015-11-25 04:07:54 +00:00
|
|
|
$time = $this->getLastUnreadNotificationTime( $cached, $dbSource, EchoAttributeManager::MESSAGE );
|
|
|
|
|
|
|
|
$foreignTime = $this->foreignNotifications->getTimestamp( EchoAttributeManager::MESSAGE );
|
|
|
|
if ( $foreignTime !== false ) {
|
|
|
|
$max = max( $time ? $time->getTimestamp( TS_MW ) : 0, $foreignTime->getTimestamp( TS_MW ) );
|
|
|
|
$time = new MWTimestamp( $max );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $time;
|
2015-08-13 00:54:16 +00:00
|
|
|
}
|
|
|
|
|
2015-04-29 12:08:30 +00:00
|
|
|
/**
|
|
|
|
* Returns the timestamp of the last unread notification.
|
|
|
|
*
|
2015-08-13 00:54:16 +00:00
|
|
|
* @param boolean $cached Set to false to bypass the cache. (Optional. Defaults to true)
|
|
|
|
* @param int $dbSource Use master or slave database to pull count (Optional. Defaults to DB_SLAVE)
|
2015-04-29 12:08:30 +00:00
|
|
|
* @param string $section Notification section
|
|
|
|
* @return bool|MWTimestamp Timestamp of last notification, or false if there is none
|
|
|
|
*/
|
2015-05-07 11:58:51 +00:00
|
|
|
public function getLastUnreadNotificationTime( $cached = true, $dbSource = DB_SLAVE, $section = EchoAttributeManager::ALL ) {
|
2015-04-29 12:08:30 +00:00
|
|
|
global $wgEchoConfig;
|
|
|
|
|
|
|
|
if ( $this->mUser->isAnon() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$memcKey = wfMemcKey(
|
|
|
|
'echo-notification-timestamp' . ( $section === EchoAttributeManager::ALL ? '' : ( '-' . $section ) ),
|
|
|
|
$this->mUser->getId(),
|
|
|
|
$wgEchoConfig['version']
|
|
|
|
);
|
|
|
|
|
|
|
|
// read from cache, if allowed
|
|
|
|
if ( $cached ) {
|
|
|
|
$timestamp = $this->cache->get( $memcKey );
|
|
|
|
if ( $timestamp !== false ) {
|
|
|
|
return new MWTimestamp( $timestamp );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
|
|
|
if ( $section === EchoAttributeManager::ALL ) {
|
|
|
|
$eventTypesToLoad = $attributeManager->getUserEnabledEvents( $this->mUser, 'web' );
|
|
|
|
} else {
|
|
|
|
$eventTypesToLoad = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', array( $section ) );
|
|
|
|
}
|
|
|
|
|
2015-12-09 18:41:40 +00:00
|
|
|
$notifications = $this->notifMapper->fetchUnreadByUser( $this->mUser, 1, null, $eventTypesToLoad, $dbSource );
|
2015-04-29 12:08:30 +00:00
|
|
|
if ( $notifications ) {
|
|
|
|
$notification = reset( $notifications );
|
|
|
|
$timestamp = $notification->getTimestamp();
|
|
|
|
|
|
|
|
// store to cache & return
|
2015-10-01 13:48:52 +00:00
|
|
|
$this->cache->set( $memcKey, $timestamp, 86400 );
|
|
|
|
|
2015-04-29 12:08:30 +00:00
|
|
|
return new MWTimestamp( $timestamp );
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-24 22:51:47 +00:00
|
|
|
/**
|
|
|
|
* Mark one or more notifications read for a user.
|
|
|
|
* @param $eventIds Array of event IDs to mark read
|
2014-08-13 22:00:25 +00:00
|
|
|
* @return boolean
|
2013-05-24 22:51:47 +00:00
|
|
|
*/
|
|
|
|
public function markRead( $eventIds ) {
|
|
|
|
$eventIds = array_filter( (array)$eventIds, 'is_numeric' );
|
|
|
|
if ( !$eventIds || wfReadOnly() ) {
|
2014-08-13 22:00:25 +00:00
|
|
|
return false;
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
2014-08-13 22:00:25 +00:00
|
|
|
$res = $this->userNotifGateway->markRead( $eventIds );
|
|
|
|
if ( $res ) {
|
2014-08-07 00:07:34 +00:00
|
|
|
// Delete records from echo_target_page
|
|
|
|
$this->targetPageMapper->deleteByUserEvents( $this->mUser, $eventIds );
|
|
|
|
// Update notification count in cache
|
2014-08-13 22:00:25 +00:00
|
|
|
$this->resetNotificationCount( DB_MASTER );
|
2015-08-15 01:51:11 +00:00
|
|
|
|
|
|
|
// After this 'mark read', is there any unread edit-user-talk
|
|
|
|
// remaining? If not, we should clear the newtalk flag.
|
|
|
|
if ( $this->mUser->getNewtalk() ) {
|
2015-12-09 18:41:40 +00:00
|
|
|
$unreadEditUserTalk = $this->notifMapper->fetchUnreadByUser( $this->mUser, 1, null, array( 'edit-user-talk' ), DB_MASTER );
|
2015-08-15 01:51:11 +00:00
|
|
|
if ( count( $unreadEditUserTalk ) === 0 ) {
|
|
|
|
$this->mUser->setNewtalk( false );
|
|
|
|
}
|
|
|
|
}
|
2014-08-13 22:00:25 +00:00
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-08-13 22:00:25 +00:00
|
|
|
return $res;
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-08-13 22:00:25 +00:00
|
|
|
* Attempt to mark all or sections of notifications as read, this only
|
|
|
|
* updates up to $wgEchoMaxUpdateCount records per request, see more
|
|
|
|
* detail about this in Echo.php, the other reason is that mediawiki
|
|
|
|
* database interface doesn't support updateJoin() that would update
|
|
|
|
* across multiple tables, we would visit this later
|
|
|
|
*
|
|
|
|
* @param string[] $sections
|
2013-05-24 22:51:47 +00:00
|
|
|
* @return boolean
|
|
|
|
*/
|
2014-08-13 22:00:25 +00:00
|
|
|
public function markAllRead( array $sections = array( EchoAttributeManager::ALL ) ) {
|
|
|
|
if ( wfReadOnly() ) {
|
2013-05-24 22:51:47 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-13 22:00:25 +00:00
|
|
|
global $wgEchoMaxUpdateCount;
|
|
|
|
|
|
|
|
// Mark all sections as read if this is the case
|
|
|
|
if ( in_array( EchoAttributeManager::ALL, $sections ) ) {
|
|
|
|
$sections = EchoAttributeManager::$sections;
|
|
|
|
}
|
|
|
|
|
|
|
|
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
|
|
|
$eventTypes = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', $sections );
|
|
|
|
|
2015-12-09 18:41:40 +00:00
|
|
|
$notifs = $this->notifMapper->fetchUnreadByUser( $this->mUser, $wgEchoMaxUpdateCount, null, $eventTypes );
|
2014-08-07 00:07:34 +00:00
|
|
|
|
|
|
|
$eventIds = array_filter(
|
2015-10-01 13:48:52 +00:00
|
|
|
array_map( function ( EchoNotification $notif ) {
|
2014-08-07 00:07:34 +00:00
|
|
|
// This should not happen at all, but use 0 in
|
2014-08-13 22:00:25 +00:00
|
|
|
// such case so to keep the code running
|
|
|
|
if ( $notif->getEvent() ) {
|
|
|
|
return $notif->getEvent()->getId();
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
2014-08-07 00:07:34 +00:00
|
|
|
}, $notifs )
|
|
|
|
);
|
|
|
|
|
|
|
|
$res = $this->markRead( $eventIds );
|
|
|
|
if ( $res ) {
|
|
|
|
// Delete records from echo_target_page
|
|
|
|
$this->targetPageMapper->deleteByUserEvents( $this->mUser, $eventIds );
|
|
|
|
if ( count( $notifs ) < $wgEchoMaxUpdateCount ) {
|
|
|
|
$this->flagCacheWithNoTalkNotification();
|
|
|
|
}
|
2014-08-13 22:00:25 +00:00
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-08-13 22:00:25 +00:00
|
|
|
return $res;
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Recalculates the number of notifications that a user has.
|
2013-10-08 20:48:54 +00:00
|
|
|
* @param $dbSource int use master or slave database to pull count
|
2013-05-24 22:51:47 +00:00
|
|
|
*/
|
|
|
|
public function resetNotificationCount( $dbSource = DB_SLAVE ) {
|
2014-08-05 21:50:54 +00:00
|
|
|
// Reset notification count for all sections as well
|
|
|
|
$this->getNotificationCount( false, $dbSource, EchoAttributeManager::ALL );
|
2015-10-26 15:27:31 +00:00
|
|
|
$alertCount = $this->getNotificationCount( false, $dbSource, EchoAttributeManager::ALERT );
|
|
|
|
$msgCount = $this->getNotificationCount( false, $dbSource, EchoAttributeManager::MESSAGE );
|
|
|
|
|
|
|
|
$user = $this->mUser;
|
2015-04-29 12:08:30 +00:00
|
|
|
// when notification count needs to be updated, last notification may have
|
|
|
|
// changed too, so we need to invalidate that cache too
|
2015-05-07 11:58:51 +00:00
|
|
|
$this->getLastUnreadNotificationTime( false, $dbSource, EchoAttributeManager::ALL );
|
2015-10-26 15:27:31 +00:00
|
|
|
$alertUnread = $this->getLastUnreadNotificationTime( false, $dbSource, EchoAttributeManager::ALERT );
|
|
|
|
$msgUnread = $this->getLastUnreadNotificationTime( false, $dbSource, EchoAttributeManager::MESSAGE );
|
2013-05-24 22:51:47 +00:00
|
|
|
$this->mUser->invalidateCache();
|
2015-10-26 15:27:31 +00:00
|
|
|
DeferredUpdates::addCallableUpdate( function () use ( $user, $alertCount, $alertUnread, $msgCount, $msgUnread ) {
|
|
|
|
$uw = EchoUnreadWikis::newFromUser( $user );
|
|
|
|
if ( $uw ) {
|
|
|
|
$uw->updateCount( wfWikiID(), $alertCount, $alertUnread, $msgCount, $msgUnread );
|
|
|
|
}
|
|
|
|
} );
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|
|
|
|
|
2013-06-24 00:22:08 +00:00
|
|
|
/**
|
|
|
|
* Get the user's email notification format
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getEmailFormat() {
|
|
|
|
global $wgAllowHTMLEmail;
|
|
|
|
|
|
|
|
if ( $wgAllowHTMLEmail ) {
|
|
|
|
return $this->mUser->getOption( 'echo-email-format' );
|
|
|
|
} else {
|
|
|
|
return EchoHooks::EMAIL_FORMAT_PLAIN_TEXT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-24 22:51:47 +00:00
|
|
|
}
|