Bsitu has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/70112


Change subject: Add HTML email support to Echo notification
......................................................................

Add HTML email support to Echo notification

-2ed as this needs testing and some code update

Change-Id: Ia4b98b14e135742b84f1b0e04589b0efdd24e954
---
M Echo.i18n.php
M Echo.php
M Notifier.php
M formatters/BasicFormatter.php
M formatters/CommentFormatter.php
M formatters/EditFormatter.php
M formatters/NotificationFormatter.php
A includes/EmailFormatter.php
8 files changed, 546 insertions(+), 201 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Echo 
refs/changes/12/70112/1

diff --git a/Echo.i18n.php b/Echo.i18n.php
index b8de66e..01e6c84 100644
--- a/Echo.i18n.php
+++ b/Echo.i18n.php
@@ -91,56 +91,15 @@
        'notification-new-user' => "Welcome to {{SITENAME}}, $1! We're glad 
you're here.",
        'notification-reverted2' => 'Your {{PLURAL:$4|edit on [[:$2]] has|edits 
on [[:$2]] have}} been {{GENDER:$1|reverted}} by [[User:$1|$1]] $3',
        'notification-reverted-flyout2' => 'Your {{PLURAL:$4|edit on $2 
has|edits on $2 have}} been {{GENDER:$1|reverted}} by $1 $3',
-       'notification-edit-talk-page-email-subject2' => 'You have a new 
talkpage message on {{SITENAME}}',
-       'notification-edit-talk-page-email-body2' => '$1
-
-$3
-
-View more:
-
-<$2>
-
-$4',
-       'notification-edit-talk-page-email-batch-body2' => '$1 
{{GENDER:$1|posted}} on your talk page',
+       'notification-edit-talk-page-email-subject2' => '$1 {{GENDER:$1|left}} 
you a message on {{SITENAME}}',
+       'notification-edit-talk-page-email-batch-body2' => '$1 
{{GENDER:$1|left}} a message on your talk page',
        'notification-page-linked-email-subject' => 'A page you started was 
linked on {{SITENAME}}',
-       'notification-page-linked-email-body' => '$1
-
-See all links to this page:
-
-{{canonicalurl:{{#special:WhatLinksHere/$2}}}}
-
-$3',
        'notification-page-linked-email-batch-body' => '$2 was 
{{GENDER:$1|linked}} from $3',
        'notification-reverted-email-subject2' => 'Your {{PLURAL:$3|edit on $2 
was|edits on $2 were}} {{GENDER:$1|reverted}} by $1 on {{SITENAME}}',
-       'notification-reverted-email-body2' => 'Your {{PLURAL:$7|edit on $2 has 
been|edits on $2 have been}} {{GENDER:$1|reverted}} by $1.
-
-$5
-
-View more:
-
-<$3>
-
-$6',
        'notification-reverted-email-batch-body2' => 'Your {{PLURAL:$3|edit on 
$2 was|edits on $2 were}} {{GENDER:$1|reverted}} by $1',
        'notification-mention-email-subject' => '$1 {{GENDER:$1|mentioned}} you 
on {{SITENAME}}',
-       'notification-mention-email-body' => '{{SITENAME}} user $1 
{{GENDER:$1|mentioned}} you on $2.
-
-$3
-
-View more:
-
-<$4>
-
-$5',
        'notification-mention-email-batch-body' => '$1 {{GENDER:$1|mentioned}} 
you on $2',
        'notification-user-rights-email-subject' => 'Your user rights have 
