MediaWiki master
RecentChangeMailComposer.php
Go to the documentation of this file.
1<?php
8
24
33
37 public const USER_TALK = 'user_talk';
41 public const WATCHLIST = 'watchlist';
45 public const ALL_CHANGES = 'all_changes';
46
47 protected string $subject = '';
48
49 protected string $body = '';
50
51 protected string $summary = '';
52
54
55 protected ?MailAddress $from;
56
57 protected bool $composed_common = false;
58
60 protected array $mailTargets = [];
61
62 protected ?bool $minorEdit;
63
65 protected $oldid;
66
67 protected string $timestamp;
68
69 protected string $pageStatus = '';
70
71 protected Title $title;
72
73 protected User $editor;
74
75 private Config $mainConfig;
76 private UserOptionsLookup $userOptionsLookup;
77 private UrlUtils $urlUtils;
78 private MessageParser $messageParser;
79 private Language $contentLanguage;
80 private IEmailer $emailer;
81
82 public function __construct(
85 RecentChange $recentChange,
86 string $pageStatus
87 ) {
89 $this->editor = $services->getUserFactory()->newFromAuthority( $editor );
90 $this->title = $title;
91 $this->oldid = $recentChange->getAttribute( 'rc_last_oldid' );
92 $this->minorEdit = $recentChange->getAttribute( 'rc_minor' );
93 $this->timestamp = $recentChange->getAttribute( 'rc_timestamp' );
94 $this->summary = $recentChange->getAttribute( 'rc_comment' );
95 $this->pageStatus = $pageStatus;
96
97 // Prepare for dependency injection
98 $this->mainConfig = $services->getMainConfig();
99 $this->userOptionsLookup = $services->getUserOptionsLookup();
100 $this->urlUtils = $services->getUrlUtils();
101 $this->messageParser = $services->getMessageParser();
102 $this->contentLanguage = $services->getContentLanguage();
103 $this->emailer = $services->getEmailer();
104 }
105
109 private function composeCommonMailtext() {
110 $this->composed_common = true;
111
112 # You as the WikiAdmin and Sysops can make use of plenty of
113 # named variables when composing your notification emails while
114 # simply editing the Meta pages
115
116 $keys = [];
117 $postTransformKeys = [];
118 $pageTitleUrl = $this->title->getCanonicalURL();
119 $pageTitle = $this->title->getPrefixedText();
120
121 if ( $this->oldid ) {
122 // Always show a link to the diff which triggered the mail. See T34210.
123 $keys['$NEWPAGE'] = "\n\n" . wfMessage(
124 'enotif_lastdiff',
125 $this->title->getCanonicalURL( [ 'diff' => 'next', 'oldid' => $this->oldid ] )
126 )->inContentLanguage()->text();
127
128 // For personal mail, also show a link to the diff of all changes
129 // since last visited.
130 $keys['$NEWPAGE'] .= "\n\n" . wfMessage(
131 'enotif_lastvisited',
132 $this->title->getCanonicalURL( [ 'diff' => '0', 'oldid' => $this->oldid ] )
133 )->inContentLanguage()->text();
134 $keys['$OLDID'] = $this->oldid;
135 $keys['$PAGELOG'] = '';
136 } else {
137 // If there is no revision to link to, link to the page log, which should have details. See T115183.
138 $keys['$OLDID'] = '';
139 $keys['$NEWPAGE'] = '';
140 $keys['$PAGELOG'] = "\n\n" . wfMessage(
141 'enotif_pagelog',
142 SpecialPage::getTitleFor( 'Log' )->getCanonicalURL( [ 'page' =>
143 $this->title->getPrefixedDBkey() ] )
144 )->inContentLanguage()->text();
145 }
146
147 $keys['$PAGETITLE'] = $this->title->getPrefixedText();
148 $keys['$PAGETITLE_URL'] = $this->title->getCanonicalURL();
149 $keys['$PAGEMINOREDIT'] = $this->minorEdit ?
150 "\n\n" . wfMessage( 'enotif_minoredit' )->inContentLanguage()->text() :
151 '';
152 $keys['$UNWATCHURL'] = $this->title->getCanonicalURL( 'action=unwatch' );
153
154 if ( $this->editor->isAnon() ) {
155 # real anon (user:xxx.xxx.xxx.xxx)
156 $keys['$PAGEEDITOR'] = wfMessage( 'enotif_anon_editor', $this->editor->getName() )
157 ->inContentLanguage()->text();
158 $keys['$PAGEEDITOR_EMAIL'] = wfMessage( 'noemailtitle' )->inContentLanguage()->text();
159 } elseif ( $this->editor->isTemp() ) {
160 $keys['$PAGEEDITOR'] = wfMessage( 'enotif_temp_editor', $this->editor->getName() )
161 ->inContentLanguage()->text();
162 $keys['$PAGEEDITOR_EMAIL'] = wfMessage( 'noemailtitle' )->inContentLanguage()->text();
163 } else {
164 $keys['$PAGEEDITOR'] = $this->mainConfig->get( MainConfigNames::EnotifUseRealName ) &&
165 $this->editor->getRealName() !== ''
166 ? $this->editor->getRealName() : $this->editor->getName();
167 $emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $this->editor->getName() );
168 $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getCanonicalURL();
169 }
170
171 $keys['$PAGEEDITOR_WIKI'] = $this->editor->getTalkPage()->getCanonicalURL();
172 $keys['$HELPPAGE'] = $this->urlUtils->expand(
173 Skin::makeInternalOrExternalUrl( wfMessage( 'helppage' )->inContentLanguage()->text() ),
175 ) ?? false;
176
177 # Replace this after transforming the message, T37019
178 $postTransformKeys['$PAGESUMMARY'] = $this->summary == '' ? ' - ' : $this->summary;
179
180 // Now build message's subject and body
181
182 // Messages:
183 // enotif_subject_deleted, enotif_subject_created, enotif_subject_moved,
184 // enotif_subject_restored, enotif_subject_changed
185 $this->subject = wfMessage( 'enotif_subject_' . $this->pageStatus )->inContentLanguage()
186 ->params( $pageTitle, $keys['$PAGEEDITOR'] )->text();
187
188 // Messages:
189 // enotif_body_intro_deleted, enotif_body_intro_created, enotif_body_intro_moved,
190 // enotif_body_intro_restored, enotif_body_intro_changed
191 $keys['$PAGEINTRO'] = wfMessage( 'enotif_body_intro_' . $this->pageStatus )
192 ->inContentLanguage()
193 ->params( $pageTitle, $keys['$PAGEEDITOR'], "<{$pageTitleUrl}>" )
194 ->text();
195
196 $body = wfMessage( 'enotif_body' )->inContentLanguage()->plain();
197 $body = strtr( $body, $keys );
198 $body = $this->messageParser->transform( $body, false, null, $this->title );
199 $this->body = wordwrap( strtr( $body, $postTransformKeys ), 72 );
200
201 # Reveal the page editor's address as REPLY-TO address only if
202 # the user has not opted-out and the option is enabled at the
203 # global configuration level.
204 $adminAddress = new MailAddress(
205 $this->mainConfig->get( MainConfigNames::PasswordSender ),
206 wfMessage( 'emailsender' )->inContentLanguage()->text()
207 );
208 if ( $this->mainConfig->get( MainConfigNames::EnotifRevealEditorAddress )
209 && ( $this->editor->getEmail() != '' )
210 && $this->userOptionsLookup->getOption( $this->editor, 'enotifrevealaddr' )
211 ) {
212 $editorAddress = MailAddress::newFromUser( $this->editor );
213 if ( $this->mainConfig->get( MainConfigNames::EnotifFromEditor ) ) {
214 $this->from = $editorAddress;
215 } else {
216 $this->from = $adminAddress;
217 $this->replyto = $editorAddress;
218 }
219 } else {
220 $this->from = $adminAddress;
221 $this->replyto = new MailAddress(
222 $this->mainConfig->get( MainConfigNames::NoReplyAddress )
223 );
224 }
225 }
226
233 public function compose( UserEmailContact $watchingUser, $source ) {
234 if ( !$this->composed_common ) {
235 $this->composeCommonMailtext();
236 }
237
238 // From the PHP manual:
239 // Note: The to parameter cannot be an address in the form of
240 // "Something <someone@example.com>". The mail command will not parse
241 // this properly while talking with the MTA.
242 $to = MailAddress::newFromUser( $watchingUser );
243
244 # $PAGEEDITDATE is the time and date of the page change
245 # expressed in terms of individual local time of the notification
246 # recipient, i.e. watching user
247 $watchingUserName = (
248 $this->mainConfig->get( MainConfigNames::EnotifUseRealName ) &&
249 $watchingUser->getRealName() !== ''
250 ) ? $watchingUser->getRealName() : $watchingUser->getUser()->getName();
251 $body = str_replace(
252 [
253 '$WATCHINGUSERNAME',
254 '$PAGEEDITDATE',
255 '$PAGEEDITTIME'
256 ],
257 [
258 $watchingUserName,
259 $this->contentLanguage->userDate( $this->timestamp, $watchingUser->getUser() ),
260 $this->contentLanguage->userTime( $this->timestamp, $watchingUser->getUser() )
261 ],
262 $this->body
263 );
264
265 $headers = [];
266 if ( $source === self::WATCHLIST ) {
267 $headers['List-Help'] = 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Watchlist';
268 }
269
270 $this->emailer->send(
271 [ $to ],
272 $this->from,
273 $this->subject,
274 $body,
275 null,
276 [
277 'replyTo' => $this->replyto,
278 'headers' => $headers,
279 ]
280 );
281 }
282}
const PROTO_CURRENT
Definition Defines.php:222
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Base class for language-specific code.
Definition Language.php:65
Service for transformation of interface message text.
Represent and format a single name and email address pair for SMTP.
A class containing constants representing the names of configuration variables.
const NoReplyAddress
Name constant for the NoReplyAddress setting, for use with Config::get()
const EnotifRevealEditorAddress
Name constant for the EnotifRevealEditorAddress setting, for use with Config::get()
const EnotifFromEditor
Name constant for the EnotifFromEditor setting, for use with Config::get()
const EnotifUseRealName
Name constant for the EnotifUseRealName setting, for use with Config::get()
const PasswordSender
Name constant for the PasswordSender setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Component responsible for composing and sending emails triggered after a RecentChange.
compose(UserEmailContact $watchingUser, $source)
Compose a mail to a given user and send it now.
const ALL_CHANGES
Notification because user is notified for all changes.
const USER_TALK
Notification is due to user's user talk being edited.
__construct(Authority $editor, Title $title, RecentChange $recentChange, string $pageStatus)
const WATCHLIST
Notification is due to a watchlisted page being edited.
Utility class for creating and reading rows in the recentchanges table.
getAttribute( $name)
Get an attribute value.
The base class for all skins.
Definition Skin.php:54
Parent class for all special pages.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
static getSafeTitleFor( $name, $subpage=false)
Get a localised Title object for a page name with a possibly unvalidated subpage.
Represents a title within MediaWiki.
Definition Title.php:69
Provides access to user options.
User class for the MediaWiki software.
Definition User.php:129
A service to expand, parse, and otherwise manipulate URLs.
Definition UrlUtils.php:16
Interface for configuration instances.
Definition Config.php:18
Interface for sending arbitrary emails.
Definition IEmailer.php:20
getRealName()
Get the user's real name or an empty string if unknown.
getUser()
Get the identity of the user this contact belongs to.
This interface represents the authority associated with the current execution context,...
Definition Authority.php:23
$source