* (which will be false if not present), and takes the arguments:
* (this BagOStuff, cache key, current value, TTL).
* The TTL parameter is reference set to $exptime. It can be overriden in the callback.
+ * If the callback returns false, then the current value will be unchanged (including TTL).
*
* @param string $key
* @param callable $callback Callback method to be executed
protected static $limitPreferenceName = 'wllimit';
protected static $collapsedPreferenceName = 'rcfilters-wl-collapsed';
+ /** @var float|int */
private $maxDays;
+ /** WatchedItemStore */
+ private $watchStore;
public function __construct( $page = 'Watchlist', $restriction = 'viewmywatchlist' ) {
parent::__construct( $page, $restriction );
$this->maxDays = $this->getConfig()->get( 'RCMaxAge' ) / ( 3600 * 24 );
+ $this->watchStore = MediaWikiServices::getInstance()->getWatchedItemStore();
}
public function doesWrites() {
'label' => 'rcfilters-filter-watchlistactivity-unseen-label',
'description' => 'rcfilters-filter-watchlistactivity-unseen-description',
'cssClassSuffix' => 'watchedunseen',
- 'isRowApplicableCallable' => function ( $ctx, $rc ) {
+ 'isRowApplicableCallable' => function ( $ctx, RecentChange $rc ) {
$changeTs = $rc->getAttribute( 'rc_timestamp' );
- $lastVisitTs = $rc->getAttribute( 'wl_notificationtimestamp' );
+ $lastVisitTs = $this->watchStore->getLatestNotificationTimestamp(
+ $rc->getAttribute( 'wl_notificationtimestamp' ),
+ $rc->getPerformer(),
+ $rc->getTitle()
+ );
return $lastVisitTs !== null && $changeTs >= $lastVisitTs;
},
],
}
}
+ // Get the timestamp (TS_MW) of this revision to track the latest one seen
+ $seenTime = call_user_func(
+ $this->revisionGetTimestampFromIdCallback,
+ $title,
+ $oldid ?: $title->getLatestRevID()
+ );
+
// Mark the item as read immediately in lightweight storage
$this->stash->merge(
$this->getPageSeenTimestampsKey( $user ),
- function ( $cache, $key, $current ) use ( $time, $title ) {
+ function ( $cache, $key, $current ) use ( $title, $seenTime ) {
$value = $current ?: new MapCacheLRU( 300 );
- $value->set( $this->getPageSeenKey( $title ), wfTimestamp( TS_MW, $time ) );
-
- $this->latestUpdateCache->set( $key, $value, IExpiringStore::TTL_PROC_LONG );
+ $subKey = $this->getPageSeenKey( $title );
+
+ if ( $seenTime > $value->get( $subKey ) ) {
+ // Revision is newer than the last one seen
+ $value->set( $subKey, $seenTime );
+ $this->latestUpdateCache->set( $key, $value, IExpiringStore::TTL_PROC_LONG );
+ } elseif ( $seenTime === false ) {
+ // Revision does not exist
+ $value->set( $subKey, wfTimestamp( TS_MW ) );
+ $this->latestUpdateCache->set( $key, $value, IExpiringStore::TTL_PROC_LONG );
+ } else {
+ return false; // nothing to update
+ }
return $value;
},
/**
* @param User $user
- * @return MapCacheLRU|null
+ * @return MapCacheLRU|null The map contains prefixed title keys and TS_MW values
*/
private function getPageSeenTimestamps( User $user ) {
$key = $this->getPageSeenTimestampsKey( $user );
$oldid
)
);
- $this->assertEquals( 1, $getTimestampCallCounter );
+ $this->assertEquals( 2, $getTimestampCallCounter );
ScopedCallback::consume( $scopedOverrideRevision );
}
$oldid
)
);
- $this->assertEquals( 1, $getTimestampCallCounter );
+ $this->assertEquals( 2, $getTimestampCallCounter );
ScopedCallback::consume( $scopedOverrideRevision );
}
$oldid
)
);
- $this->assertEquals( 1, $getTimestampCallCounter );
+ $this->assertEquals( 2, $getTimestampCallCounter );
ScopedCallback::consume( $scopedOverrideRevision );
}