changed on {{SITENAME}}',
-       'notification-user-rights-email-body' => 'Your user rights were 
{{GENDER:$1|changed}} by $1. $2
-
-View more:
-
-{{canonicalurl:{{#special:ListGroupRights}}}}
-
-$3',
        'notification-user-rights-email-batch-body' => 'Your user rights were 
{{GENDER:$1|changed}} by $1. $2',
        'echo-notification-count' => '$1+',
        // Email notification
@@ -154,6 +113,8 @@
 To control which emails we send you, check your preferences:
 {{canonicalurl:{{#special:Preferences}}#mw-prefsection-echo}}
 
+$1',
+       'echo-email-footer-default-html' => 'To control which emails we send 
you, <a href="$2" style="text-decoration:none;">check your preferences</a><br />
 $1',
        // Notifications overlay
        'echo-overlay-link' => 'All notifications',
@@ -318,8 +279,7 @@
 See also:
 * {{msg-mw|Notification-page-linked-flyout}}
 * {{msg-mw|Notification-page-linked-email-batch-body}}
-* {{msg-mw|Notification-page-linked-email-subject}}
-* {{msg-mw|Notification-page-linked-email-body}}',
+* {{msg-mw|Notification-page-linked-email-subject}}',
        'notification-page-linked-flyout' => 'Flyout-specific format for 
displaying notifications of articles being linked
 * $1 is the username of the person who linked the page, plain text. Can be 
used for GENDER.
 * $2 is the page being linked
@@ -327,8 +287,7 @@
 See also:
 * {{msg-mw|Notification-page-linked}}
 * {{msg-mw|Notification-page-linked-email-batch-body}}
-* {{msg-mw|Notification-page-linked-email-subject}}
-* {{msg-mw|Notification-page-linked-email-body}}',
+* {{msg-mw|Notification-page-linked-email-subject}}',
        'notification-add-comment2' => 'Format for displaying notifications of 
a comment being added to an existing discussion. Parameters:
 * $1 is the username of the person who edited, plain text. Can be used for 
GENDER.
 * $2 is the section title of the discussion,
@@ -391,11 +350,6 @@
 * $4 is the number of edits that were reverted. NOTE: This will only be set to 
1 or 2, with 2 actually meaning 'an unknown number greater than 0'.
 {{Related|Notification-reverted}}",
        'notification-edit-talk-page-email-subject2' => 'E-mail subject.',
-       'notification-edit-talk-page-email-body2' => 'E-mail notification. 
Parameters:
-* $1 - the email intro, could be 
{{msg-mw|notification-edit-talk-page-email-batch-body2}} or 
{{msg-mw|notification-edit-user-talk-email-batch-bundle-body}}
-* <$2> - a link to a change
-* $3 - the edit summary
-* $4 - the e-mail footer, {{msg-mw|echo-email-footer-default}}',
        'notification-edit-talk-page-email-batch-body2' => 'E-mail notification 
for talk page edit
 * $1 is a username
 
@@ -407,17 +361,7 @@
 See also:
 * {{msg-mw|Notification-page-linked}}
 * {{msg-mw|Notification-page-linked-flyout}}
-* {{msg-mw|Notification-page-linked-email-batch-body}}
-* {{msg-mw|Notification-page-linked-email-body}}',
-       'notification-page-linked-email-body' => 'E-mail notification. 
Parameters:
-* $1 is the email intro, could be 
{{msg-mw|notification-page-linked-email-batch-body}} or 
{{msg-mw|notification-page-linked-email-batch-bundle-body}}
-* $2 is the page being linked.
-* $3 is the e-mail footer, {{msg-mw|echo-email-footer-default}}.
-See also:
-* {{msg-mw|Notification-page-linked}}
-* {{msg-mw|Notification-page-linked-flyout}}
-* {{msg-mw|Notification-page-linked-email-batch-body}}
-* {{msg-mw|Notification-page-linked-email-subject}}',
+* {{msg-mw|Notification-page-linked-email-batch-body}}',
        'notification-page-linked-email-batch-body' => 'E-mail notification for 
page being linked. Parameters:
 * $1 is the username of the person who linked the page, plain text. Can be 
used for GENDER.
 * $2 is the page being linked.
@@ -425,22 +369,12 @@
 See also:
 * {{msg-mw|Notification-page-linked}}
 * {{msg-mw|Notification-page-linked-flyout}}
-* {{msg-mw|Notification-page-linked-email-subject}}
-* {{msg-mw|Notification-page-linked-email-body}}',
+* {{msg-mw|Notification-page-linked-email-subject}}',
        'notification-reverted-email-subject2' => 'E-mail subject. Parameters:
 * $1 is a username
 * $2 is a page title
 * $3 is the number of revert
 {{Related|Notification-reverted}}',
-       'notification-reverted-email-body2' => "E-mail notification. Parameters:
-* $1 is the username
-* $2 is the page title
-* <$3> is the link to the change
-* $4 is the e-mail recipient's username
-* $5 is the edit summary
-* $6 is the email footer, {{msg-mw|echo-email-footer-default}}
-* $7 is the number of revert
-{{Related|Notification-reverted}}",
        'notification-reverted-email-batch-body2' => 'E-mail notification for 
page revert. Parameters:
 * $1 is a username
 * $2 is a page title
@@ -452,20 +386,7 @@
 See also:
 * {{msg-mw|Notification-mention}}
 * {{msg-mw|Notification-mention-flyout}}
-* {{msg-mw|Notification-mention-email-batch-body}}
-* {{msg-mw|Notification-mention-email-body}}',
-       'notification-mention-email-body' => 'E-mail notification. Parameters:
-* $1 is a username, plaintext.  Can be used for gender support
-* $2 is talk page title
-* $3 is the edit summary
-* <$4> is the link to the talk page section title
-* $5 is the email footer
-
-See also:
-* {{msg-mw|Notification-mention}}
-* {{msg-mw|Notification-mention-flyout}}
-* {{msg-mw|Notification-mention-email-batch-body}}
-* {{msg-mw|Notification-mention-email-subject}}',
+* {{msg-mw|Notification-mention-email-batch-body}}',
        'notification-mention-email-batch-body' => 'E-mail notification batch 
body.  Parameters:
 * $1 is a username, plaintext.  Can be used for gender support
 * $2 is talk page title
@@ -473,25 +394,13 @@
 See also:
 * {{msg-mw|Notification-mention}}
 * {{msg-mw|Notification-mention-flyout}}
-* {{msg-mw|Notification-mention-email-body}}
 * {{msg-mw|Notification-mention-email-subject}}',
        'notification-user-rights-email-subject' => 'E-mail subject for user 
rights notification
 
 See also:
 * {{msg-mw|Notification-user-rights}}
 * {{msg-mw|Notification-user-rights-flyout}}
-* {{msg-mw|Notification-user-rights-email-batch-body}}
-* {{msg-mw|Notification-user-rights-email-body}}',
-       'notification-user-rights-email-body' => 'E-mail notification.  
Parameters:
-* $1 - a user name, plaintext.  Can be used for gender support
-* $2 - a semicolon separated list of {{msg-mw|notification-user-rights-add}}, 
{{msg-mw|notification-user-rights-remove}}
-* $3 - the email footer
-
-See also:
-* {{msg-mw|Notification-user-rights}}
-* {{msg-mw|Notification-user-rights-flyout}}
-* {{msg-mw|Notification-user-rights-email-batch-body}}
-* {{msg-mw|Notification-user-rights-email-subject}}',
+* {{msg-mw|Notification-user-rights-email-batch-body}}',
        'notification-user-rights-email-batch-body' => 'Email notification 
batch body.  Parameters:
 * $1 is a user name, plaintext.  Can be used for gender support
 * $2 is a semicolon separated list of {{msg-mw|notification-user-rights-add}}, 
{{msg-mw|notification-user-rights-remove}}',
@@ -502,9 +411,12 @@
        'echo-email-body-default' => 'Default message content for Echo e-mail 
notifications.
 * $1 is a plain text description of the notification.',
        'echo-email-batch-body-default' => 'Default message for Echo e-mail 
digest notifications',
-       'echo-email-footer-default' => 'Default footer content for Echo e-mail 
notifications.  Parameters:
+       'echo-email-footer-default' => 'Default footer content for Echo text 
e-mail notifications.  Parameters:
 * $1 is the address of the organization that sent the e-mail
 * $2 is "-------..." ({{msg-mw|echo-email-batch-separator}})',
+       'echo-email-footer-default-html' => 'Default footer content for Echo 
html e-mail notifications.  Parameters:
+* $1 is the address of the organization that sent the e-mail
+* $2 is the url to the notification preference page',
        'echo-overlay-link' => 'Link to "all notifications" at the bottom of 
the overlay.
 {{Identical|All notifications}}',
        'echo-overlay-title' => 'Title at the top of the notifications overlay. 
Should include bold tags.',
@@ -526,8 +438,7 @@
 See also:
 * {{msg-mw|Notification-edit-talk-page2}}
 * {{msg-mw|Notification-edit-talk-page-email-batch-body2}}
-* {{msg-mw|Notification-edit-talk-page-email-subject2}}
-* {{msg-mw|Notification-edit-talk-page-email-body2}}',
+* {{msg-mw|Notification-edit-talk-page-email-subject2}}',
        'notification-page-linked-bundle' => 'Bundled message for page-linked 
notification.  Parameters:
 * $1 - the username who performs the action, which can be used for gender 
support
 * $2 - the page title
@@ -549,8 +460,7 @@
 * {{msg-mw|Notification-edit-talk-page2}}
 * {{msg-mw|Notification-edit-talk-page-flyout2}}
 * {{msg-mw|Notification-edit-talk-page-email-batch-body2}}
-* {{msg-mw|Notification-edit-talk-page-email-subject2}}
-* {{msg-mw|Notification-edit-talk-page-email-body2}}',
+* {{msg-mw|Notification-edit-talk-page-email-subject2}}',
        'notification-page-linked-email-batch-bundle-body' => 'Bundled message 
for page-linked email digest notification.  Parameters:
 * $1 - the username who performs the action, which can be used for gender 
support
 * $2 - the link-to page title
@@ -562,8 +472,7 @@
 * {{msg-mw|Notification-page-linked}}
 * {{msg-mw|Notification-page-linked-flyout}}
 * {{msg-mw|Notification-page-linked-email-batch-body}}
-* {{msg-mw|Notification-page-linked-email-subject}}
-* {{msg-mw|Notification-page-linked-email-body}}',
+* {{msg-mw|Notification-page-linked-email-subject}}',
        'echo-email-batch-separator' => '{{optional}}
 Email batch content separator',
        'echo-email-batch-bullet' => '{{optional}}',
diff --git a/Echo.php b/Echo.php
index 1843b2b..de18e60 100755
--- a/Echo.php
+++ b/Echo.php
@@ -61,6 +61,14 @@
 $wgAutoloadClasses['EchoUserRightsFormatter'] = $dir . 
'formatters/UserRightsFormatter.php';
 $wgAutoloadClasses['EchoPageLinkFormatter'] = $dir . 
'formatters/PageLinkFormatter.php';
 
+// Email formatters
+$wgAutoloadClasses['EchoEmailFormatter'] = $dir . 
'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoTextEmailFormatter'] = $dir . 
'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoHTMLEmailFormatter'] = $dir . 
'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoEmailMode'] = $dir . 'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoEmailSingle'] = $dir . 'includes/EmailFormatter.php';
+$wgAutoloadClasses['EchoEmailDigest'] = $dir . 'includes/EmailFormatter.php';
+
 // Internal stuff
 $wgAutoloadClasses['EchoNotifier'] = $dir . 'Notifier.php';
 $wgAutoloadClasses['EchoNotificationController'] = $dir . 
'controller/NotificationController.php';
@@ -432,8 +440,7 @@
                'flyout-message' => 'notification-edit-talk-page-flyout2',
                'flyout-params' => array( 'agent', 'user', 'subject-anchor' ),
                'email-subject-message' => 
'notification-edit-talk-page-email-subject2',
-               'email-body-message' => 
'notification-edit-talk-page-email-body2',
-               'email-body-params' => array( 'email-intro', 'titlelink', 
'summary', 'email-footer' ),
+               'email-subject-params' => array( 'agent' ),
                'email-body-batch-message' => 
'notification-edit-talk-page-email-batch-body2',
                'email-body-batch-params' => array( 'agent' ),
                'email-body-batch-bundle-message' => 
'notification-edit-user-talk-email-batch-bundle-body',
@@ -452,8 +459,6 @@
                'flyout-params' => array( 'agent', 'title', 'difflink', 
'number' ),
                'email-subject-message' => 
'notification-reverted-email-subject2',
                'email-subject-params' => array( 'agent', 'title', 'number' ),
-               'email-body-message' => 'notification-reverted-email-body2',
-               'email-body-params' => array( 'agent', 'title', 'difflink', 
'user', 'summary', 'email-footer', 'number' ),
                'email-body-batch-message' => 
'notification-reverted-email-batch-body2',
                'email-body-batch-params' => array( 'agent', 'title', 'number' 
),
                'icon' => 'revert',
@@ -473,8 +478,6 @@
                'flyout-params' => array( 'agent', 'title', 'link-from-page' ),
                'email-subject-message' => 
'notification-page-linked-email-subject',
                'email-subject-params' => array(),
-               'email-body-message' => 'notification-page-linked-email-body',
-               'email-body-params' => array( 'email-intro', 'title', 
'email-footer', 'link-from-page' ),
                'email-body-batch-message' => 
'notification-page-linked-email-batch-body',
                'email-body-batch-params' => array( 'agent', 'title', 
'link-from-page' ),
                'email-body-batch-bundle-message' => 
'notification-page-linked-email-batch-bundle-body',
@@ -494,8 +497,6 @@
                'flyout-params' => array( 'agent', 'subject-anchor',  'title' ),
                'email-subject-message' => 'notification-mention-email-subject',
                'email-subject-params' => array( 'agent' ),
-               'email-body-message' => 'notification-mention-email-body',
-               'email-body-params' => array( 'agent', 'title', 'summary', 
'subject-link', 'email-footer' ),
                'email-body-batch-message' => 
'notification-mention-email-batch-body',
                'email-body-batch-params' => array( 'agent', 'title' ),
                'icon' => 'chat',
@@ -512,8 +513,6 @@
                'flyout-params' => array( 'agent', 'user-rights-list' ),
                'email-subject-message' => 
'notification-user-rights-email-subject',
                'email-subject-params' => array(),
-               'email-body-message' => 'notification-user-rights-email-body',
-               'email-body-params' => array( 'agent', 'user-rights-list', 
'email-footer' ),
                'email-body-batch-message' => 
'notification-user-rights-email-batch-body',
                'email-body-batch-params' => array( 'agent', 'user-rights-list' 
),
                'icon' => 'site',
diff --git a/Notifier.php b/Notifier.php
index 2e4f03f..884382c 100644
--- a/Notifier.php
+++ b/Notifier.php
@@ -95,6 +95,8 @@
                                $subject = $email['subject'];
                                $body = $email['body'];
 
+                               $body = array( 'text' => $body, 'html' => 
$email['body-html'] );
+
                                UserMailer::send( $toAddress, $fromAddress, 
$subject, $body, $replyAddress );
                                MWEchoEventLogging::logSchemaEchoMail( $user, 
'single' );
                        }
diff --git a/formatters/BasicFormatter.php b/formatters/BasicFormatter.php
index 7354e38..da2bd4b 100644
--- a/formatters/BasicFormatter.php
+++ b/formatters/BasicFormatter.php
@@ -8,15 +8,6 @@
 class EchoBasicFormatter extends EchoNotificationFormatter {
 
        /**
-        * Required parameters
-        * @param array
-        */
-       protected $requiredParameters = array(
-               'title-message',
-               'title-params'
-       );
-
-       /**
         * Notification title data for archive page
         * @param array
         */
@@ -34,11 +25,6 @@
        protected $bundleTitle;
 
        /**
-        * @Todo Check if this varaible can be removed
-        */
-       protected $content;
-
-       /**
         * Notification email data
         * @param array
         */
@@ -49,6 +35,15 @@
         * @param string
         */
        protected $icon;
+
+       /**
+        * Required parameters
+        * @param array
+        */
+       protected $requiredParameters = array (
+               'title-message',
+               'title-params'
+       );
 
        /**
         * Data for constructing bundle message, data in this array
@@ -92,10 +87,6 @@
                                'message' => $params['email-subject-message'],
                                'params' => $params['email-subject-params']
                        ),
-                       'body' => array(
-                               'message' => $params['email-body-message'],
-                               'params' => $params['email-body-params']
-                       ),
                        'batch-body' => array(
                                'message' => 
$params['email-body-batch-message'],
                                'params' => $params['email-body-batch-params']
@@ -124,8 +115,6 @@
                        'payload' => array(),
                        'email-subject-message' => 'echo-email-subject-default',
                        'email-subject-params' => array(),
-                       'email-body-message' => 'echo-email-body-default',
-                       'email-body-params' => array( 'text-notification' ),
                        'email-body-batch-message' => 
'echo-email-batch-body-default',
                        'email-body-batch-params' => array(),
                        'email-body-batch-bundle-message' => '',
@@ -261,25 +250,37 @@
        }
 
        /**
+        * Create text version and/or html version for email notification
+        *
         * @param $event EchoEvent
         * @param $user User
-        * @param $type
+        * @param $type string
         * @return array
         */
        protected function formatEmail( $event, $user, $type ) {
-               $subject = $this->formatFragment( $this->email['subject'], 
$event, $user )->text();
-
-               $body = preg_replace( "/\n{3,}/", "\n\n", 
$this->formatFragment( $this->email['body'], $event, $user )->text() );
+               global $wgEchoNotifications;
 
                if ( $this->bundleData['use-bundle'] && 
$this->email['batch-bundle-body'] ) {
-                       $bodyKey = $this->email['batch-bundle-body'];
+                       $key = $this->email['batch-bundle-body'];
                } else {
-                       $bodyKey = $this->email['batch-body'];
+                       $key = $this->email['batch-body'];
                }
 
-               $batchBody = preg_replace( "/\n{3,}/", "\n\n", 
$this->formatFragment( $bodyKey, $event, $user )->text() );
+               // Echo single email
+               $emailSingle = new EchoEmailSingle( $this, $event, $user );
 
-               return array( 'subject' => $subject, 'body' => $body, 
'batch-body' => $batchBody );
+               $content = array(
+                       // Single email subject
+                       'subject' => $this->formatFragment( 
$this->email['subject'], $event, $user )->escaped(),
+                       // Single email text body
+                       'body' => EchoTextEmailFormatter::newFromEmailMode( 
$emailSingle )->formatEmail(), 
+                       // Single email html body
+                       'body-html' => 
EchoHTMLEmailFormatter::newFromEmailMode( $emailSingle )->formatEmail(),
+                       // Email digest text body
+                       'batch-body' => $this->formatFragment( $key, $event, 
$user )->text()
+               );
+
+               return $content;
        }
 
        /**
@@ -290,7 +291,7 @@
         * @param $user User to format the notification for.
         * @return string
         */
-       protected function formatFragment( $details, $event, $user ) {
+       public function formatFragment( $details, $event, $user ) {
                $message = wfMessage( $details['message'] )
                        ->inLanguage( $user->getOption( 'language' ) );
 
@@ -387,7 +388,6 @@
                return Xml::tags( 'div', array( 'class' => 
'mw-echo-notification-footer' ), $footer ) . "\n";
        }
 
-
        /**
         * Generate links based on output format and passed properties
         * $event EchoEvent
@@ -414,10 +414,10 @@
                }
                $title->setFragment( "#$fragment" );
 
-               if ( $this->outputFormat === 'html' || $this->outputFormat === 
'flyout' ) {
-                       $class = array();
-                       if ( isset( $props['class'] ) ) {
-                               $class['class'] = $props['class'];
+               if ( in_array( $this->outputFormat, array( 'html', 'flyout', 
'htmlemail' ) ) ) {
+                       $attribs = array();
+                       if ( isset( $props['attribs'] ) ) {
+                               $attribs = (array)$props['attribs'];
                        }
 
                        if ( isset( $props['linkText'] ) ) {
@@ -426,25 +426,38 @@
                                $linkText = htmlspecialchars( 
$title->getPrefixedText() );
                        }
 
-                       $message->rawParams( Linker::link( $title, $linkText, 
$class, $param ) );
-               } elseif ( $this->outputFormat === 'email' ) {
-                       // plain text email in some mail client is messing with
-                       // ending punctuation in links, it is better to encode 
them
-                       $url = $title->getCanonicalURL( $param );
-                       // $url should contain all ascii characters now, it's 
safe to use substr()
-                       $lastChar = substr( $url, -1 );
-                       if ( $lastChar && !ctype_alnum( $lastChar ) ) {
-                               $lastChar = str_replace(
-                                       array( '.', '-', '(', ';', '!', ':', 
',' ),
-                                       array( '%2E', '%2D', '%28', '%3B', 
'%21', '%3A', '%2C' ),
-                                       $lastChar
-                               );
-                               $url = substr( $url, 0, -1 ) . $lastChar;
+                       $options = array();
+                       if ( $this->outputFormat === 'htmlemail' ) {
+                               $options = array( 'http' );
                        }
-                       $message->params( $url );
+
+                       $message->rawParams( Linker::link( $title, $linkText, 
$attribs, $param, $options ) );
+               } elseif ( $this->outputFormat === 'email' ) {
+                       $url = $title->getCanonicalURL( $param );
+                       $message->params( $this->sanitizeEmailLink( $url ) );
                } else {
                        $message->params( $title->getFullURL( $param ) );
                }
+       }
+
+       /**
+        * Plain text email in some mail client is misinterpreting the ending
+        * punctuation, this function would encode the last character
+        * @param $url string
+        * @param string
+        */
+       public function sanitizeEmailLink( $url ) {
+               // $url should contain all ascii characters now, it's safe to 
use substr()
+               $lastChar = substr( $url, -1 );
+               if ( $lastChar && !ctype_alnum( $lastChar ) ) {
+                       $lastChar = str_replace(
+                               array( '.', '-', '(', ';', '!', ':', ',' ),
+                               array( '%2E', '%2D', '%28', '%3B', '%21', 
'%3A', '%2C' ),
+                               $lastChar
+                       );
+                       $url = substr( $url, 0, -1 ) . $lastChar;
+               }
+               return $url;
        }
 
        /**
@@ -551,11 +564,12 @@
         *     'border: 1px solid green; text-decoration: none;' (optional)
         * @return String URL for link, or HTML for anchor tag, or empty string
         */
-       protected function getLink( $event, $user, $rank = 'primary', $local = 
true, $urlOnly = false, $style = '' ) {
+       public function getLink( $event, $user, $rank = 'primary', $local = 
true, $urlOnly = false, $style = '' ) {
                $destination = $event->getLinkDestination( $rank );
                if ( !$destination ) {
                        return '';
                }
+
                // Get link parameters based on the destination
                list( $target, $query ) = $this->getLinkParams( $event, $user, 
$destination );
                if ( !$target ) {
@@ -625,24 +639,37 @@
                }
                return array( $target, $query );
        }
-
+       
        /**
         * Helper function for processParams()
         *
         * @param $event EchoEvent
-        * @param $param
+        * @param $param string
         * @param $message Message
         * @param $user User
         * @throws MWException
         */
        protected function processParam( $event, $param, $message, $user ) {
                if ( $param === 'agent' ) {
-                       if ( !$event->getAgent() ) {
+                       $agent = $event->getAgent();
+                       if ( !$agent ) {
                                $message->params( wfMessage( 'echo-no-agent' 
)->text() );
                        } elseif ( !$event->userCan( Revision::DELETED_USER, 
$user ) ) {
                                $message->params( wfMessage( 'rev-deleted-user' 
)->text() );
                        } else {
-                               $message->params( $event->getAgent()->getName() 
);
+                               if ( $this->outputFormat === 'htmlemail' ) {
+                                       $message->rawParams(
+                                               Linker::link(
+                                                       $agent->getUserPage(),
+                                                       $agent->getName(),
+                                                       array( 'style' => 
'text-decoration: none;' ),
+                                                       array(),
+                                                       array( 'http' )
+                                               )
+                                       );
+                               } else {
+                                       $message->params( $agent->getName() );
+                               }
                        }
                // example: {7} others, {99+} others
                } elseif ( $param === 'agent-other-display') {
@@ -667,7 +694,14 @@
                        if ( !$event->getTitle() ) {
                                $message->params( wfMessage( 'echo-no-title' 
)->text() );
                        } else {
-                               $message->params( $this->formatTitle( 
$event->getTitle() ) );
+                               if ( $this->outputFormat === 'htmlemail' ) {
+                                       $props = array (
+                                               'attribs' => array( 'style' => 
'text-decoration: none;' )       
+                                       );
+                                       $this->setTitleLink( $event, $message, 
$props );        
+                               } else {
+                                       $message->params( $this->formatTitle( 
$event->getTitle() ) );
+                               }
                        }
                } elseif ( $param === 'titlelink' ) {
                        $this->setTitleLink( $event, $message );
@@ -679,29 +713,20 @@
                        $this->setOutputFormat( $oldOutputFormat );
 
                        $message->params( $textNotification );
-               } elseif ( $param === 'email-intro' ) {
-                       if ( $this->bundleData['use-bundle'] && isset( 
$this->email['batch-bundle-body']['message'] ) ) {
-                               $detail = array(
-                                       'message' => 
$this->email['batch-bundle-body']['message'],
-                                       'params' => 
$this->email['batch-bundle-body']['params']
-                               );
-                       } else {
-                               $detail = array(
-                                       'message' => 
$this->email['batch-body']['message'],
-                                       'params' => 
$this->email['batch-body']['params']
-                               );
-                       }
-                       $message->params( $this->formatFragment( $detail, 
$event, $user )->text() );
-               } elseif ( $param === 'email-footer' ) {
-                       global $wgEchoEmailFooterAddress;
-                       $message->params(
-                               wfMessage( 'echo-email-footer-default' )
-                               ->inLanguage( $user->getOption( 'language' ) )
-                               ->params( $wgEchoEmailFooterAddress, wfMessage( 
'echo-email-batch-separator' )->text() )
-                               ->text()
-                       );
                } else {
                        throw new MWException( "Unrecognised parameter $param" 
);
                }
+       }       
+
+       /**
+        * Getter method
+        * @param $key string
+        * @return mixed
+        */
+       public function getValue( $key ) {
+               if ( !property_exists( $this, $key ) ) {
+                       throw new MWException( "Call to non-existing property 
$key in " . get_class( $this ) );
+               }
+               return $this->$key;
        }
 }
diff --git a/formatters/CommentFormatter.php b/formatters/CommentFormatter.php
index 8e7f333..25a781e 100644
--- a/formatters/CommentFormatter.php
+++ b/formatters/CommentFormatter.php
@@ -8,10 +8,6 @@
                        $this->title['message-yours'] = 
$params['title-message-yours'];
                }
 
-               if ( isset( $params['content-message-yours'] ) ) {
-                       $this->content['message-yours'] = 
$params['content-message-yours'];
-               }
-
                if ( isset( $params['email-subject-message-yours'] ) ) {
                        $this->email['subject']['message-yours'] = 
$params['email-subject-message-yours'];
                }
diff --git a/formatters/EditFormatter.php b/formatters/EditFormatter.php
index 31dda39..5c02f65 100644
--- a/formatters/EditFormatter.php
+++ b/formatters/EditFormatter.php
@@ -18,7 +18,7 @@
                                return;
                        }
                        $props = array(
-                               'class' => 'mw-echo-diff',
+                               'attribs' => array( 'class' => 'mw-echo-diff' ),
                                'linkText' => wfMessage( 'parentheses', 
wfMessage( 'showdiff' )->text() )->escaped(),
                                'param' => array(
                                        'oldid' => $revid,
diff --git a/formatters/NotificationFormatter.php 
b/formatters/NotificationFormatter.php
index 775eb49..7f0b87e 100644
--- a/formatters/NotificationFormatter.php
+++ b/formatters/NotificationFormatter.php
@@ -12,7 +12,7 @@
         * List of valid output format
         * @var array
         */
-       protected $validOutputFormats = array( 'text', 'flyout', 'html', 
'email' );
+       protected $validOutputFormats = array( 'text', 'flyout', 'html', 
'email', 'htmlemail' );
 
        /**
         * Current output format, default is 'text'
@@ -121,7 +121,7 @@
         * @param User $user The user to format the notification for.
         * @return String The revision comment (or empty string)
         */
-       protected function formatRevisionComment( $event, $user ) {
+       public function formatRevisionComment( $event, $user ) {
                $revision = $event->getRevision();
                if ( $revision === null ) {
                        return '';
@@ -143,6 +143,11 @@
                                        $comment = Xml::tags( 'div', array( 
'class' => 'mw-echo-edit-summary' ), $comment );
                                }
                        }
+
+                       if ( in_array( $this->outputFormat, array( 'htmlemail', 
'email' ) ) && $comment ) {
+                               $comment = wfMessage( 'echo-quotation-marks', 
$comment )->inContentLanguage()->plain();
+                       }
+                       
                        return $comment;
                }
        }
diff --git a/includes/EmailFormatter.php b/includes/EmailFormatter.php
new file mode 100644
index 0000000..93adcdb
--- /dev/null
+++ b/includes/EmailFormatter.php
@@ -0,0 +1,409 @@
+<?php
+
+/**
+ * Abstract class for formatting email notifications
+ */
+abstract class EchoEmailFormatter {
+
+       /**
+        * @var EchoEmailMode
+        */
+       public $emailMode;
+
+       /**
+        * @var EchoBasicFormatter 
+        */
+       public $notifFormatter;
+
+       /**
+        * @param $emailMode EchoEmailMode
+        */
+       public function __construct( EchoEmailMode $emailMode ) {
+               $this->emailMode = $emailMode;
+               $this->notifFormatter = $emailMode->notifFormatter;
+       }
+
+       /**
+        * Factory method for creating EchoEmailFormatter
+        * @param $mode EchoEmailMode
+        * @return EchoEmailFormatter
+        */
+       public static function newFromEmailMode( EchoEmailMode $mode ) {
+               return new static( $mode );
+       }
+       
+       /**
+        * Abstract method for formatting email
+        * @return string
+        */
+       abstract public function formatEmail();
+}
+
+/**
+ * Formatter class for formatting text email notification
+ */
+class EchoTextEmailFormatter extends EchoEmailFormatter {
+
+       /**
+        * @param $emailMode EchoEmailMode
+        */
+       public function __construct( EchoEmailMode $emailMode ) {
+               parent::__construct( $emailMode );
+       }
+
+       /**
+        * Formatting text email notification
+        * @return string
+        */
+       public function formatEmail() {
+
+               $template = $this->emailMode->getTextTemplate();
+
+               foreach ( $this->emailMode->component as $val ) {
+                       $func = 'get' . ucfirst( $val );
+                       $template = str_replace( "%%$val%%", 
$this->emailMode->$func( 'text' ), $template );
+               }
+
+               // Remove redundant newline characters
+               return $this->removeExtraNewLine( $template );
+       }
+
+       /**
+        * Remove extra newline from a text content
+        * @param $text string
+        * @return string
+        */
+       protected function removeExtraNewLine( $text ) {
+               return  preg_replace( "/\n{3,}/", "\n\n", $text );
+       }
+
+}
+
+/**
+ * Formatter class for formatting HTML email notification
+ */
+class EchoHTMLEmailFormatter extends EchoEmailFormatter {
+
+       /**
+        * @param $emailMode EchoEmailMode
+        */
+       public function __construct( EchoEmailMode $emailMode ) {
+               parent::__construct( $emailMode );
+       }
+
+       /**
+        * Formatting HTML email notification
+        * @return string
+        */
+       public function formatEmail() {
+               $outputFormat = $this->notifFormatter->getValue( 'outputFormat' 
);
+               $this->notifFormatter->setOutputFormat( 'htmlemail' );
+
+               $template = $this->emailMode->getHTMLTemplate();
+
+               foreach ( $this->emailMode->component as $val ) {
+                       $func = 'get' . ucfirst( $val );
+                       $template = str_replace( "%%$val%%", 
$this->emailMode->$func( 'html' ), $template );
+               }
+
+               $this->notifFormatter->setOutputFormat( $outputFormat );
+
+               return $template;
+       }
+}
+
+/**
+ * Abstract entity that represents an email delivery mode
+ */
+abstract class EchoEmailMode {
+
+       /**
+        * @var EchoBasicFormatter
+        */
+       public $notifFormatter;
+
+       /**
+        * Email components
+        * @var array
+        */
+       public $component;
+
+       /**
+        * @var EchoEvent
+        */
+       public $event;
+
+       /**
+        * @var User
+        */
+       public $user;
+
+       /**
+        * @param $notifFormatter EchoBasicFormatter
+        * @param $event EchoEvent
+        * @param $user User
+        */
+       public function __construct( EchoBasicFormatter $notifFormatter, 
EchoEvent $event, User $user ) {
+               $this->notifFormatter = $notifFormatter;        
+               $this->event = $event;
+               $this->user = $user;
+               // All email delivery mode share the same footer
+               $this->component = array( 'footer' );
+       }
+
+       /**
+        * Get text email template
+        * @return string
+        */
+       abstract public function getTextTemplate();
+
+       /**
+        * Get html email template
+        * @return string
+        */
+       abstract public function getHTMLTemplate();
+
+       /**
+        * Get the footer component
+        * @return string
+        */
+       public function getFooter( $format ) {
+               global $wgEchoEmailFooterAddress;
+               
+               if ( $format === 'text' ) {
+                       return wfMessage( 'echo-email-footer-default' )
+                               ->params( $wgEchoEmailFooterAddress, wfMessage( 
'echo-email-batch-separator' )->text() )
+                               ->text();
+               } else {
+                       $title = Title::makeTitle( NS_SPECIAL, 'Preferences' );
+                       $title->setFragment( "#mw-prefsection-echo" );
+                       return wfMessage( 'echo-email-footer-default-html' )
+                                       ->params( $wgEchoEmailFooterAddress )
+                                       ->rawParams( $title->getCanonicalURL() )
+                                       ->text();
+               }
+       }
+
+       /**
+        * The style for primary link
+        */
+       protected function getPrimaryLinkCSS() {
+               return 'cursor:pointer; text-align:center; 
text-decoration:none; padding:.5em 1.2em .55em; color:#d9eef7; 
background:#0095cd;';
+       }
+
+       /**
+        * The style for secondary link
+        */
+       protected function getSecondaryLinkCSS() {
+               return 'text-decoration: none;font-size: 13px;';
+       }
+}
+
+/**
+ * Entity that represents a single email delivery mode
+ */
+class EchoEmailSingle extends EchoEmailMode {
+
+       /**
+        * @param $notifFormatter EchoBasicFormatter
+        * @param $event EchoEvent
+        * @param $user User
+        */
+       public function __construct( EchoBasicFormatter $notifFormatter, 
EchoEvent $event, User $user ) {
+               parent::__construct( $notifFormatter, $event, $user );
+               $this->component = array_merge( $this->component, array ( 
'emailIcon', 'intro', 'summary', 'action' ) );
+       }
+
+       /**
+        * Get the intro component
+        * @return string
+        */
+       public function getIntro() {
+               $bundle = $this->notifFormatter->getValue( 'bundleData' );
+               $email  = $this->notifFormatter->getValue( 'email' );
+
+               if ( $bundle['use-bundle'] && 
$email['batch-bundle-body']['message'] ) {
+                       $detail = $email['batch-bundle-body'];
+               } else {
+                       $detail = $email['batch-body']; 
+               }
+               
+               return $this->notifFormatter->formatFragment( $detail, 
$this->event, $this->user );     
+       }
+
+       /**
+        * Get the summary component
+        * @return string
+        */
+       public function getSummary() {
+               return $this->notifFormatter->formatRevisionComment( 
$this->event, $this->user );
+       }
+
+       /**
+        * Get the action component
+        * @return string
+        */
+       public function getAction( $format ) {
+               $link = array();
+               $ranks = array( 'primary', 'secondary' );
+
+               foreach ( $ranks as $rank ) {
+                       $message = $this->event->getLinkMessage( $rank );
+
+                       // Valid call to action should have link text
+                       if ( !$message ) {
+                               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 );
+                       }
+               }
+
+               // Add some spacing between the two action links
+               if ( $format === 'text' ) {
+                       $link = implode( "\n\n", $link );
+               } else {
+                       $link = implode( "<br /><br />", $link );       
+               }
+               
+               return $link;
+       }
+
+       /**
+        * Get the email icon component
+        * @return string
+        */
+       public function getEmailIcon() {
+               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 );
+       }
+
+       /**
+        * Get template for text email
+        * @return string
+        */
+       public function getTextTemplate() {
+               return <<< EOF
+%%intro%%
+
+%%summary%%
+
+%%action%%
+
+%%footer%%
+EOF;
+       }
+
+       /**
+        * Get template for html email
+        * @return string
+        */
+       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">&nbsp;</td>
+                                <td bgcolor="#FFFFFF" width = "61">&nbsp;</td>
+                                <td bgcolor="#FFFFFF" width = "469" style = 
"line-height:50px;">&nbsp;</td>
+                                <td bgcolor="#FFFFFF" width = "35">&nbsp;</td>
+                        </tr><tr>
+                                <td bgcolor="#FFFFFF" width = "35" 
rowspan="2">&nbsp;</td>
+                                <td bgcolor="#FFFFFF" width = "61" align = 
"center" valign="top" rowspan="2"><img src="%%emailIcon%%" alt = "" height = 
"30" width = "30"></td>
+                                <td bgcolor="#FFFFFF" width = "369" style = 
"font-family:sans-serif; font-size:15px; line-height:19px; 
color:#C9C9C9;">%%intro%%</td>
+                                <td bgcolor="#FFFFFF" width = "35" rowspan = 
"2">&nbsp;</td>
+                        </tr><tr>
+                                <td bgcolor="#FFFFFF" width = "61" style = 
"font-family: sans-serif; font-size:16px; line-height: 20px; font-weight: 600;">
+                                       <table cellspacing="0" cellpadding="0" 
border="0" style="margin-top: 12px;">
+                                                <tr>
+                                                       <td bgcolor="#FFFFFF" 
style="font-family: sans-serif; font-size:16px; font-weight: 600;">
+                                                               %%summary%%
+                                                       </td>
+                                                </tr>
+                                        </table>
+                                        <table cellspacing="0" cellpadding="0" 
border="0" style="margin-top: 25px;">
+                                                <tr>
+                                                       <td bgcolor="#FFFFFF" 
style="font-family: sans-serif; font-size:14px;">
+                                                               %%action%%
+                                                       </td>
+                                                </tr>
+                                        </table>
+                                </td>
+                        </tr><tr>
+                                <td bgcolor="#FFFFFF" width = "35">&nbsp;</td>
+                                <td bgcolor="#FFFFFF" width = "61">&nbsp;</td>
+                                <td bgcolor="#FFFFFF" width = "369" style = 
"line-height:30px;">&nbsp;</td>
+                                <td bgcolor="#FFFFFF" width = "35">&nbsp;</td>
+                        </tr><tr>
+                                <td bgcolor="#F8F8F8" width = "35">&nbsp;</td>
+                                <td bgcolor="#F8F8F8" width = "61">&nbsp;</td>
+                                <td bgcolor="#F8F8F8" width = "369" style = 
"font-family:sans-serif; font-size:12px; line-height:15px; color:#C9C9C9"><br />
+                                %%footer%%
+<br /><br />
+                        </td>
+                                <td bgcolor="#F8F8F8" width = "35">&nbsp;</td>
+                        </tr>
+                </table>
+                <br><br></center>
+        </td>
+</tr>
+</table>
+</body></html> 
+EOF;
+       }
+
+}
+
+/**
+ * Class that represents email digest delivery mode
+ * @Todo - To be completed for email digest
+ */
+class EchoEmailDigest extends EchoEmailMode {
+
+       public function __construct( EchoBasicFormatter $notifFormatter, 
$event, $user ) {
+               parent::__construct( $notifFormatter, $event, $user );
+               $this->component = array_merge( $this->component, array( 
'header', 'intro', 'digestList' ) );
+       }
+
+       public function getHeader() {}
+       public function getIntro() {}
+       public function getDigestList() {}
+       public function getFooter() {}
+
+       public function getTextTemplate() {}
+       
+       public function getHTMLTemplate() {}
+
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/70112
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia4b98b14e135742b84f1b0e04589b0efdd24e954
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Bsitu <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to