MediaWiki REL1_35
WatchlistNotificationManager.php
Go to the documentation of this file.
1<?php
2
23namespace MediaWiki\User;
24
32use ReadOnlyMode;
34
41
42 public const CONSTRUCTOR_OPTIONS = [
43 'UseEnotif',
44 'ShowUpdatedMarker',
45 ];
46
48 private $options;
49
51 private $hookRunner;
52
55
58
61
64
67
85
95 public function __construct(
97 HookContainer $hookContainer,
103 ) {
104 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
105 $this->options = $options;
106 $this->hookRunner = new HookRunner( $hookContainer );
107 $this->permissionManager = $permissionManager;
108 $this->readOnlyMode = $readOnlyMode;
109 $this->revisionLookup = $revisionLookup;
110 $this->talkPageNotificationManager = $talkPageNotificationManager;
111 $this->watchedItemStore = $watchedItemStore;
112 }
113
123 public function clearAllUserNotifications( UserIdentity $user ) {
124 if ( $this->readOnlyMode->isReadOnly() ) {
125 // Cannot change anything in read only
126 return;
127 }
128
129 if ( !$this->permissionManager->userHasRight( $user, 'editmywatchlist' ) ) {
130 // User isn't allowed to edit the watchlist
131 return;
132 }
133
134 if ( !$this->options->get( 'UseEnotif' ) &&
135 !$this->options->get( 'ShowUpdatedMarker' )
136 ) {
137 $this->talkPageNotificationManager->removeUserHasNewMessages( $user );
138 return;
139 }
140
141 $userId = $user->getId();
142 if ( !$userId ) {
143 return;
144 }
145
146 $this->watchedItemStore->resetAllNotificationTimestampsForUser( $user );
147
148 // We also need to clear here the "you have new message" notification for the own
149 // user_talk page; it's cleared one page view later in WikiPage::doViewUpdates().
150 }
151
164 UserIdentity $user,
166 int $oldid = 0
167 ) {
168 if ( $this->readOnlyMode->isReadOnly() ) {
169 // Cannot change anything in read only
170 return;
171 }
172
173 if ( !$this->permissionManager->userHasRight( $user, 'editmywatchlist' ) ) {
174 // User isn't allowed to edit the watchlist
175 return;
176 }
177
178 $userTalkPage = (
179 $title->getNamespace() === NS_USER_TALK &&
180 $title->getText() === $user->getName()
181 );
182
183 if ( $userTalkPage ) {
184 // If we're working on user's talk page, we should update the talk page message indicator
185 if ( !$this->hookRunner->onUserClearNewTalkNotification( $user, $oldid ) ) {
186 return;
187 }
188
189 // Try to update the DB post-send and only if needed...
192 DeferredUpdates::addCallableUpdate( function () use (
193 $user,
194 $oldid,
197 ) {
199 // no notifications to clear
200 return;
201 }
202 // Delete the last notifications (they stack up)
204
205 // If there is a new, unseen, revision, use its timestamp
206 if ( !$oldid ) {
207 return;
208 }
209
211 $oldid,
212 RevisionLookup::READ_LATEST
213 );
214 if ( !$oldRev ) {
215 return;
216 }
217
218 $newRev = $revisionLookup->getNextRevision( $oldRev );
219 if ( $newRev ) {
221 $user,
222 $newRev
223 );
224 }
225 } );
226 }
227
228 if ( !$this->options->get( 'UseEnotif' ) &&
229 !$this->options->get( 'ShowUpdatedMarker' )
230 ) {
231 return;
232 }
233
234 if ( !$user->isRegistered() ) {
235 // Nothing else to do
236 return;
237 }
238
239 // Only update the timestamp if the page is being watched.
240 // The query to find out if it is watched is cached both in memcached and per-invocation,
241 // and when it does have to be executed, it can be on a replica DB
242 // If this is the user's newtalk page, we always update the timestamp
243 $force = $userTalkPage ? 'force' : '';
244 $this->watchedItemStore->resetNotificationTimestamp( $user, $title, $force, $oldid );
245 }
246
255 $userId = $user->getId();
256
257 if ( !$userId ) {
258 return false;
259 }
260
261 $cacheKey = 'u' . (string)$userId . '-' .
262 (string)$title->getNamespace() . ':' . $title->getDBkey();
263
264 // avoid isset here, as it'll return false for null entries
265 if ( array_key_exists( $cacheKey, $this->notificationTimestampCache ) ) {
266 return $this->notificationTimestampCache[ $cacheKey ];
267 }
268
269 $watchedItem = $this->watchedItemStore->getWatchedItem( $user, $title );
270 if ( $watchedItem ) {
271 $timestamp = $watchedItem->getNotificationTimestamp();
272 } else {
273 $timestamp = false;
274 }
275
276 $this->notificationTimestampCache[ $cacheKey ] = $timestamp;
277 return $timestamp;
278 }
279
280}
Class for managing the deferred updates.
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
setUserHasNewMessages(UserIdentity $user, RevisionRecord $curRev=null)
Update the talk page messages status.
userHasNewMessages(UserIdentity $user)
Check if the user has new messages.
removeUserHasNewMessages(UserIdentity $user)
Remove the new messages status.
array $notificationTimestampCache
Cache for getTitleNotificationTimestamp.
__construct(ServiceOptions $options, HookContainer $hookContainer, PermissionManager $permissionManager, ReadOnlyMode $readOnlyMode, RevisionLookup $revisionLookup, TalkPageNotificationManager $talkPageNotificationManager, WatchedItemStoreInterface $watchedItemStore)
clearTitleUserNotifications(UserIdentity $user, LinkTarget $title, int $oldid=0)
Clear the user's notification timestamp for the given title.
clearAllUserNotifications(UserIdentity $user)
Resets all of the given user's page-change notification timestamps.
getTitleNotificationTimestamp(UserIdentity $user, LinkTarget $title)
Get the timestamp when this page was updated since the user last saw it.
A service class for fetching the wiki's current read-only mode.
const NS_USER_TALK
Definition Defines.php:73
Service for looking up page revisions.
getNextRevision(RevisionRecord $rev, $flags=0)
Get next revision for this title.
getRevisionById( $id, $flags=0)
Load a page revision from a given revision ID number.
Interface for objects representing user identity.