jenkins-bot has submitted this change and it was merged.
Change subject: (bug 46665) Add HTML email support to email digest
......................................................................
(bug 46665) Add HTML email support to email digest
Change-Id: I3b881acbcf4b18fc0401364ea0a6bc993d2c2246
---
M Echo.i18n.php
M Echo.php
M formatters/BasicFormatter.php
M includes/EmailBatch.php
M includes/EmailFormatter.php
M tests/EmailFormatterTest.php
M tests/NotificationFormatterTest.php
7 files changed, 562 insertions(+), 195 deletions(-)
Approvals:
Matthias Mullie: Looks good to me, approved
jenkins-bot: Verified
diff --git a/Echo.i18n.php b/Echo.i18n.php
index 5b6de50..dd1b4e7 100644
--- a/Echo.i18n.php
+++ b/Echo.i18n.php
@@ -19,8 +19,7 @@
'prefs-newmessageindicator' => 'New message indicator',
'echo-pref-send-me' => 'Send me:',
'echo-pref-send-to' => 'Send to:',
- // Update this to 'Email format' when HTML email is ready for email
digest
- 'echo-pref-email-format' => 'Individual email format:',
+ 'echo-pref-email-format' => 'Email format:',
'echo-pref-web' => 'Web',
'echo-pref-email' => 'Email',
'echo-pref-email-frequency-never' => 'Do not send me any email
notifications',
@@ -142,23 +141,11 @@
'echo-email-batch-bullet' => '•', # only translate this message to
other languages if you have to change it
'echo-email-batch-subject-daily' => 'You have {{PLURAL:$2|a new
notification|new notifications}} at {{SITENAME}}',
'echo-email-batch-subject-weekly' => 'You have {{PLURAL:$2|a new
notification|new notifications}} at {{SITENAME}} this week',
- 'echo-email-batch-body-daily' => 'Hi $1,
-
-You have {{PLURAL:$3|a new notification|new notifications}} on {{SITENAME}}.
View {{PLURAL:$3|it|them}} here:
-{{canonicalurl:{{#special:Notifications}}}}
-
-$4
-
-$5',
- 'echo-email-batch-body-weekly' => 'Hi $1,
-
-You have {{PLURAL:$3|a new notification|new notifications}} on {{SITENAME}}
this week. View {{PLURAL:$3|it|them}} here:
-{{canonicalurl:{{#special:Notifications}}}}
-
-$4
-
-$5',
-
+ 'echo-email-batch-body-intro-daily' => "Hi $1,
+Here's a summary of today's activity on {{SITENAME}} for you",
+ 'echo-email-batch-body-intro-weekly' => "Hi $1,
+Here's a summary of this week's activity on {{SITENAME}} for you",
+ 'echo-email-batch-link-text-view-all-notifications' => 'View all
notifications',
// Supressed Revisions
'echo-rev-deleted-text-view' => 'This page revision has been
suppressed',
);
@@ -495,22 +482,11 @@
* $2 is a numeric count, this is used for plural support
See also:
* {{msg-mw|Echo-email-batch-subject-daily}}',
- 'echo-email-batch-body-daily' => 'Daily e-mail batch body. Parameters:
-* $1 is a username
-* $2 is currently not used, could be a numeric count or "10+". See also:
{{msg-mw|echo-notification-count|optional message|notext=1}}.
-* $3 is a numeric count, this is used for plural support
-* $4 is the e-mail batch content separated by "-------..."
({{msg-mw|echo-email-batch-separator}})
-* $5 is the e-mail footer, {{msg-mw|echo-email-footer-default}}
-See also:
-* {{msg-mw|Echo-email-batch-body-weekly}}',
- 'echo-email-batch-body-weekly' => 'Weekly e-mail batch body. Parameters:
-* $1 is a username
-* $2 is currently not used, could be a numeric count or "10+". See also:
{{msg-mw|echo-notification-count|optional message|notext=1}}.
-* $3 is a numeric count, this is used for plural support
-* $4 is the e-mail batch content separated by "--------..."
({{msg-mw|echo-email-batch-separator}})
-* $5 is the e-mail footer, {{msg-mw|echo-email-footer-default}}
-See also:
-* {{msg-mw|Echo-email-batch-body-daily}}',
+ 'echo-email-batch-body-intro-daily' => "Introduction text for daily
email digest. Parameters:
+* $1 is a username",
+ 'echo-email-batch-body-intro-weekly' => "Introduction text for weekly
email digest. Parameters:
+* $1 is a username",
+ 'echo-email-batch-link-text-view-all-notifications' => 'The link text
for the primary action in daily and weekly email digest',
'echo-rev-deleted-text-view' => 'Short message displayed instead of
edit content when revision text is suppressed.',
);
diff --git a/Echo.php b/Echo.php
index 66eb6b9..9775edf 100644
--- a/Echo.php
+++ b/Echo.php
@@ -68,6 +68,9 @@
$wgAutoloadClasses['EchoEmailMode'] = $dir . 'includes/EmailFormatter.php';
$wgAutoloadClasses['EchoEmailSingle'] = $dir . 'includes/EmailFormatter.php';
$wgAutoloadClasses['EchoEmailDigest'] = $dir . 'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoEmailDecorator'] = $dir .
'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoTextEmailDecorator'] = $dir .
'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoHTMLEmailDecorator'] = $dir .
'includes/EmailFormatter.php';
// Internal stuff
$wgAutoloadClasses['EchoNotifier'] = $dir . 'Notifier.php';
diff --git a/formatters/BasicFormatter.php b/formatters/BasicFormatter.php
index e2b3eab..6e56f3b 100644
--- a/formatters/BasicFormatter.php
+++ b/formatters/BasicFormatter.php
@@ -258,10 +258,9 @@
* @return array
*/
protected function formatEmail( $event, $user, $type ) {
- if ( $this->bundleData['use-bundle'] &&
$this->email['batch-bundle-body'] ) {
- $key = $this->email['batch-bundle-body'];
- } else {
- $key = $this->email['batch-body'];
+ // Email digest
+ if ( $type === 'emaildigest' ) {
+ return $this->formatEmailDigest( $event, $user );
}
// Echo single email
@@ -274,8 +273,6 @@
'subject' => $this->formatFragment(
$this->email['subject'], $event, $user )->text(),
// Single email text body
'body' => $textEmailFormatter->formatEmail(),
- // Email digest text body
- 'batch-body' => $this->formatFragment( $key, $event,
$user )->text()
);
$format = MWEchoNotifUser::newFromUser( $user
)->getEmailFormat();
@@ -295,6 +292,32 @@
}
/**
+ * Format text and/or html verion of email digest fragment for this
event
+ * @param $event EchoEvent
+ * @param $user User
+ * @return array
+ */
+ protected function formatEmailDigest( $event, $user ) {
+ if ( $this->bundleData['use-bundle'] &&
$this->email['batch-bundle-body'] ) {
+ $key = $this->email['batch-bundle-body'];
+ } else {
+ $key = $this->email['batch-body'];
+ }
+
+ // Email digest text body
+ $content = array( 'batch-body' => $this->formatFragment( $key,
$event, $user )->text() );
+ $format = MWEchoNotifUser::newFromUser( $user
)->getEmailFormat();
+ if ( $format == EchoHooks::EMAIL_FORMAT_HTML ) {
+ $outputFormat = $this->outputFormat;
+ $this->setOutputFormat( 'htmlemail' );
+ $content['batch-body-html'] = $this->formatFragment(
$key, $event, $user )->parse();
+ $content['icon'] = $this->icon;
+ $this->setOutputFormat( $outputFormat );
+ }
+ return $content;
+ }
+
+ /**
* Creates a notification fragment based on a message and parameters
*
* @param $details array An i18n message and parameters to pass to the
message
diff --git a/includes/EmailBatch.php b/includes/EmailBatch.php
index cd6686d..50f9202 100644
--- a/includes/EmailBatch.php
+++ b/includes/EmailBatch.php
@@ -159,52 +159,12 @@
// get the category for this event
$category = $event->getCategory();
$event->setBundleHash( $hash );
- $email = EchoNotificationController::formatNotification(
$event, $this->mUser, 'email', 'email' );
+ $email = EchoNotificationController::formatNotification(
$event, $this->mUser, 'email', 'emaildigest' );
if ( !isset( $this->content[$category] ) ) {
$this->content[$category] = array();
}
- $this->content[$category][] = $email['batch-body'];
- }
-
- /**
- * Concatenate the list of contents with 'echo-email-batch-separator'
- * grouped by category
- * @return string
- */
- protected function listToText() {
- if ( !$this->content ) {
- return '';
- }
-
- $result = array();
- // build the text section for each category
- foreach( $this->content as $category => $notifs ) {
- // Messages that can be used here:
- // * echo-category-title-system
- // * echo-category-title-other
- // * echo-category-title-edit-user-talk
- // * echo-category-title-reverted
- // * echo-category-title-article-linked
- // * echo-category-title-mention
- $output = wfMessage( 'echo-category-title-' . $category
)->numParams( count( $notifs ) )->text()
- . wfMessage( 'colon-separator' )->text() . "\n";
-
- foreach( $notifs as $notif ) {
- $output .= "\n " . wfMessage(
'echo-email-batch-bullet' )->text() . ' ' . $notif;
- }
- $result[] = $output;
- }
-
- // for prepending and appending 'echo-email-batch-separator'
- $result = array_merge( array( '' ), $result, array( '' ) );
-
- return trim(
- implode(
- "\n\n" . wfMessage(
'echo-email-batch-separator' )->text() . "\n\n",
- $result
- )
- );
+ $this->content[$category][] = $email;
}
/**
@@ -216,13 +176,7 @@
* Send the batch email
*/
public function sendEmail() {
- global $wgNotificationSender, $wgNotificationSenderName,
$wgNotificationReplyName, $wgEchoEmailFooterAddress;
-
- // global email footer
- $footer = wfMessage( 'echo-email-footer-default' )
- ->inLanguage( $this->mUser->getOption(
'language' ) )
- ->params( $wgEchoEmailFooterAddress, '' )
- ->text();
+ global $wgNotificationSender, $wgNotificationSenderName,
$wgNotificationReplyName;
// @Todo - replace them with the CONSTANT in 33810 once it is
merged
if ( $this->mUser->getOption( 'echo-email-frequency' ) == 7 ) {
@@ -233,6 +187,22 @@
$emailDeliveryMode = 'daily_digest';
}
+ // Echo digest email mode
+ $emailDigest = new EchoEmailDigest( $this->mUser,
$this->content, $frequency );
+
+ $textEmailFormatter = new EchoTextEmailFormatter( $emailDigest
);
+
+ $body = $textEmailFormatter->formatEmail();
+
+ $format = MWEchoNotifUser::newFromUser( $this->mUser
)->getEmailFormat();
+ if ( $format == EchoHooks::EMAIL_FORMAT_HTML ) {
+ $htmlEmailFormatter = new EchoHTMLEmailFormatter(
$emailDigest );
+ $body = array(
+ 'text' => $body,
+ 'html' => $htmlEmailFormatter->formatEmail()
+ );
+ }
+
// email subject
if ( $this->count > self::$displaySize ) {
$count = wfMessage( 'echo-notification-count'
)->params( self::$displaySize )->text();
@@ -240,13 +210,6 @@
$count = $this->count;
}
$subject = wfMessage( 'echo-email-batch-subject-' . $frequency
)->params( $count, $this->count )->text();
- $body = wfMessage( 'echo-email-batch-body-' . $frequency
)->params(
- $this->mUser->getName(),
- $count,
- $this->count,
- $this->listToText(),
- $footer
- )->text();
$toAddress = new MailAddress( $this->mUser );
$fromAddress = new MailAddress( $wgNotificationSender,
$wgNotificationSenderName );
diff --git a/includes/EmailFormatter.php b/includes/EmailFormatter.php
index e5f0bab..a4f9cfe 100644
--- a/includes/EmailFormatter.php
+++ b/includes/EmailFormatter.php
@@ -34,18 +34,18 @@
*/
public function __construct( EchoEmailMode $emailMode ) {
parent::__construct( $emailMode );
+ $this->emailMode->attachDecorator( new EchoTextEmailDecorator()
);
}
/**
- * Formatting text email notification
- * @return string
+ * {@inheritDoc}
*/
public function formatEmail() {
$template = $this->emailMode->getTextTemplate();
foreach ( $this->emailMode->getComponent() as $val ) {
$func = 'build' . ucfirst( $val );
- $template = str_replace( "%%$val%%",
$this->emailMode->$func( 'text' ), $template );
+ $template = str_replace( "%%$val%%",
$this->emailMode->$func(), $template );
}
// Remove redundant newline characters
@@ -73,18 +73,18 @@
*/
public function __construct( EchoEmailMode $emailMode ) {
parent::__construct( $emailMode );
+ $this->emailMode->attachDecorator( new EchoHTMLEmailDecorator()
);
}
/**
- * Formatting HTML email notification
- * @return string
+ * {@inheritDoc}
*/
public function formatEmail() {
$template = $this->emailMode->getHTMLTemplate();
foreach ( $this->emailMode->getComponent() as $val ) {
$func = 'build' . ucfirst( $val );
- $template = str_replace( "%%$val%%",
$this->emailMode->$func( 'html' ), $template );
+ $template = str_replace( "%%$val%%",
$this->emailMode->$func(), $template );
}
return $template;
@@ -97,15 +97,22 @@
abstract class EchoEmailMode {
/**
- * Email components
* @var array
+ * Email components
*/
protected $component;
/**
* @var User
+ * The user who receives email notifications
*/
protected $user;
+
+ /**
+ * @var EchoEmailDecorator
+ * Email decorator
+ */
+ protected $decorator;
/**
* @param $user User
@@ -115,6 +122,9 @@
$this->user = $user;
// All email delivery mode share the same footer
$this->component = array_merge( $component, array( 'footer' ) );
+ // Initialize with a text decorator, the decorator can be
altered
+ // via attacheDecorator() based on text/html emails
+ $this->decorator = new EchoTextEmailDecorator();
}
/**
@@ -131,27 +141,11 @@
/**
* Get the footer component
- * @param $format string 'text'/'html'
* @return string
*/
- public function buildFooter( $format ) {
+ public function buildFooter() {
global $wgEchoEmailFooterAddress;
-
- if ( $format === 'text' ) {
- return wfMessage( 'echo-email-footer-default' )
- ->params(
- $wgEchoEmailFooterAddress,
- wfMessage(
'echo-email-batch-separator' )->text()
- )
- ->text();
- } else {
- $title = SpecialPage::getTitleFor( 'Preferences' );
- $title->setFragment( "#mw-prefsection-echo" );
- return wfMessage( 'echo-email-footer-default-html' )
- ->params( $wgEchoEmailFooterAddress )
- ->rawParams( $title->getFullURL( '',
false, PROTO_HTTPS ) )
- ->text();
- }
+ return $this->decorator->decorateFooter(
$wgEchoEmailFooterAddress );
}
/**
@@ -163,24 +157,35 @@
}
/**
- * The style for primary link
+ * Get the notification icon path
+ * @param $icon string
* @return string
*/
- protected function getPrimaryLinkCSS() {
- return 'cursor:pointer; text-align:center;
- text-decoration:none; padding:.45em 1.2em .45em;
- color:#D9EEF7; background:#3366BB;
- font-family: arial;font-size: 13px;';
+ public static function getNotifIcon( $icon ) {
+ global $wgEchoNotificationIcons, $wgExtensionAssetsPath;
+
+ $iconInfo = $wgEchoNotificationIcons[$icon];
+ if ( isset( $iconInfo['url'] ) && $iconInfo['url'] ) {
+ $iconUrl = $iconInfo['url'];
+ } else {
+ if ( !isset( $iconInfo['path'] ) || !$iconInfo['path']
) {
+ $iconInfo =
$wgEchoNotificationIcons['placeholder'];
+ }
+ $iconUrl = "$wgExtensionAssetsPath/{$iconInfo['path']}";
+ }
+
+ // Use http for image path, there is no need for https
+ return wfExpandUrl( $iconUrl, PROTO_HTTP );
}
/**
- * The style for secondary link
- * @return string
+ * Attach an email decorator to the email mode object
+ * @param $decorator EchoEmailDecorator
*/
- protected function getSecondaryLinkCSS() {
- return 'text-decoration: none;font-size: 10px;font-family:
arial;
- color: #808184';
+ public function attachDecorator( EchoEmailDecorator $decorator ) {
+ $this->decorator = $decorator;
}
+
}
/**
@@ -211,10 +216,9 @@
/**
* Build the intro component
- * @param $format string 'text'/'html'
* @return string
*/
- public function buildIntro( $format ) {
+ public function buildIntro() {
$bundle = $this->notifFormatter->getValue( 'bundleData' );
$email = $this->notifFormatter->getValue( 'email' );
@@ -230,19 +234,14 @@
$this->user
);
- if ( $format === 'text' ) {
- return $message->text();
- } else {
- return $message->parse();
- }
+ return $this->decorator->decorateIntro( $message );
}
/**
* Build the summary component
- * @param $format string 'text'/'html'
* @return string
*/
- public function buildSummary( $format ) {
+ public function buildSummary() {
return $this->notifFormatter->formatRevisionComment(
$this->event,
$this->user
@@ -251,10 +250,9 @@
/**
* Build the action component
- * @param $format string 'text'/'html'
* @return string
*/
- public function buildAction( $format ) {
+ public function buildAction() {
$link = array();
$ranks = array( 'primary', 'secondary' );
@@ -266,56 +264,30 @@
continue;
}
- // Plain text email
- if ( $format === 'text' ) {
- $url = $this->notifFormatter->getLink(
$this->event, $this->user, $rank, false, true );
-
- $link[] = wfMessage( $message )->text()
- . wfMessage( 'colon-separator' )->text()
- . '<'
- .
$this->notifFormatter->sanitizeEmailLink( $url )
- . '>';
- // HTML email
- } else {
- if ( $rank === 'primary' ) {
- $style = $this->getPrimaryLinkCSS();
- } else {
- $style = $this->getSecondaryLinkCSS();
- }
-
- $link[] = $this->notifFormatter->getLink(
$this->event, $this->user, $rank, false, false, $style );
- }
+ $link[] = $this->decorator->decorateSingleAction(
+ $this->notifFormatter,
+ $this->event,
+ $this->user,
+ $rank,
+ $message
+ );
}
// Add some spacing between the two action links
- $spacing = ( $format === 'text' ) ? "\n\n" : " ";
- return implode( $spacing, $link );
+ $spacing = $this->decorator->getActionLinkSeparator();
+ return implode( $spacing . $spacing, $link );
}
/**
* Build the email icon component
- * @param $format string 'text'/'html'
* @return string
*/
- public function buildEmailIcon( $format ) {
- global $wgEchoNotificationIcons, $wgExtensionAssetsPath;
-
- $iconInfo =
$wgEchoNotificationIcons[$this->notifFormatter->getValue( 'icon' )];
- if ( isset( $iconInfo['url'] ) && $iconInfo['url'] ) {
- $iconUrl = $iconInfo['url'];
- } else {
- if ( !isset( $iconInfo['path'] ) || !$iconInfo['path']
) {
- $iconInfo =
$wgEchoNotificationIcons['placeholder'];
- }
- $iconUrl = "$wgExtensionAssetsPath/{$iconInfo['path']}";
- }
-
- return wfExpandUrl( $iconUrl );
+ public function buildEmailIcon() {
+ return EchoEmailMode::getNotifIcon(
$this->notifFormatter->getValue( 'icon' ) );
}
/**
- * Get template for text email
- * @return string
+ * {@inheritDoc}
*/
public function getTextTemplate() {
return <<< EOF
@@ -330,8 +302,7 @@
}
/**
- * Get template for html email
- * @return string
+ * {@inheritDoc}
*/
public function getHTMLTemplate() {
return <<< EOF
@@ -397,19 +368,424 @@
/**
* Class that represents email digest delivery mode
- * @Todo - To be completed for email digest
*/
class EchoEmailDigest extends EchoEmailMode {
- public function __construct( $user ) {
- parent::__construct( $user, array( 'header', 'intro',
'digestList' ) );
+ /**
+ * @var string
+ * The mode of email digest, 'weekly' or 'daily'
+ */
+ protected $digestMode;
+
+ /**
+ * @var array
+ * Raw email digest list
+ */
+ protected $rawDigestList;
+
+ /**
+ * @param $user User
+ * @param $rawDigestList array the raw notification event list
+ * @param $digestMode string 'daily'/'weekly'
+ */
+ public function __construct( User $user, array $rawDigestList,
$digestMode = 'daily' ) {
+ parent::__construct( $user, array( 'intro', 'digestList',
'action' ) );
+ // Some data validation
+ if ( !in_array( $digestMode, array( 'daily', 'weekly' ) ) ) {
+ $digestMode = 'daily';
+ }
+ $this->digestMode = $digestMode;
+ $this->rawDigestList = $rawDigestList;
}
- public function buildHeader() {}
- public function buildIntro() {}
- public function buildDigestList() {}
+ /**
+ * Build the intro component
+ * @return string
+ */
+ public function buildIntro() {
+ $message = wfMessage(
+ 'echo-email-batch-body-intro-' . $this->digestMode,
+ $this->user->getName()
+ );
- public function getTextTemplate() {}
- public function getHTMLTemplate() {}
+ return $this->decorator->decorateIntro( $message );
+ }
+
+ /**
+ * Build the digestList component
+ * @return string
+ */
+ public function buildDigestList() {
+ if ( !$this->rawDigestList ) {
+ return '';
+ }
+
+ return $this->decorator->decorateDigestList(
$this->rawDigestList );
+ }
+
+ /**
+ * Build the action component
+ * @return string
+ */
+ public function buildAction() {
+ $title = SpecialPage::getTitleFor( 'Notifications' );
+
+ return $this->decorator->decorateDigestAction( $title );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getTextTemplate() {
+ return <<< EOF
+%%intro%%
+
+%%digestList%%
+
+%%action%%
+
+%%footer%%
+
+EOF;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getHTMLTemplate() {
+ return <<< EOF
+<html><head></head><body>
+<table cellspacing="0" cellpadding="0" border="0" width="100%" align="center">
+<tr>
+ <td bgcolor="#E6E7E8"><center>
+ <br /><br />
+ <table cellspacing="0" cellpadding="0" border="0" width="600">
+ <tr>
+ <td bgcolor="#FFFFFF" width="35"> </td>
+ <td bgcolor="#FFFFFF" width="31"> </td>
+ <td bgcolor="#FFFFFF" width="469"
style="line-height:40px;"> </td>
+ <td bgcolor="#FFFFFF" width="65"> </td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF" width="35"
rowspan="2"> </td>
+ <td bgcolor="#FFFFFF" width="31"
rowspan="2"> </td>
+ <td bgcolor="#FFFFFF" width="469"
align="center" style="font-family:arial; font-size:13px; line-height:20px;
color: #A6A8AB; text-align: center;">%%intro%%</td>
+ <td bgcolor="#FFFFFF" width="65"
rowspan="2"> </td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF" width="469" align="left"
style="font-family: arial; font-size:16px; line-height: 20px; font-weight:
600;">
+ <table cellspacing="0" cellpadding="0"
border="0" width="100%">
+ <tr>
+ <td bgcolor="#FFFFFF"
align="left" style="font-family: arial; font-size:13px; color: #58585B;
padding-top: 25px;">
+ %%digestList%%
+ </td>
+ </tr>
+ </table>
+ <br /><br />
+ </td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF" width="35"> </td>
+ <td bgcolor="#FFFFFF" width="31"> </td>
+ <td bgcolor="#FFFFFF" width="469"
style="line-height:60px;" align="center">%%action%%</td>
+ <td bgcolor="#FFFFFF" width="65"> </td>
+ </tr>
+ <tr>
+ <td bgcolor="#FFFFFF" width="35"> </td>
+ <td bgcolor="#FFFFFF" width="31"> </td>
+ <td bgcolor="#FFFFFF" width="469"
style="line-height:40px;"> </td>
+ <td bgcolor="#FFFFFF" width="65"> </td>
+ </tr>
+ <tr>
+ <td bgcolor="#F8F8F8" width="35"> </td>
+ <td bgcolor="#F8F8F8" width="31"> </td>
+ <td bgcolor="#F8F8F8" width="469" align="left"
style="font-family:arial; font-size:10px; line-height:13px; color:#B7B7B7;
padding: 10px 20px;"><br />
+ %%footer%%
+ <br /><br />
+ </td>
+ <td bgcolor="#F8F8F8" width="65"> </td>
+ </tr>
+ <tr>
+ <td colspan="4"> </td>
+ </tr>
+ </table>
+ <br><br></center>
+ </td>
+</tr>
+</table>
+</body></html>
+EOF;
+ }
}
+
+/**
+ * Email decorator interface
+ */
+interface EchoEmailDecorator {
+ /**
+ * Decorate the intro for all modes
+ * @param $message Message the intro message object
+ * @return string
+ */
+ public function decorateIntro( $message );
+
+ /**
+ * Decorate the digest list for digest mode
+ * @param $digestList array
+ * @return string
+ */
+ public function decorateDigestList( $digestList );
+
+ /**
+ * Decorate the primary action for digest mode
+ * @param $title Title
+ * @return string
+ */
+ public function decorateDigestAction( $title );
+
+ /**
+ * Decorate the footer for all mode
+ * @param $address string
+ * @return string
+ */
+ public function decorateFooter( $address );
+
+ /**
+ * Decorate the actions for single mode
+ * @param $notifFormatter EchoBasicFormatter
+ * @param $event EchoEvent
+ * @param $user User
+ * @param $rank string
+ * @param $message string
+ * @return string
+ */
+ public function decorateSingleAction( $notifFormatter, $event, $user,
$rank, $message );
+
+ /**
+ * Get the spacing for between action links
+ * @return string
+ */
+ public function getActionLinkSeparator();
+}
+
+/**
+ * Text email decorator
+ */
+class EchoTextEmailDecorator implements EchoEmailDecorator {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateIntro( $message ) {
+ return $message->text();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestList( $digestList ) {
+ $result = array();
+
+ // build the text section for each category
+ foreach( $digestList as $category => $notifs ) {
+ $output = wfMessage( 'echo-category-title-' . $category
)->numParams( count( $notifs ) )->text()
+ . wfMessage( 'colon-separator' )->text() . "\n";
+
+ foreach( $notifs as $notif ) {
+ $output .= "\n " . wfMessage(
'echo-email-batch-bullet' )->text() . ' ' . $notif['batch-body'];
+ }
+ $result[] = $output;
+ }
+
+ // for prepending and appending 'echo-email-batch-separator'
+ $result = array_merge( array( '' ), $result, array( '' ) );
+
+ return trim(
+ implode(
+ "\n\n" . wfMessage(
'echo-email-batch-separator' )->text() . "\n\n",
+ $result
+ )
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestAction( $title ) {
+ return wfMessage(
'echo-email-batch-link-text-view-all-notifications' )->text()
+ . wfMessage( 'colon-separator' )->text()
+ . '<'
+ . $title->getFullURL( '', false, PROTO_HTTPS )
+ . '>';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateFooter( $address ) {
+ return wfMessage( 'echo-email-footer-default' )
+ ->params(
+ $address,
+ wfMessage( 'echo-email-batch-separator'
)->text()
+ )
+ ->text();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateSingleAction( $notifFormatter, $event, $user,
$rank, $message ) {
+ $url = $notifFormatter->getLink( $event, $user, $rank, false,
true );
+
+ return wfMessage( $message )->text()
+ . wfMessage( 'colon-separator' )->text()
+ . '<'
+ . $notifFormatter->sanitizeEmailLink( $url )
+ . '>';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getActionLinkSeparator() {
+ return "\n";
+ }
+}
+
+/**
+ * HTML email decorator
+ */
+class EchoHTMLEmailDecorator implements EchoEmailDecorator {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateIntro( $message ) {
+ return nl2br( $message->parse() );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestList( $digestList ) {
+ $result = array();
+ // build the html section for each category
+ foreach( $digestList as $category => $notifs ) {
+ $output = $this->applyStyleToCategory(
+ wfMessage( 'echo-category-title-' . $category )
+ ->numParams( count( $notifs ) )
+ ->escaped()
+ );
+ foreach( $notifs as $notif ) {
+ $output .= "\n" . $this->applyStyleToEvent(
$notif );
+ }
+ $result[] = '<table border="0" width="100%">' . $output
. '</table>';
+ }
+
+ return trim( implode( "\n", $result ) );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateDigestAction( $title ) {
+ return Linker::link(
+ $title,
+ wfMessage(
'echo-email-batch-link-text-view-all-notifications' )->escaped(),
+ array( 'style' => $this->getPrimaryLinkCSS() ),
+ array(),
+ array( 'https' )
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateFooter( $address ) {
+ $title = SpecialPage::getTitleFor( 'Preferences' );
+ $title->setFragment( "#mw-prefsection-echo" );
+ return wfMessage( 'echo-email-footer-default-html' )
+ ->params( $address )
+ ->rawParams( $title->getFullURL( '', false,
PROTO_HTTPS ) )
+ ->text();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function decorateSingleAction( $notifFormatter, $event, $user,
$rank, $message ) {
+ if ( $rank === 'primary' ) {
+ $style = $this->getPrimaryLinkCSS();
+ } else {
+ $style = $this->getSecondaryLinkCSS();
+ }
+
+ return $notifFormatter->getLink( $event, $user, $rank, false,
false, $style );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getActionLinkSeparator() {
+ return " ";
+ }
+
+ /**
+ * The style for primary link
+ * @return string
+ */
+ protected function getPrimaryLinkCSS() {
+ return 'cursor:pointer; text-align:center;
text-decoration:none; padding:.45em 1.2em .45em;
+ color:#D9EEF7; background:#3366BB; font-family:
arial;font-size: 13px;';
+ }
+
+ /**
+ * The style for secondary link
+ * @return string
+ */
+ protected function getSecondaryLinkCSS() {
+ return 'text-decoration: none;font-size: 10px;font-family:
arial; color: #808184';
+ }
+
+ /**
+ * Apply style to notification category header
+ * @param $category string
+ * @return string
+ */
+ protected function applyStyleToCategory( $category ) {
+ return <<< EOF
+<tr>
+ <td colspan="2" style="color: #A87B4F; font-weight: normal; font-size:
13px; padding-top: 15px;">
+ $category <br />
+ <hr style="background-color:#FFFFFF; color:#FFFFFF; border: 1px
solid #F2F2F2;" />
+ </td>
+</tr>
+EOF;
+ }
+
+ /**
+ * Apply style to individual notification event
+ * @param $notif array an array containts keys: icon, batch-body,
batch-body-html
+ * @return string
+ */
+ protected function applyStyletoEvent( $notif ) {
+ // notification icon
+ $icon = EchoEmailMode::getNotifIcon( $notif['icon'] );
+ // notification text
+ $text = $notif['batch-body-html'];
+
+ return <<< EOF
+<tr>
+ <td width="30">
+ <img src="$icon" width="70%" height="70%"
style="vertical-align:middle;">
+ </td>
+ <td style="font-family: arial; font-size:13px; color: #58585B;">
+ $text
+ </td>
+</tr>
+EOF;
+ }
+
+}
+
diff --git a/tests/EmailFormatterTest.php b/tests/EmailFormatterTest.php
index 9f79eb7..67d5e56 100644
--- a/tests/EmailFormatterTest.php
+++ b/tests/EmailFormatterTest.php
@@ -3,6 +3,7 @@
class EchoEmailFormatterTest extends MediaWikiTestCase {
private $emailSingle;
+ private $emailDigest;
public function setUp() {
parent::setUp();
@@ -18,11 +19,15 @@
$formatter->setOutputFormat( 'email' );
$this->emailSingle = new EchoEmailSingle( $formatter, $event,
User::newFromId( 2 ) );
+
+ $content[$event->getCategory()][] =
EchoNotificationController::formatNotification( $event, User::newFromId( 2 ),
'email', 'emaildigest' );
+ $this->emailDigest = new EchoEmailDigest( User::newFromId( 2 ),
$content );
}
public function testEmailFormatter() {
$pattern = '/%%(.*?)%%/is';
+ // Single email mode
$textFormatter = new EchoTextEmailFormatter( $this->emailSingle
);
$this->assertRegExp( $pattern,
$this->emailSingle->getTextTemplate() );
$this->assertEquals( 0, preg_match ( $pattern,
$textFormatter->formatEmail() ) );
@@ -30,11 +35,29 @@
$htmlFormatter = new EchoHTMLEmailFormatter( $this->emailSingle
);
$this->assertRegExp( $pattern,
$this->emailSingle->getHTMLTemplate() );
$this->assertEquals( 0, preg_match ( $pattern,
$htmlFormatter->formatEmail() ) );
+
+ // Digest email mode
+ $textFormatter = new EchoTextEmailFormatter( $this->emailDigest
);
+ $this->assertRegExp( $pattern,
$this->emailSingle->getTextTemplate() );
+ $this->assertEquals( 0, preg_match ( $pattern,
$textFormatter->formatEmail() ) );
+
+ $htmlFormatter = new EchoHTMLEmailFormatter( $this->emailDigest
);
+ $this->assertRegExp( $pattern,
$this->emailSingle->getHTMLTemplate() );
+ $this->assertEquals( 0, preg_match ( $pattern,
$htmlFormatter->formatEmail() ) );
}
public function testBuildAction() {
- $this->assertEquals( 0, preg_match ( '/<a /i',
$this->emailSingle->buildAction( 'text' ) ) );
- $this->assertRegExp( '/<a /i', $this->emailSingle->buildAction(
'html' ) );
+ $this->emailSingle->attachDecorator( new
EchoTextEmailDecorator() );
+ $this->assertEquals( 0, preg_match ( '/<a /i',
$this->emailSingle->buildAction() ) );
+
+ $this->emailSingle->attachDecorator( new
EchoHTMLEmailDecorator() );
+ $this->assertRegExp( '/<a /i',
$this->emailSingle->buildAction() );
+
+ $this->emailDigest->attachDecorator( new
EchoTextEmailDecorator() );
+ $this->assertEquals( 0, preg_match ( '/<a /i',
$this->emailDigest->buildAction() ) );
+
+ $this->emailDigest->attachDecorator( new
EchoHTMLEmailDecorator() );
+ $this->assertRegExp( '/<a /i',
$this->emailDigest->buildAction() );
}
protected function mockEvent( $type ) {
@@ -48,6 +71,9 @@
$event->expects( $this->any() )
->method( 'getType' )
->will( $this->returnValue( $type ) );
+ $event->expects( $this->any() )
+ ->method( 'getCategory' )
+ ->will( $this->returnValue(
EchoNotificationController::getNotificationCategory( $type ) ) );
return $event;
}
diff --git a/tests/NotificationFormatterTest.php
b/tests/NotificationFormatterTest.php
index d1afd9f..34dd8e0 100644
--- a/tests/NotificationFormatterTest.php
+++ b/tests/NotificationFormatterTest.php
@@ -174,7 +174,7 @@
// generic assertion, could do better
if ( $format === 'email' ) {
$this->assertInternalType( 'array', $result );
- $this->assertCount( 3, $result );
+ $this->assertCount( 2, $result );
} else {
$this->assertInternalType( 'string', $result );
$this->assertGreaterThan( 0, strlen( $result ) );
--
To view, visit https://gerrit.wikimedia.org/r/72672
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I3b881acbcf4b18fc0401364ea0a6bc993d2c2246
Gerrit-PatchSet: 18
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Bsitu <[email protected]>
Gerrit-Reviewer: Bsitu <[email protected]>
Gerrit-Reviewer: EBernhardson (WMF) <[email protected]>
Gerrit-Reviewer: Matthias Mullie <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits