MediaWiki master
RecentChangeMailComposer.php
Go to the documentation of this file.
1<?php
8
24
32
36 public const USER_TALK = 'user_talk';
40 public const WATCHLIST = 'watchlist';
44 public const ALL_CHANGES = 'all_changes';
45
46 protected string $subject = '';
47
48 protected string $body = '';
49
50 protected string $summary = '';
51
53
54 protected ?MailAddress $from;
55
56 protected bool $composed_common = false;
57
59 protected array $mailTargets = [];
60
61 protected ?bool $minorEdit;
62
64 protected $oldid;
65
66 protected string $timestamp;
67
68 protected string $pageStatus = '';
69
70 protected Title $title;
71
72 protected User $editor;
73
74 private Config $mainConfig;
75 private UserOptionsLookup $userOptionsLookup;
76 private UrlUtils $urlUtils;
77 private MessageParser $messageParser;
78 private Language $contentLanguage;
79 private IEmailer $emailer;
80
81 public function __construct(
84 RecentChange $recentChange,
85 string $pageStatus
86 ) {
88 $this->editor = $services->getUserFactory()->newFromAuthority( $editor );
89 $this->title = $title;
90 $this->oldid = $recentChange->getAttribute( 'rc_last_oldid' );
91 $this->minorEdit = $recentChange->getAttribute( 'rc_minor' );
92 $this->timestamp = $recentChange->getAttribute( 'rc_timestamp' );
93 $this->summary = $recentChange->getAttribute( 'rc_comment' );
94 $this->pageStatus = $pageStatus;
95
96 // Prepare for dependency injection
97 $this->mainConfig = $services->getMainConfig();
98 $this->userOptionsLookup = $services->getUserOptionsLookup();
99 $this->urlUtils = $services->getUrlUtils();
100 $this->messageParser = $services->getMessageParser();
101 $this->contentLanguage = $services->getContentLanguage();
102 $this->emailer = $services->getEmailer();
103 }
104
108 private function composeCommonMailtext() {
109 $this->composed_common = true;
110
111 # You as the WikiAdmin and Sysops can make use of plenty of
112 # named variables when composing your notification emails while
113 # simply editing the Meta pages
114
115 $keys = [];
116 $postTransformKeys = [];
117 $pageTitleUrl = $this->title->getCanonicalURL();
118 $pageTitle = $this->title->getPrefixedText();
119
120 if ( $this->oldid ) {
121 // Always show a link to the diff which triggered the mail. See T34210.
122 $keys['$NEWPAGE'] = "\n\n" . wfMessage(
123 'enotif_lastdiff',
124 $this->title->getCanonicalURL( [ 'diff' => 'next', 'oldid' => $this->oldid ] )
125 )->inContentLanguage()->text();
126
127 // For personal mail, also show a link to the diff of all changes
128 // since last visited.
129 $keys['$NEWPAGE'] .= "\n\n" . wfMessage(
130 'enotif_lastvisited',
131 $this->title->getCanonicalURL( [ 'diff' => '0', 'oldid' => $this->oldid ] )
132 )->inContentLanguage()->text();
133 $keys['$OLDID'] = $this->oldid;
134 $keys['$PAGELOG'] = '';
135 } else {
136 // If there is no revision to link to, link to the page log, which should have details. See T115183.
137 $keys['$OLDID'] = '';
138 $keys['$NEWPAGE'] = '';
139 $keys['$PAGELOG'] = "\n\n" . wfMessage(
140 'enotif_pagelog',
141 SpecialPage::getTitleFor( 'Log' )->getCanonicalURL( [ 'page' =>
142 $this->title->getPrefixedDBkey() ] )
143 )->inContentLanguage()->text();
144 }
145
146 $keys['$PAGETITLE'] = $this->title->getPrefixedText();
147 $keys['$PAGETITLE_URL'] = $this->title->getCanonicalURL();
148 $keys['$PAGEMINOREDIT'] = $this->minorEdit ?
149 "\n\n" . wfMessage( 'enotif_minoredit' )->inContentLanguage()->text() :
150 '';
151 $keys['$UNWATCHURL'] = $this->title->getCanonicalURL( 'action=unwatch' );
152
153 if ( $this->editor->isAnon() ) {
154 # real anon (user:xxx.xxx.xxx.xxx)
155 $keys['$PAGEEDITOR'] = wfMessage( 'enotif_anon_editor', $this->editor->getName() )
156 ->inContentLanguage()->text();
157 $keys['$PAGEEDITOR_EMAIL'] = wfMessage( 'noemailtitle' )->inContentLanguage()->text();
158 } elseif ( $this->editor->isTemp() ) {
159 $keys['$PAGEEDITOR'] = wfMessage( 'enotif_temp_editor', $this->editor->getName() )
160 ->inContentLanguage()->text();
161 $keys['$PAGEEDITOR_EMAIL'] = wfMessage( 'noemailtitle' )->inContentLanguage()->text();
162 } else {
163 $keys['$PAGEEDITOR'] = $this->mainConfig->get( MainConfigNames::EnotifUseRealName ) &&
164 $this->editor->getRealName() !== ''
165 ? $this->editor->getRealName() : $this->editor->getName();
166 $emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $this->editor->getName() );
167 $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getCanonicalURL();
168 }
169
170 $keys['$PAGEEDITOR_WIKI'] = $this->editor->getTalkPage()->getCanonicalURL();
171 $keys['$HELPPAGE'] = $this->urlUtils->expand(
172 Skin::makeInternalOrExternalUrl( wfMessage( 'helppage' )->inContentLanguage()->text() ),
174 ) ?? false;
175
176 # Replace this after transforming the message, T37019
177 $postTransformKeys['$PAGESUMMARY'] = $this->summary == '' ? ' - ' : $this->summary;
178
179 // Now build message's subject and body
180
181 // Messages:
182 // enotif_subject_deleted, enotif_subject_created, enotif_subject_moved,
183 // enotif_subject_restored, enotif_subject_changed
184 $this->subject = wfMessage( 'enotif_subject_' . $this->pageStatus )->inContentLanguage()
185 ->params( $pageTitle, $keys['$PAGEEDITOR'] )->text();
186
187 // Messages:
188 // enotif_body_intro_deleted, enotif_body_intro_created, enotif_body_intro_moved,
189 // enotif_body_intro_restored, enotif_body_intro_changed
190 $keys['$PAGEINTRO'] = wfMessage( 'enotif_body_intro_' . $this->pageStatus )
191 ->inContentLanguage()
192 ->params( $pageTitle, $keys['$PAGEEDITOR'], "<{$pageTitleUrl}>" )
193 ->text();
194
195 $body = wfMessage( 'enotif_body' )->inContentLanguage()->plain();
196 $body = strtr( $body, $keys );
197 $body = $this->messageParser->transform( $body, false, null, $this->title );
198 $this->body = wordwrap( strtr( $body, $postTransformKeys ), 72 );
199
200 # Reveal the page editor's address as REPLY-TO address only if
201 # the user has not opted-out and the option is enabled at the
202 # global configuration level.
203 $adminAddress = new MailAddress(
204 $this->mainConfig->get( MainConfigNames::PasswordSender ),
205 wfMessage( 'emailsender' )->inContentLanguage()->text()
206 );
207 if ( $this->mainConfig->get( MainConfigNames::EnotifRevealEditorAddress )
208 && ( $this->editor->getEmail() != '' )
209 && $this->userOptionsLookup->getOption( $this->editor, 'enotifrevealaddr' )
210 ) {
211 $editorAddress = MailAddress::newFromUser( $this->editor );
212 if ( $this->mainConfig->get( MainConfigNames::EnotifFromEditor ) ) {
213 $this->from = $editorAddress;
214 } else {
215 $this->from = $adminAddress;
216 $this->replyto = $editorAddress;
217 }
218 } else {
219 $this->from = $adminAddress;
220 $this->replyto = new MailAddress(
221 $this->mainConfig->get( MainConfigNames::NoReplyAddress )
222 );
223 }
224 }
225
232 public function compose( UserEmailContact $watchingUser, $source ) {
233 if ( !$this->composed_common ) {
234 $this->composeCommonMailtext();
235 }
236
237 // From the PHP manual:
238 // Note: The to parameter cannot be an address in the form of
239 // "Something <someone@example.com>". The mail command will not parse
240 // this properly while talking with the MTA.
241 $to = MailAddress::newFromUser( $watchingUser );
242
243 # $PAGEEDITDATE is the time and date of the page change
244 # expressed in terms of individual local time of the notification
245 # recipient, i.e. watching user
246 $watchingUserName = (
247 $this->mainConfig->get( MainConfigNames::EnotifUseRealName ) &&
248 $watchingUser->getRealName() !== ''
249 ) ? $watchingUser->getRealName() : $watchingUser->getUser()->getName();
250 $body = str_replace(
251 [
252 '$WATCHINGUSERNAME',
253 '$PAGEEDITDATE',
254 '$PAGEEDITTIME'
255 ],
256 [
257 $watchingUserName,
258 $this->contentLanguage->userDate( $this->timestamp, $watchingUser->getUser() ),
259 $this->contentLanguage->userTime( $this->timestamp, $watchingUser->getUser() )
260 ],
261 $this->body
262 );
263
264 $headers = [];
265 if ( $source === self::WATCHLIST ) {
266 $headers['List-Help'] = 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Watchlist';
267 }
268
269 $this->emailer->send(
270 [ $to ],
271 $this->from,
272 $this->subject,
273 $body,
274 null,
275 [
276 'replyTo' => $this->replyto,
277 'headers' => $headers,
278 ]
279 );
280 }
281}
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:69
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:43
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:108
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 user 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