70 private $readOnlyMode;
73 private $revisionLookup;
76 private $talkPageNotificationManager;
79 private $watchedItemStore;
88 private $wikiPageFactory;
106 private $notificationTimestampCache = [];
131 $this->options = $options;
132 $this->hookRunner =
new HookRunner( $hookContainer );
133 $this->readOnlyMode = $readOnlyMode;
134 $this->revisionLookup = $revisionLookup;
135 $this->talkPageNotificationManager = $talkPageNotificationManager;
136 $this->watchedItemStore = $watchedItemStore;
137 $this->userFactory = $userFactory;
138 $this->nsInfo = $nsInfo;
139 $this->wikiPageFactory = $wikiPageFactory;
152 if ( $this->readOnlyMode->isReadOnly() ) {
157 if ( !$performer instanceof
Authority ) {
158 $performer = $this->userFactory->newFromUserIdentity( $performer );
161 if ( !$performer->isAllowed(
'editmywatchlist' ) ) {
166 $user = $performer->getUser();
172 $this->talkPageNotificationManager->removeUserHasNewMessages( $user );
176 if ( !$user->isRegistered() ) {
180 $this->watchedItemStore->resetAllNotificationTimestampsForUser( $user );
205 if ( $this->readOnlyMode->isReadOnly() ) {
210 if ( !$performer instanceof
Authority ) {
211 $performer = $this->userFactory->newFromUserIdentity( $performer );
214 if ( !$performer->isAllowed(
'editmywatchlist' ) ) {
219 $userIdentity = $performer->getUser();
222 $title->getDBkey() === strtr( $userIdentity->getName(),
' ',
'_' )
225 if ( $userTalkPage ) {
228 } elseif ( !$oldRev ) {
229 $oldRev = $this->revisionLookup->getRevisionById( $oldid );
231 $this->talkPageNotificationManager->clearForPageView( $userIdentity, $oldRev );
241 if ( !$userIdentity->isRegistered() ) {
250 $force = $userTalkPage ?
'force' :
'';
251 $this->watchedItemStore->resetNotificationTimestamp( $userIdentity,
$title, $force, $oldid );
266 $cacheKey =
'u' . (string)$user->
getId() .
'-' .
267 (string)
$title->getNamespace() .
':' .
$title->getDBkey();
270 if ( array_key_exists( $cacheKey, $this->notificationTimestampCache ) ) {
271 return $this->notificationTimestampCache[ $cacheKey ];
274 $watchedItem = $this->watchedItemStore->getWatchedItem( $user,
$title );
275 if ( $watchedItem ) {
276 $timestamp = $watchedItem->getNotificationTimestamp();
281 $this->notificationTimestampCache[ $cacheKey ] = $timestamp;
291 if ( !$this->nsInfo->
isWatchable( $target->getNamespace() ) ) {
311 if ( $this->isWatchable( $target ) ) {
312 return $this->watchedItemStore->isWatched( $userIdentity, $target );
326 if ( $performer->isAllowed(
'viewmywatchlist' ) ) {
327 return $this->isWatchedIgnoringRights( $performer->
getUser(), $target );
340 if ( $this->isWatchable( $target ) ) {
341 return $this->watchedItemStore->isTempWatched( $userIdentity, $target );
355 if ( $performer->isAllowed(
'viewmywatchlist' ) ) {
356 return $this->isTempWatchedIgnoringRights( $performer->
getUser(), $target );
373 ?
string $expiry =
null
375 if ( !$this->isWatchable( $target ) ) {
376 return StatusValue::newFatal(
'watchlistnotwatchable' );
379 $wikiPage = $this->wikiPageFactory->newFromTitle( $target );
380 $title = $wikiPage->getTitle();
383 $status = Status::newFatal(
'hookaborted' );
384 $user = $this->userFactory->newFromUserIdentity( $userIdentity );
385 if ( $this->hookRunner->onWatchArticle( $user, $wikiPage, $status, $expiry ) ) {
386 $status = StatusValue::newGood();
387 $this->watchedItemStore->addWatch( $userIdentity, $this->nsInfo->getSubjectPage(
$title ), $expiry );
388 if ( $this->nsInfo->canHaveTalkPage(
$title ) ) {
389 $this->watchedItemStore->addWatch( $userIdentity, $this->nsInfo->getTalkPage(
$title ), $expiry );
391 $this->hookRunner->onWatchArticleComplete( $user, $wikiPage );
395 $user->invalidateCache();
413 ?
string $expiry =
null
415 if ( !$performer->isAllowed(
'editmywatchlist' ) ) {
420 return $this->addWatchIgnoringRights( $performer->getUser(), $target, $expiry );
434 if ( !$this->isWatchable( $target ) ) {
435 return StatusValue::newFatal(
'watchlistnotwatchable' );
438 $wikiPage = $this->wikiPageFactory->newFromTitle( $target );
439 $title = $wikiPage->getTitle();
442 $status = Status::newFatal(
'hookaborted' );
443 $user = $this->userFactory->newFromUserIdentity( $userIdentity );
444 if ( $this->hookRunner->onUnwatchArticle( $user, $wikiPage, $status ) ) {
445 $status = StatusValue::newGood();
446 $this->watchedItemStore->removeWatch( $userIdentity, $this->nsInfo->getSubjectPage(
$title ) );
447 if ( $this->nsInfo->canHaveTalkPage(
$title ) ) {
448 $this->watchedItemStore->removeWatch( $userIdentity, $this->nsInfo->getTalkPage(
$title ) );
450 $this->hookRunner->onUnwatchArticleComplete( $user, $wikiPage );
454 $user->invalidateCache();
471 if ( !$performer->isAllowed(
'editmywatchlist' ) ) {
476 return $this->removeWatchIgnoringRights( $performer->getUser(), $target );
496 string $expiry =
null
499 if ( !$performer->
getUser()->isRegistered() ) {
500 return StatusValue::newGood();
504 $oldWatchedItem = $this->watchedItemStore->getWatchedItem( $performer->getUser(), $target );
505 $changingWatchStatus = (bool)$oldWatchedItem !== $watch;
506 if ( $oldWatchedItem && $expiry !==
null ) {
508 $oldWatchPeriod = $oldWatchedItem->getExpiry() ??
'infinity';
509 $changingWatchStatus = $changingWatchStatus ||
510 $oldWatchPeriod !== ExpiryDef::normalizeExpiry( $expiry, TS_MW );
513 if ( $changingWatchStatus ) {
517 return $this->addWatchIgnoringRights( $performer->getUser(), $target, $expiry );
519 return $this->removeWatch( $performer, $target );
531class_alias( WatchlistManager::class,
'MediaWiki\User\WatchlistNotificationManager' );
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
A class containing constants representing the names of configuration variables.
const EnotifWatchlist
Name constant for the EnotifWatchlist setting, for use with Config::get()
const EnotifUserTalk
Name constant for the EnotifUserTalk setting, for use with Config::get()
const ShowUpdatedMarker
Name constant for the ShowUpdatedMarker setting, for use with Config::get()
Service for creating WikiPage objects.
Manages user talk page notifications.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
A service class for fetching the wiki's current read-only mode.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
static newGood( $value=null)
Factory function for good results.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
static newFatalPermissionDeniedStatus( $permission)
Factory function for fatal permission-denied errors.
Interface for objects (potentially) representing an editable wiki page.
canExist()
Checks whether this PageIdentity represents a "proper" page, meaning that it could exist as an editab...