59 private const USER_TALK =
'user_talk';
63 private const WATCHLIST =
'watchlist';
67 private const ALL_CHANGES =
'all_changes';
150 $mwServices = MediaWikiServices::getInstance();
151 $config = $mwServices->getMainConfig();
155 if ( $config->get( MainConfigNames::EnotifWatchlist ) ||
156 $config->get( MainConfigNames::ShowUpdatedMarker )
158 $watchers = $mwServices->getWatchedItemStore()->updateNotificationTimestamp(
170 if ( $watchers === [] &&
171 !count( $config->get( MainConfigNames::UsersNotifiedOnAllChanges ) )
176 ( $config->get( MainConfigNames::EnotifMinorEdits ) &&
179 if ( $config->get( MainConfigNames::EnotifUserTalk )
198 'watchers' => $watchers,
231 $pageStatus =
'changed'
233 # we use $wgPasswordSender as sender's address
235 $mwServices = MediaWikiServices::getInstance();
236 $messageCache = $mwServices->getMessageCache();
237 $config = $mwServices->getMainConfig();
239 # The following code is only run, if several conditions are met:
240 # 1. EmailNotification for pages (other than user_talk pages) must be enabled
241 # 2. minor edits (changes) are only regarded if the global flag indicates so
244 $this->timestamp = $timestamp;
245 $this->summary = $summary;
246 $this->minorEdit = $minorEdit;
247 $this->oldid = $oldid;
248 $this->editor = MediaWikiServices::getInstance()->getUserFactory()->newFromAuthority( $editor );
249 $this->composed_common =
false;
250 $this->pageStatus = $pageStatus;
252 $formattedPageStatus = [
'deleted',
'created',
'moved',
'restored',
'changed' ];
254 Hooks::runner()->onUpdateUserMailerFormattedPageStatus( $formattedPageStatus );
255 if ( !in_array( $this->pageStatus, $formattedPageStatus ) ) {
256 throw new MWException(
'Not a valid page status!' );
262 ( $config->get( MainConfigNames::EnotifMinorEdits ) &&
263 !$editor->
isAllowed(
'nominornewtalk' ) )
265 if ( $config->get( MainConfigNames::EnotifUserTalk )
267 && $this->canSendUserTalkEmail( $editor->
getUser(),
$title, $minorEdit )
270 $this->compose( $targetUser, self::USER_TALK, $messageCache );
271 $userTalkId = $targetUser->getId();
274 if ( $config->get( MainConfigNames::EnotifWatchlist ) ) {
275 $userOptionsLookup = $mwServices->getUserOptionsLookup();
279 foreach ( $userArray as $watchingUser ) {
280 if ( $userOptionsLookup->getOption( $watchingUser,
'enotifwatchlistpages' )
281 && ( !$minorEdit || $userOptionsLookup->getOption( $watchingUser,
'enotifminoredits' ) )
282 && $watchingUser->isEmailConfirmed()
283 && $watchingUser->getId() != $userTalkId
284 && !in_array( $watchingUser->getName(),
285 $config->get( MainConfigNames::UsersNotifiedOnAllChanges ) )
288 && !( $config->get( MainConfigNames::BlockDisablesLogin ) &&
289 $watchingUser->getBlock() )
292 $this->compose( $watchingUser, self::WATCHLIST, $messageCache );
298 foreach ( $config->get( MainConfigNames::UsersNotifiedOnAllChanges ) as $name ) {
299 if ( $editor->
getUser()->getName() == $name ) {
304 if ( $user instanceof
User ) {
305 $this->compose( $user, self::ALL_CHANGES, $messageCache );
318 $services = MediaWikiServices::getInstance();
319 $config = $services->getMainConfig();
321 if ( !$config->get( MainConfigNames::EnotifUserTalk ) ||
$title->getNamespace() !==
NS_USER_TALK ) {
325 $userOptionsLookup = $services->getUserOptionsLookup();
328 if ( !$targetUser || $targetUser->isAnon() ) {
329 wfDebug( __METHOD__ .
": user talk page edited, but user does not exist" );
330 } elseif ( $targetUser->getId() == $editor->
getId() ) {
331 wfDebug( __METHOD__ .
": user edited their own talk page, no notification sent" );
332 } elseif ( $config->get( MainConfigNames::BlockDisablesLogin ) &&
333 $targetUser->getBlock()
337 wfDebug( __METHOD__ .
": talk page owner is blocked and cannot login, no notification sent" );
338 } elseif ( $userOptionsLookup->getOption( $targetUser,
'enotifusertalkpages' )
339 && ( !$minorEdit || $userOptionsLookup->getOption( $targetUser,
'enotifminoredits' ) )
341 if ( !$targetUser->isEmailConfirmed() ) {
342 wfDebug( __METHOD__ .
": talk page owner doesn't have validated email" );
344 wfDebug( __METHOD__ .
": talk page update notification is aborted for this user" );
346 wfDebug( __METHOD__ .
": sending talk page update notification" );
350 wfDebug( __METHOD__ .
": talk page owner doesn't want notifications" );
359 private function composeCommonMailtext(
MessageCache $messageCache ) {
360 $services = MediaWikiServices::getInstance();
361 $config = $services->getMainConfig();
362 $userOptionsLookup = $services->getUserOptionsLookup();
364 $this->composed_common =
true;
366 # You as the WikiAdmin and Sysops can make use of plenty of
367 # named variables when composing your notification emails while
368 # simply editing the Meta pages
371 $postTransformKeys = [];
372 $pageTitleUrl = $this->title->getCanonicalURL();
373 $pageTitle = $this->title->getPrefixedText();
375 if ( $this->oldid ) {
379 $this->title->getCanonicalURL( [
'diff' =>
'next',
'oldid' => $this->oldid ] )
380 )->inContentLanguage()->text();
382 if ( !$config->get( MainConfigNames::EnotifImpersonal ) ) {
386 'enotif_lastvisited',
387 $this->title->getCanonicalURL( [
'diff' =>
'0',
'oldid' => $this->oldid ] )
388 )->inContentLanguage()->text();
390 $keys[
'$OLDID'] = $this->oldid;
392 $keys[
'$CHANGEDORCREATED'] =
wfMessage(
'changed' )->inContentLanguage()->text();
394 # clear $OLDID placeholder in the message template
395 $keys[
'$OLDID'] =
'';
396 $keys[
'$NEWPAGE'] =
'';
398 $keys[
'$CHANGEDORCREATED'] =
wfMessage(
'created' )->inContentLanguage()->text();
401 $keys[
'$PAGETITLE'] = $this->title->getPrefixedText();
402 $keys[
'$PAGETITLE_URL'] = $this->title->getCanonicalURL();
403 $keys[
'$PAGEMINOREDIT'] = $this->minorEdit ?
404 "\n\n" .
wfMessage(
'enotif_minoredit' )->inContentLanguage()->text() :
406 $keys[
'$UNWATCHURL'] = $this->title->getCanonicalURL(
'action=unwatch' );
408 if ( !$this->editor->isRegistered() ) {
409 # real anon (user:xxx.xxx.xxx.xxx)
410 $keys[
'$PAGEEDITOR'] =
wfMessage(
'enotif_anon_editor', $this->editor->getName() )
411 ->inContentLanguage()->text();
412 $keys[
'$PAGEEDITOR_EMAIL'] =
wfMessage(
'noemailtitle' )->inContentLanguage()->text();
415 $keys[
'$PAGEEDITOR'] = $config->get( MainConfigNames::EnotifUseRealName ) &&
416 $this->editor->getRealName() !==
''
417 ? $this->editor->getRealName() : $this->editor->getName();
419 $keys[
'$PAGEEDITOR_EMAIL'] = $emailPage->getCanonicalURL();
422 $keys[
'$PAGEEDITOR_WIKI'] = $this->editor->getUserPage()->getCanonicalURL();
427 # Replace this after transforming the message, T37019
428 $postTransformKeys[
'$PAGESUMMARY'] = $this->summary ==
'' ?
' - ' : $this->summary;
435 $this->subject =
wfMessage(
'enotif_subject_' . $this->pageStatus )->inContentLanguage()
436 ->params( $pageTitle,
$keys[
'$PAGEEDITOR'] )->text();
441 $keys[
'$PAGEINTRO'] =
wfMessage(
'enotif_body_intro_' . $this->pageStatus )
442 ->inContentLanguage()
443 ->params( $pageTitle,
$keys[
'$PAGEEDITOR'], $pageTitleUrl )
446 $body =
wfMessage(
'enotif_body' )->inContentLanguage()->plain();
447 $body = strtr( $body,
$keys );
448 $body = $messageCache->
transform( $body,
false,
null, $this->title );
449 $this->body = wordwrap( strtr( $body, $postTransformKeys ), 72 );
451 # Reveal the page editor's address as REPLY-TO address only if
452 # the user has not opted-out and the option is enabled at the
453 # global configuration level.
455 $config->get( MainConfigNames::PasswordSender ),
456 wfMessage(
'emailsender' )->inContentLanguage()->text()
458 if ( $config->get( MainConfigNames::EnotifRevealEditorAddress )
459 && ( $this->editor->getEmail() !=
'' )
460 && $userOptionsLookup->getOption( $this->editor,
'enotifrevealaddr' )
463 if ( $config->get( MainConfigNames::EnotifFromEditor ) ) {
464 $this->from = $editorAddress;
466 $this->from = $adminAddress;
467 $this->replyto = $editorAddress;
470 $this->from = $adminAddress;
472 $config->get( MainConfigNames::NoReplyAddress )
487 if ( !$this->composed_common ) {
488 $this->composeCommonMailtext( $messageCache );
491 if ( MediaWikiServices::getInstance()->getMainConfig()->
get( MainConfigNames::EnotifImpersonal ) ) {
494 $this->sendPersonalised( $user,
$source );
501 private function sendMails() {
502 if ( MediaWikiServices::getInstance()->getMainConfig()->
get( MainConfigNames::EnotifImpersonal ) ) {
503 $this->sendImpersonal( $this->mailTargets );
524 # $PAGEEDITDATE is the time and date of the page change
525 # expressed in terms of individual local time of the notification
526 # recipient, i.e. watching user
527 $mwServices = MediaWikiServices::getInstance();
528 $contLang = $mwServices->getContentLanguage();
529 $watchingUserName = (
530 $mwServices->getMainConfig()->get( MainConfigNames::EnotifUseRealName ) &&
541 $contLang->userDate( $this->timestamp, $watchingUser->
getUser() ),
542 $contLang->userTime( $this->timestamp, $watchingUser->
getUser() )
548 if (
$source === self::WATCHLIST ) {
549 $headers[
'List-Help'] =
'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Watchlist';
553 'replyTo' => $this->replyto,
554 'headers' => $headers,
564 private function sendImpersonal( $addresses ) {
565 if ( empty( $addresses ) ) {
569 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
577 wfMessage(
'enotif_impersonal_salutation' )->inContentLanguage()->text(),
578 $contLang->date( $this->timestamp,
false,
false ),
579 $contLang->time( $this->timestamp,
false,
false )
585 'replyTo' => $this->replyto,
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
This module processes the email notifications when the current page is changed.
MailAddress null $replyto
actuallyNotifyOnPageChange(Authority $editor, $title, $timestamp, $summary, $minorEdit, $oldid, $watchers, $pageStatus='changed')
Immediate version of notifyOnPageChange().
notifyOnPageChange(Authority $editor, $title, $timestamp, $summary, $minorEdit, $oldid=false, $pageStatus='changed')
Send emails corresponding to the user $editor editing the page $title.
getPageStatus()
Extensions that have hooks for UpdateUserMailerFormattedPageStatus (to provide additional pageStatus ...
MailAddress[] $mailTargets
Send an email notification.
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Stores a single person's name and email address.
static newFromUser(UserEmailContact $user)
Create a new MailAddress object for the given user.
A class containing constants representing the names of configuration variables.
Cache messages that are defined by MediaWiki-namespace pages or by hooks.
transform( $message, $interface=false, $language=null, PageReference $page=null)
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
static getSafeTitleFor( $name, $subpage=false)
Get a localised Title object for a page name with a possibly unvalidated subpage.
getNamespace()
Get the namespace index, i.e.
static send( $to, $from, $subject, $body, $options=[])
This function will perform a direct (authenticated) login to a SMTP Server to use for mail relaying i...
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
static newFromName( $name, $validate='valid')
isAllowed(string $permission)
Checks whether this authority has the given permission in general.