Index: trunk/phase3/includes/UserMailer.php |
— | — | @@ -242,108 +242,31 @@ |
243 | 243 | } |
244 | 244 | } |
245 | 245 | |
246 | | - |
| 246 | +/** |
| 247 | + * This module processes the email notifications when the current page is |
| 248 | + * changed. It looks up the table watchlist to find out which users are watching |
| 249 | + * that page. |
| 250 | + * |
| 251 | + * The current implementation sends independent emails to each watching user for |
| 252 | + * the following reason: |
| 253 | + * |
| 254 | + * - Each watching user will be notified about the page edit time expressed in |
| 255 | + * his/her local time (UTC is shown additionally). To achieve this, we need to |
| 256 | + * find the individual timeoffset of each watching user from the preferences.. |
| 257 | + * |
| 258 | + * Suggested improvement to slack down the number of sent emails: We could think |
| 259 | + * of sending out bulk mails (bcc:user1,user2...) for all these users having the |
| 260 | + * same timeoffset in their preferences. |
| 261 | + * |
| 262 | + * Visit the documentation pages under http://meta.wikipedia.com/Enotif |
| 263 | + * |
| 264 | + * |
| 265 | + */ |
247 | 266 | class EmailNotification { |
248 | | - |
249 | | - /* |
250 | | - * Send users an email. |
251 | | - * |
252 | | - * @param $editor User whose action precipitated the notification. |
253 | | - * @param $timestamp of the event. |
254 | | - * @param Callback that returns an an array of Users who will recieve the notification. |
255 | | - * @param Callback that returns an array($keys, $body, $subject) where |
256 | | - * * $keys is a dictionary whose keys will be replaced with the corresponding |
257 | | - * values within the subject and body of the message. |
258 | | - * * $body is the name of the message that will be used for the email body. |
259 | | - * * $subject is the name of the message that will be used for the subject. |
260 | | - * Both messages are resolved using the content language. |
261 | | - * The messageCompositionFunction is invoked for each recipient user; |
262 | | - * The keys returned are merged with those given by EmailNotification::commonMessageKeys(). |
263 | | - * The recipient is appended to the arguments given to messageCompositionFunction. |
264 | | - * Both callbacks are to be given in the same formats accepted by the hook system. |
265 | | - */ |
266 | | - function notify($editor, $timestamp, $userListFunction, $messageCompositionFunction) { |
267 | | - global $wgEnotifUseRealName, $wgEnotifImpersonal; |
268 | | - global $wgLang; |
| 267 | + private $to, $subject, $body, $replyto, $from; |
| 268 | + private $user, $title, $timestamp, $summary, $minorEdit, $oldid, $composed_common, $editor; |
| 269 | + private $mailTargets = array(); |
269 | 270 | |
270 | | - $common_keys = self::commonMessageKeys($editor); |
271 | | - $users = wfInvoke($userListFunction); |
272 | | - foreach($users as $u) { |
273 | | - list($user_keys, $body_msg_name, $subj_msg_name) = |
274 | | - wfInvoke($messageCompositionFunction, array($u)); |
275 | | - $keys = array_merge($common_keys, $user_keys); |
276 | | - |
277 | | - if( $wgEnotifImpersonal ) { |
278 | | - $keys['$WATCHINGUSERNAME'] = wfMsgForContent('enotif_impersonal_salutation'); |
279 | | - $keys['$PAGEEDITDATE'] = $wgLang->timeanddate($timestamp, true, false, false); |
280 | | - } else { |
281 | | - $keys['$WATCHINGUSERNAME'] = $wgEnotifUseRealName ? $u->getRealName() : $u->getName(); |
282 | | - $keys['$PAGEEDITDATE'] = $wgLang->timeAndDate($timestamp, true, false, |
283 | | - $u->getOption('timecorrection')); |
284 | | - } |
285 | | - |
286 | | - $subject = strtr(wfMsgForContent( $subj_msg_name ), $keys); |
287 | | - $body = wordwrap( strtr( wfMsgForContent( $body_msg_name ), $keys ), 72 ); |
288 | | - |
289 | | - $to = new MailAddress($u); |
290 | | - $from = $keys['$FROM_HEADER']; |
291 | | - $replyto = $keys['$REPLYTO_HEADER']; |
292 | | - UserMailer::send($to, $from, $subject, $body, $replyto); |
293 | | - } |
294 | | - } |
295 | | - |
296 | | - |
297 | | - static function commonMessageKeys($editor) { |
298 | | - global $wgEnotifUseRealName, $wgEnotifRevealEditorAddress; |
299 | | - global $wgNoReplyAddress, $wgPasswordSender; |
300 | | - |
301 | | - $keys = array(); |
302 | | - |
303 | | - $name = $wgEnotifUseRealName ? $editor->getRealName() : $editor->getName(); |
304 | | - |
305 | | - $adminAddress = new MailAddress( $wgPasswordSender, 'WikiAdmin' ); |
306 | | - $editorAddress = new MailAddress( $editor ); |
307 | | - if( $wgEnotifRevealEditorAddress |
308 | | - && $editor->getEmail() != '' |
309 | | - && $editor->getOption( 'enotifrevealaddr' ) ) { |
310 | | - if( $wgEnotifFromEditor ) { |
311 | | - $from = $editorAddress; |
312 | | - } else { |
313 | | - $from = $adminAddress; |
314 | | - $replyto = $editorAddress; |
315 | | - } |
316 | | - } else { |
317 | | - $from = $adminAddress; |
318 | | - $replyto = new MailAddress( $wgNoReplyAddress ); |
319 | | - } |
320 | | - $keys['$FROM_HEADER'] = $from; |
321 | | - $keys['$REPLYTO_HEADER'] = $replyto; |
322 | | - |
323 | | - if( $editor->isAnon() ) { |
324 | | - $keys['$PAGEEDITOR'] = wfMsgForContent('enotif_anon_editor', $name); |
325 | | - $keys['$PAGEEDITOR_EMAIL'] = wfMsgForContent( 'noemailtitle' ); |
326 | | - } else{ |
327 | | - $keys['$PAGEEDITOR'] = $name; |
328 | | - $keys['$PAGEEDITOR_EMAIL'] = SpecialPage::getSafeTitleFor('Emailuser', $name)->getFullUrl(); |
329 | | - } |
330 | | - $keys['$PAGEEDITOR_WIKI'] = $editor->getUserPage()->getFullUrl(); |
331 | | - |
332 | | - return $keys; |
333 | | - } |
334 | | - |
335 | | - |
336 | | - |
337 | | - /* |
338 | | - * @deprecated |
339 | | - * Use PageChangeNotification::notifyOnPageChange instead. |
340 | | - */ |
341 | | - function notifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid = false) { |
342 | | - PageChangeNotification::notifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid); |
343 | | - } |
344 | | -} |
345 | | - |
346 | | -class PageChangeNotification { |
347 | | - |
348 | 271 | /** |
349 | 272 | * Send emails corresponding to the user $editor editing the page $title. |
350 | 273 | * Also updates wl_notificationtimestamp. |
— | — | @@ -357,7 +280,7 @@ |
358 | 281 | * @param $minorEdit |
359 | 282 | * @param $oldid (default: false) |
360 | 283 | */ |
361 | | - static function notifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid = false) { |
| 284 | + function notifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid = false) { |
362 | 285 | global $wgEnotifUseJobQ; |
363 | 286 | |
364 | 287 | if( $title->getNamespace() < 0 ) |
— | — | @@ -374,7 +297,7 @@ |
375 | 298 | $job = new EnotifNotifyJob( $title, $params ); |
376 | 299 | $job->insert(); |
377 | 300 | } else { |
378 | | - self::actuallyNotifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid); |
| 301 | + $this->actuallyNotifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid); |
379 | 302 | } |
380 | 303 | |
381 | 304 | } |
— | — | @@ -392,16 +315,94 @@ |
393 | 316 | * @param $minorEdit |
394 | 317 | * @param $oldid (default: false) |
395 | 318 | */ |
396 | | - static function actuallyNotifyOnPageChange($editor, $title, $timestamp, |
397 | | - $summary, $minorEdit, $oldid=false) { |
398 | | - global $wgShowUpdatedMarker, $wgEnotifWatchlist; |
399 | | - |
| 319 | + function actuallyNotifyOnPageChange($editor, $title, $timestamp, $summary, $minorEdit, $oldid=false) { |
| 320 | + |
| 321 | + # we use $wgPasswordSender as sender's address |
| 322 | + global $wgEnotifWatchlist; |
| 323 | + global $wgEnotifMinorEdits, $wgEnotifUserTalk, $wgShowUpdatedMarker; |
| 324 | + global $wgEnotifImpersonal; |
| 325 | + |
400 | 326 | wfProfileIn( __METHOD__ ); |
401 | | - |
402 | | - EmailNotification::notify($editor, $timestamp, |
403 | | - array('PageChangeNotification::usersList', array($editor, $title, $minorEdit)), |
404 | | - array('PageChangeNotification::message', array($oldid, $minorEdit, $summary, $title, $editor) ) ); |
405 | | - |
| 327 | + |
| 328 | + # The following code is only run, if several conditions are met: |
| 329 | + # 1. EmailNotification for pages (other than user_talk pages) must be enabled |
| 330 | + # 2. minor edits (changes) are only regarded if the global flag indicates so |
| 331 | + |
| 332 | + $isUserTalkPage = ($title->getNamespace() == NS_USER_TALK); |
| 333 | + $enotifusertalkpage = ($isUserTalkPage && $wgEnotifUserTalk); |
| 334 | + $enotifwatchlistpage = $wgEnotifWatchlist; |
| 335 | + |
| 336 | + $this->title = $title; |
| 337 | + $this->timestamp = $timestamp; |
| 338 | + $this->summary = $summary; |
| 339 | + $this->minorEdit = $minorEdit; |
| 340 | + $this->oldid = $oldid; |
| 341 | + $this->editor = $editor; |
| 342 | + $this->composed_common = false; |
| 343 | + |
| 344 | + $userTalkId = false; |
| 345 | + |
| 346 | + if ( (!$minorEdit || $wgEnotifMinorEdits) ) { |
| 347 | + if ( $wgEnotifUserTalk && $isUserTalkPage ) { |
| 348 | + $targetUser = User::newFromName( $title->getText() ); |
| 349 | + if ( !$targetUser || $targetUser->isAnon() ) { |
| 350 | + wfDebug( __METHOD__.": user talk page edited, but user does not exist\n" ); |
| 351 | + } elseif ( $targetUser->getId() == $editor->getId() ) { |
| 352 | + wfDebug( __METHOD__.": user edited their own talk page, no notification sent\n" ); |
| 353 | + } elseif( $targetUser->getOption( 'enotifusertalkpages' ) ) { |
| 354 | + if( $targetUser->isEmailConfirmed() ) { |
| 355 | + wfDebug( __METHOD__.": sending talk page update notification\n" ); |
| 356 | + $this->compose( $targetUser ); |
| 357 | + $userTalkId = $targetUser->getId(); |
| 358 | + } else { |
| 359 | + wfDebug( __METHOD__.": talk page owner doesn't have validated email\n" ); |
| 360 | + } |
| 361 | + } else { |
| 362 | + wfDebug( __METHOD__.": talk page owner doesn't want notifications\n" ); |
| 363 | + } |
| 364 | + } |
| 365 | + |
| 366 | + if ( $wgEnotifWatchlist ) { |
| 367 | + // Send updates to watchers other than the current editor |
| 368 | + $userCondition = 'wl_user != ' . $editor->getID(); |
| 369 | + if ( $userTalkId !== false ) { |
| 370 | + // Already sent an email to this person |
| 371 | + $userCondition .= ' AND wl_user != ' . intval( $userTalkId ); |
| 372 | + } |
| 373 | + $dbr = wfGetDB( DB_SLAVE ); |
| 374 | + |
| 375 | + list( $user ) = $dbr->tableNamesN( 'user' ); |
| 376 | + |
| 377 | + $res = $dbr->select( array( 'watchlist', 'user' ), |
| 378 | + array( "$user.*" ), |
| 379 | + array( |
| 380 | + 'wl_user=user_id', |
| 381 | + 'wl_title' => $title->getDBkey(), |
| 382 | + 'wl_namespace' => $title->getNamespace(), |
| 383 | + $userCondition, |
| 384 | + 'wl_notificationtimestamp IS NULL', |
| 385 | + ), __METHOD__ ); |
| 386 | + $userArray = UserArray::newFromResult( $res ); |
| 387 | + |
| 388 | + foreach ( $userArray as $watchingUser ) { |
| 389 | + if ( $watchingUser->getOption( 'enotifwatchlistpages' ) && |
| 390 | + ( !$minorEdit || $watchingUser->getOption('enotifminoredits') ) && |
| 391 | + $watchingUser->isEmailConfirmed() ) |
| 392 | + { |
| 393 | + $this->compose( $watchingUser ); |
| 394 | + } |
| 395 | + } |
| 396 | + } |
| 397 | + } |
| 398 | + |
| 399 | + global $wgUsersNotifiedOnAllChanges; |
| 400 | + foreach ( $wgUsersNotifiedOnAllChanges as $name ) { |
| 401 | + $user = User::newFromName( $name ); |
| 402 | + $this->compose( $user ); |
| 403 | + } |
| 404 | + |
| 405 | + $this->sendMails(); |
| 406 | + |
406 | 407 | $latestTimestamp = Revision::getTimestampFromId( $title, $title->getLatestRevID() ); |
407 | 408 | // Do not update watchlists if something else already did. |
408 | 409 | if ( $timestamp >= $latestTimestamp && ($wgShowUpdatedMarker || $wgEnotifWatchlist) ) { |
— | — | @@ -422,22 +423,38 @@ |
423 | 424 | } |
424 | 425 | |
425 | 426 | wfProfileOut( __METHOD__ ); |
426 | | - } |
427 | | - |
428 | | - |
429 | | - static function message( $stuff ) { |
430 | | - global $wgEnotifImpersonal; |
| 427 | + } # function NotifyOnChange |
431 | 428 | |
432 | | - list($oldid, $medit, $summary, $title, $user) = $stuff; |
433 | | - $keys = array(); |
| 429 | + /** |
| 430 | + * @private |
| 431 | + */ |
| 432 | + function composeCommonMailtext() { |
| 433 | + global $wgPasswordSender, $wgNoReplyAddress; |
| 434 | + global $wgEnotifFromEditor, $wgEnotifRevealEditorAddress; |
| 435 | + global $wgEnotifImpersonal, $wgEnotifUseRealName; |
434 | 436 | |
| 437 | + $this->composed_common = true; |
| 438 | + |
| 439 | + $summary = ($this->summary == '') ? ' - ' : $this->summary; |
| 440 | + $medit = ($this->minorEdit) ? wfMsg( 'minoredit' ) : ''; |
| 441 | + |
| 442 | + # You as the WikiAdmin and Sysops can make use of plenty of |
| 443 | + # named variables when composing your notification emails while |
| 444 | + # simply editing the Meta pages |
| 445 | + |
| 446 | + $subject = wfMsgForContent( 'enotif_subject' ); |
| 447 | + $body = wfMsgForContent( 'enotif_body' ); |
| 448 | + $from = ''; /* fail safe */ |
| 449 | + $replyto = ''; /* fail safe */ |
| 450 | + $keys = array(); |
| 451 | + |
435 | 452 | # regarding the use of oldid as an indicator for the last visited version, see also |
436 | 453 | # http://bugzilla.wikipeda.org/show_bug.cgi?id=603 "Delete + undelete cycle doesn't preserve old_id" |
437 | 454 | # However, in the case of a new page which is already watched, we have no previous version to compare |
438 | | - if( $oldid ) { |
439 | | - $difflink = $title->getFullUrl( 'diff=0&oldid=' . $oldid ); |
| 455 | + if( $this->oldid ) { |
| 456 | + $difflink = $this->title->getFullUrl( 'diff=0&oldid=' . $this->oldid ); |
440 | 457 | $keys['$NEWPAGE'] = wfMsgForContent( 'enotif_lastvisited', $difflink ); |
441 | | - $keys['$OLDID'] = $oldid; |
| 458 | + $keys['$OLDID'] = $this->oldid; |
442 | 459 | $keys['$CHANGEDORCREATED'] = wfMsgForContent( 'changed' ); |
443 | 460 | } else { |
444 | 461 | $keys['$NEWPAGE'] = wfMsgForContent( 'enotif_newpagetext' ); |
— | — | @@ -446,92 +463,151 @@ |
447 | 464 | $keys['$CHANGEDORCREATED'] = wfMsgForContent( 'created' ); |
448 | 465 | } |
449 | 466 | |
450 | | - if ($wgEnotifImpersonal && $oldid) { |
451 | | - # For impersonal mail, show a diff link to the last revision. |
| 467 | + if ($wgEnotifImpersonal && $this->oldid) |
| 468 | + /* |
| 469 | + * For impersonal mail, show a diff link to the last |
| 470 | + * revision. |
| 471 | + */ |
452 | 472 | $keys['$NEWPAGE'] = wfMsgForContent('enotif_lastdiff', |
453 | | - $title->getFullURL("oldid={$oldid}&diff=prev")); |
454 | | - } |
| 473 | + $this->title->getFullURL("oldid={$this->oldid}&diff=prev")); |
455 | 474 | |
456 | | - $keys['$PAGETITLE'] = $title->getPrefixedText(); |
457 | | - $keys['$PAGETITLE_URL'] = $title->getFullUrl(); |
458 | | - $keys['$PAGEMINOREDIT'] = $medit ? wfMsg( 'minoredit' ) : ''; |
459 | | - $keys['$PAGESUMMARY'] = ($summary == '') ? ' - ' : $summary; |
| 475 | + $body = strtr( $body, $keys ); |
| 476 | + $pagetitle = $this->title->getPrefixedText(); |
| 477 | + $keys['$PAGETITLE'] = $pagetitle; |
| 478 | + $keys['$PAGETITLE_URL'] = $this->title->getFullUrl(); |
460 | 479 | |
461 | | - return array($keys, 'enotif_body', 'enotif_subject'); |
462 | | - } |
| 480 | + $keys['$PAGEMINOREDIT'] = $medit; |
| 481 | + $keys['$PAGESUMMARY'] = $summary; |
463 | 482 | |
464 | | - static function usersList($stuff) { |
465 | | - global $wgEnotifWatchlist, $wgEnotifMinorEdits, $wgUsersNotifiedOnAllChanges; |
| 483 | + $subject = strtr( $subject, $keys ); |
466 | 484 | |
467 | | - list($editor, $title, $minorEdit) = $stuff; |
468 | | - $recipients = array(); |
| 485 | + # Reveal the page editor's address as REPLY-TO address only if |
| 486 | + # the user has not opted-out and the option is enabled at the |
| 487 | + # global configuration level. |
| 488 | + $editor = $this->editor; |
| 489 | + $name = $wgEnotifUseRealName ? $editor->getRealName() : $editor->getName(); |
| 490 | + $adminAddress = new MailAddress( $wgPasswordSender, 'WikiAdmin' ); |
| 491 | + $editorAddress = new MailAddress( $editor ); |
| 492 | + if( $wgEnotifRevealEditorAddress |
| 493 | + && ( $editor->getEmail() != '' ) |
| 494 | + && $editor->getOption( 'enotifrevealaddr' ) ) { |
| 495 | + if( $wgEnotifFromEditor ) { |
| 496 | + $from = $editorAddress; |
| 497 | + } else { |
| 498 | + $from = $adminAddress; |
| 499 | + $replyto = $editorAddress; |
| 500 | + } |
| 501 | + } else { |
| 502 | + $from = $adminAddress; |
| 503 | + $replyto = new MailAddress( $wgNoReplyAddress ); |
| 504 | + } |
469 | 505 | |
470 | | - # User talk pages: |
471 | | - $userTalkId = false; |
472 | | - if( $title->getNamespace() == NS_USER_TALK && (!$minorEdit || $wgEnotifMinorEdits) ) { |
473 | | - $targetUser = User::newFromName($title->getText()); |
| 506 | + if( $editor->isIP( $name ) ) { |
| 507 | + #real anon (user:xxx.xxx.xxx.xxx) |
| 508 | + $utext = wfMsgForContent('enotif_anon_editor', $name); |
| 509 | + $subject = str_replace('$PAGEEDITOR', $utext, $subject); |
| 510 | + $keys['$PAGEEDITOR'] = $utext; |
| 511 | + $keys['$PAGEEDITOR_EMAIL'] = wfMsgForContent( 'noemailtitle' ); |
| 512 | + } else { |
| 513 | + $subject = str_replace('$PAGEEDITOR', $name, $subject); |
| 514 | + $keys['$PAGEEDITOR'] = $name; |
| 515 | + $emailPage = SpecialPage::getSafeTitleFor( 'Emailuser', $name ); |
| 516 | + $keys['$PAGEEDITOR_EMAIL'] = $emailPage->getFullUrl(); |
| 517 | + } |
| 518 | + $userPage = $editor->getUserPage(); |
| 519 | + $keys['$PAGEEDITOR_WIKI'] = $userPage->getFullUrl(); |
| 520 | + $body = strtr( $body, $keys ); |
| 521 | + $body = wordwrap( $body, 72 ); |
474 | 522 | |
475 | | - if ( !$targetUser || $targetUser->isAnon() ) |
476 | | - $msg = "user talk page edited, but user does not exist"; |
| 523 | + # now save this as the constant user-independent part of the message |
| 524 | + $this->from = $from; |
| 525 | + $this->replyto = $replyto; |
| 526 | + $this->subject = $subject; |
| 527 | + $this->body = $body; |
| 528 | + } |
477 | 529 | |
478 | | - else if ( $targetUser->getId() == $editor->getId() ) |
479 | | - $msg = "user edited their own talk page, no notification sent"; |
| 530 | + /** |
| 531 | + * Compose a mail to a given user and either queue it for sending, or send it now, |
| 532 | + * depending on settings. |
| 533 | + * |
| 534 | + * Call sendMails() to send any mails that were queued. |
| 535 | + */ |
| 536 | + function compose( $user ) { |
| 537 | + global $wgEnotifImpersonal; |
480 | 538 | |
481 | | - else if ( !$targetUser->getOption('enotifusertalkpages') ) |
482 | | - $msg = "talk page owner doesn't want notifications"; |
| 539 | + if ( !$this->composed_common ) |
| 540 | + $this->composeCommonMailtext(); |
483 | 541 | |
484 | | - else if ( !$targetUser->isEmailConfirmed() ) |
485 | | - $msg = "talk page owner doesn't have validated email"; |
| 542 | + if ( $wgEnotifImpersonal ) { |
| 543 | + $this->mailTargets[] = new MailAddress( $user ); |
| 544 | + } else { |
| 545 | + $this->sendPersonalised( $user ); |
| 546 | + } |
| 547 | + } |
486 | 548 | |
487 | | - else { |
488 | | - $msg = "sending talk page update notification"; |
489 | | - $recipients[] = $targetUser; |
490 | | - $userTalkId = $targetUser->getId(); # won't be included in watchlist, below. |
491 | | - } |
492 | | - wfDebug( __METHOD__ .": ". $msg . "\n" ); |
| 549 | + /** |
| 550 | + * Send any queued mails |
| 551 | + */ |
| 552 | + function sendMails() { |
| 553 | + global $wgEnotifImpersonal; |
| 554 | + if ( $wgEnotifImpersonal ) { |
| 555 | + $this->sendImpersonal( $this->mailTargets ); |
493 | 556 | } |
494 | | - wfDebug("Did not send a user-talk notification.\n"); |
| 557 | + } |
495 | 558 | |
496 | | - if( $wgEnotifWatchlist && (!$minorEdit || $wgEnotifMinorEdits) ) { |
497 | | - // Send updates to watchers other than the current editor |
498 | | - $userCondition = 'wl_user != ' . $editor->getID(); |
| 559 | + /** |
| 560 | + * Does the per-user customizations to a notification e-mail (name, |
| 561 | + * timestamp in proper timezone, etc) and sends it out. |
| 562 | + * Returns true if the mail was sent successfully. |
| 563 | + * |
| 564 | + * @param User $watchingUser |
| 565 | + * @param object $mail |
| 566 | + * @return bool |
| 567 | + * @private |
| 568 | + */ |
| 569 | + function sendPersonalised( $watchingUser ) { |
| 570 | + global $wgLang, $wgEnotifUseRealName; |
| 571 | + // From the PHP manual: |
| 572 | + // Note: The to parameter cannot be an address in the form of "Something <someone@example.com>". |
| 573 | + // The mail command will not parse this properly while talking with the MTA. |
| 574 | + $to = new MailAddress( $watchingUser ); |
| 575 | + $name = $wgEnotifUseRealName ? $watchingUser->getRealName() : $watchingUser->getName(); |
| 576 | + $body = str_replace( '$WATCHINGUSERNAME', $name , $this->body ); |
499 | 577 | |
500 | | - if ( $userTalkId !== false ) { |
501 | | - // Already sent an email to this person |
502 | | - $userCondition .= ' AND wl_user != ' . intval( $userTalkId ); |
503 | | - } |
504 | | - $dbr = wfGetDB( DB_SLAVE ); |
| 578 | + $timecorrection = $watchingUser->getOption( 'timecorrection' ); |
505 | 579 | |
506 | | - list( $user ) = $dbr->tableNamesN( 'user' ); |
| 580 | + # $PAGEEDITDATE is the time and date of the page change |
| 581 | + # expressed in terms of individual local time of the notification |
| 582 | + # recipient, i.e. watching user |
| 583 | + $body = str_replace('$PAGEEDITDATE', |
| 584 | + $wgLang->timeanddate( $this->timestamp, true, false, $timecorrection ), |
| 585 | + $body); |
507 | 586 | |
508 | | - $res = $dbr->select( array( 'watchlist', 'user' ), |
509 | | - array( "$user.*" ), |
510 | | - array( |
511 | | - 'wl_user=user_id', |
512 | | - 'wl_title' => $title->getDBkey(), |
513 | | - 'wl_namespace' => $title->getNamespace(), |
514 | | - $userCondition, |
515 | | - 'wl_notificationtimestamp IS NULL', |
516 | | - ), __METHOD__ ); |
517 | | - $userArray = UserArray::newFromResult( $res ); |
| 587 | + return UserMailer::send($to, $this->from, $this->subject, $body, $this->replyto); |
| 588 | + } |
518 | 589 | |
519 | | - foreach ( $userArray as $watchingUser ) { |
520 | | - if ( $watchingUser->getOption( 'enotifwatchlistpages' ) && |
521 | | - ( !$minorEdit || $watchingUser->getOption('enotifminoredits') ) && |
522 | | - $watchingUser->isEmailConfirmed() ) { |
523 | | - $recipients[] = $watchingUser; |
524 | | - } |
525 | | - } |
526 | | - } |
| 590 | + /** |
| 591 | + * Same as sendPersonalised but does impersonal mail suitable for bulk |
| 592 | + * mailing. Takes an array of MailAddress objects. |
| 593 | + */ |
| 594 | + function sendImpersonal( $addresses ) { |
| 595 | + global $wgLang; |
527 | 596 | |
528 | | - foreach ( $wgUsersNotifiedOnAllChanges as $name ) { |
529 | | - $recipients[] = User::newFromName($name); |
530 | | - } |
| 597 | + if (empty($addresses)) |
| 598 | + return; |
531 | 599 | |
532 | | - return $recipients; |
| 600 | + $body = str_replace( |
| 601 | + array( '$WATCHINGUSERNAME', |
| 602 | + '$PAGEEDITDATE'), |
| 603 | + array( wfMsgForContent('enotif_impersonal_salutation'), |
| 604 | + $wgLang->timeanddate($this->timestamp, true, false, false)), |
| 605 | + $this->body); |
| 606 | + |
| 607 | + return UserMailer::send($addresses, $this->from, $this->subject, $body, $this->replyto); |
533 | 608 | } |
534 | | -} |
535 | 609 | |
| 610 | +} # end of class EmailNotification |
| 611 | + |
536 | 612 | /** |
537 | 613 | * Backwards compatibility functions |
538 | 614 | */ |
Index: trunk/phase3/includes/RecentChange.php |
— | — | @@ -184,8 +184,10 @@ |
185 | 185 | $editor = ($wgUser->getName() == $this->mAttribs['rc_user_text']) ? |
186 | 186 | $wgUser : User::newFromName( $this->mAttribs['rc_user_text'], false ); |
187 | 187 | } |
| 188 | + # FIXME: this would be better as an extension hook |
| 189 | + $enotif = new EmailNotification(); |
188 | 190 | $title = Title::makeTitle( $this->mAttribs['rc_namespace'], $this->mAttribs['rc_title'] ); |
189 | | - PageChangeNotification::notifyOnPageChange( $editor, $title, |
| 191 | + $enotif->notifyOnPageChange( $editor, $title, |
190 | 192 | $this->mAttribs['rc_timestamp'], |
191 | 193 | $this->mAttribs['rc_comment'], |
192 | 194 | $this->mAttribs['rc_minor'], |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -55,7 +55,6 @@ |
56 | 56 | 'EditPage' => 'includes/EditPage.php', |
57 | 57 | 'EmaillingJob' => 'includes/EmaillingJob.php', |
58 | 58 | 'EmailNotification' => 'includes/UserMailer.php', |
59 | | - 'PageChangeNotification' => 'includes/UserMailer.php', |
60 | 59 | 'EnhancedChangesList' => 'includes/ChangesList.php', |
61 | 60 | 'EnotifNotifyJob' => 'includes/EnotifNotifyJob.php', |
62 | 61 | 'ErrorPageError' => 'includes/Exception.php', |
Index: trunk/phase3/includes/EnotifNotifyJob.php |
— | — | @@ -12,6 +12,7 @@ |
13 | 13 | } |
14 | 14 | |
15 | 15 | function run() { |
| 16 | + $enotif = new EmailNotification(); |
16 | 17 | // Get the user from ID (rename safe). Anons are 0, so defer to name. |
17 | 18 | if( isset($this->params['editorID']) && $this->params['editorID'] ) { |
18 | 19 | $editor = User::newFromId( $this->params['editorID'] ); |
— | — | @@ -19,7 +20,7 @@ |
20 | 21 | } else { |
21 | 22 | $editor = User::newFromName( $this->params['editor'], false ); |
22 | 23 | } |
23 | | - PageChangeNotification::actuallyNotifyOnPageChange( |
| 24 | + $enotif->actuallyNotifyOnPageChange( |
24 | 25 | $editor, |
25 | 26 | $this->title, |
26 | 27 | $this->params['timestamp'], |