http://www.mediawiki.org/wiki/Special:Code/MediaWiki/89637

Revision: 89637
Author:   nagelp
Date:     2011-06-07 09:20:13 +0000 (Tue, 07 Jun 2011)
Log Message:
-----------
Initial commit of new extension Notificator

Added Paths:
-----------
    trunk/extensions/Notificator/
    trunk/extensions/Notificator/Notificator.body.php
    trunk/extensions/Notificator/Notificator.i18n.php
    trunk/extensions/Notificator/Notificator.php
    trunk/extensions/Notificator/Notificator.sql
    trunk/extensions/Notificator/SpecialNotificator.php
    trunk/extensions/Notificator/diff-in-mail.css

Added: trunk/extensions/Notificator/Notificator.body.php
===================================================================
--- trunk/extensions/Notificator/Notificator.body.php                           
(rev 0)
+++ trunk/extensions/Notificator/Notificator.body.php   2011-06-07 09:20:13 UTC 
(rev 89637)
@@ -0,0 +1,200 @@
+<?php
+
+if (!defined('MEDIAWIKI')) {
+       echo "Not a valid entry point";
+       exit(1);
+}
+
+class Notificator {
+
+public static function notificator_Render($parser, $receiver = '', 
$receiverLabel = '') {
+       global $wgScript, $wgTitle;
+
+       if(! $receiverLabel) {
+               $receiverLabel = $receiver;
+       }
+
+       // Check that the database table is in place
+       if(! Notificator::checkDatabaseTableExists()) {
+               $output = '<span class="error">' . 
wfMsg('notificator-db-table-does-not-exist') . '</span>';
+               return array($output, 'noparse' => true, 'isHTML' => true);
+       }
+
+       // Check whether the parameter is a valid e-mail address or not
+       if($receiver && Notificator::checkEmailAddress($receiver)) {
+               // Valid e-mail address available, so just show a button
+               $output = '<form action="' . $wgScript . '/Special:Notificator" 
method="post" enctype="multipart/form-data"> 
+<input type="hidden" name="pageId" value="' . $wgTitle->getArticleID() . '" />
+<input type="hidden" name="revId" value="' . $wgTitle->getLatestRevID() . '" />
+<input type="hidden" name="receiver" value="' . $receiver . '" />
+<input type="submit" value="' . wfMsg('notify-address-or-name', 
htmlspecialchars($receiverLabel)) . '" />
+</form>';
+       } else {
+               // No valid e-mail address available, show text entry field and 
button
+               $output = '<form action="' . $wgScript . '/Special:Notificator" 
method="post" enctype="multipart/form-data"> 
+<input type="hidden" name="pageId" value="' . $wgTitle->getArticleID() . '" />
+<input type="hidden" name="revId" value="' . $wgTitle->getLatestRevID() . '" />
+<input type="text" name="receiver" value="' . wfMsg('e-mail-address') . '" 
onfocus="if (this.value == \'' . wfMsg('e-mail-address') . '\') 
{this.value=\'\'}" />
+<input type="submit" value="' . wfMsg('notify') . '" />
+</form>';
+       }
+
+       return $parser->insertStripItem($output, $parser->mStripState);
+}
+
+private function checkDatabaseTableExists() {
+       $dbr = wfGetDB(DB_SLAVE);
+       $res = $dbr->tableExists('notificator');
+       return $res;
+}
+
+private function getDiffCss() {
+       $ret = '';
+       $file = fopen(dirname(__FILE__) . '/diff-in-mail.css', 'r');
+       while(!feof($file)) {
+               $ret = $ret . fgets($file, 4096);
+       }
+       fclose ($file);
+       return $ret;
+}
+
+public static function checkEmailAddress($string) {
+// from http://www.linuxjournal.com/article/9585
+       $isValid = true;
+       $atIndex = strrpos($string, "@");
+       if (is_bool($atIndex) && !$atIndex) {
+               $isValid = false;
+       } else {
+               $domain = substr($string, $atIndex+1);
+               $local = substr($string, 0, $atIndex);
+               $localLen = strlen($local);
+               $domainLen = strlen($domain);
+               if ($localLen < 1 || $localLen > 64) {
+                       // local part length exceeded
+                       $isValid = false;
+               }
+               else if ($domainLen < 1 || $domainLen > 255) {
+                       // domain part length exceeded
+                       $isValid = false;
+               }
+               else if ($local[0] == '.' || $local[$localLen-1] == '.') {
+                       // local part starts or ends with '.'
+                       $isValid = false;
+               }
+               else if (preg_match('/\\.\\./', $local)) {
+                       // local part has two consecutive dots
+                       $isValid = false;
+               }
+               else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {
+                       // character not valid in domain part
+                       $isValid = false;
+               }
+               else if (preg_match('/\\.\\./', $domain)) {
+                       // domain part has two consecutive dots
+                       $isValid = false;
+               }
+               else if 
(!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', 
str_replace("\\\\","",$local))) {
+                       // character not valid in local part unless 
+                       // local part is quoted
+                       if (!preg_match('/^"(\\\\"|[^"])+"$/', 
str_replace("\\\\","",$local))) {
+                               $isValid = false;
+                       }
+               }
+               if ($isValid && !(checkdnsrr($domain,"MX") || 
checkdnsrr($domain,"A"))) {
+                       // domain not found in DNS
+                       $isValid = false;
+               }
+       }
+       return $isValid;
+}
+
+public static function getLastNotifiedRevId($pageId, $revId, $receiver) {
+       // Returns -1 if any parameter is missing
+       // Returns -2 if the database revId is the same as the given revId (= 
notified already)
+       // Returns revId from the database - if there is no record, return 0
+
+       if (! $pageId || ! $revId || ! $receiver) {
+               return -1;
+       }
+
+       // Get $oldRevId from database
+       $dbr = wfGetDB(DB_SLAVE);
+       $res = $dbr->select('notificator',                    // table
+                      'rev_id',                         // vars (columns of 
the table)
+                      array('page_id' => (int)$pageId, 'receiver_email' => 
$receiver)  // conds
+                          );
+
+       $row = $dbr->fetchRow($res);
+
+       $oldRevId = $row[rev_id];
+
+       if(! $oldRevId) {
+               $oldRevId = 0;
+       } elseif ($oldRevId == $revId) {
+               $oldRevId = -2;
+       }
+
+       return $oldRevId;
+}
+
+public static function getNotificationDiffHtml($oldRevId, $revId) {
+       $oldRevisionObj = Revision::newFromId($oldRevId);
+       $newRevisionObj = Revision::newFromId($revId);
+
+       if($oldRevisionObj->getTitle() != $newRevisionObj->getTitle()) {
+               return '<span class="error">' . 
wfMsg('revs-not-from-same-title') . '</span>';
+       }
+
+       $titleObj = $oldRevisionObj->getTitle();
+
+       $differenceEngineObj = new DifferenceEngine($titleObj, $oldRevId, 
$revId);
+
+       $notificationDiffHtml = '<style media="screen" type="text/css">' . 
Notificator::getDiffCss() . '</style><table class="diff">
+<col class="diff-marker" />
+<col class="diff-content" />
+<col class="diff-marker" />
+<col class="diff-content" />
+' . $differenceEngineObj->getDiffBody() . '
+</table>';
+
+       return $notificationDiffHtml;
+}
+
+public static function sendNotificationMail($receiver, $mailSubject, 
$notificationText) {
+       global $ngFromAddress;
+       $headers = 'From: ' . $ngFromAddress . "\r\n" .
+             'X-Mailer: PHP/' . phpversion() . "\r\n" .
+             'MIME-Version: 1.0' . "\r\n" .
+             'Content-type: text/html; charset=utf-8' . "\r\n";
+       $encodedMailSubject = mb_encode_mimeheader($mailSubject,"UTF-8", "B", 
"\n");
+
+       return mail($receiver, $encodedMailSubject, $notificationText, 
$headers);
+}
+
+public static function recordNotificationInDatabase($pageId, $revId, 
$receiver) {
+       $lastNotifiedRevId = Notificator::getLastNotifiedRevId($pageId, $revId, 
$receiver);
+       if($lastNotifiedRevId > 0) {
+               $dbw = wfGetDB(DB_MASTER);
+               $res = $dbw->update('notificator',                    // table
+                        array('rev_id' => (int)$revId),                        
 // vars (columns of the table)
+                        array('page_id' => (int)$pageId, 'receiver_email' => 
$receiver)  // conds
+                            );
+               return $res;
+       } elseif($lastNotifiedRevId == 0) {
+               $dbw = wfGetDB(DB_MASTER);
+               $res = $dbw->insert('notificator',                    // table
+                        array('page_id' => (int)$pageId,
+                              'rev_id' => (int)$revId,
+                              'receiver_email' => $receiver) // "$a"
+                            );
+               return $res;
+       } elseif($lastNotifiedRevId < 0) {
+               return false;
+       }
+}
+
+public static function getReturnToText($linkToPage, $pageTitle) {
+       return '<p style="margin-top: 2em;">' . wfMsg('return-to') . ' <a 
href="' . $linkToPage . '">' . $pageTitle . '</a>.';
+}
+
+}

Added: trunk/extensions/Notificator/Notificator.i18n.php
===================================================================
--- trunk/extensions/Notificator/Notificator.i18n.php                           
(rev 0)
+++ trunk/extensions/Notificator/Notificator.i18n.php   2011-06-07 09:20:13 UTC 
(rev 89637)
@@ -0,0 +1,54 @@
+<?php
+
+$aliases = array();
+$messages = array();
+ 
+$aliases['en'] = array(
+       'Notificator' => array( 'Notificator' ),
+);
+ 
+$messages['en'] = array(
+       'notificator' => 'Notificator',
+       'notificator-description' => 'Notifies someone by e-mail about changes 
to a page when a button on that page gets clicked.',
+       'notificator-db-table-does-not-exist' => 'Database table 
\'notificator\' does not exist. The update.php maintenance script needs to be 
run before the Notificator extension can be used.',
+       'e-mail-address' => 'e-mail address',
+       'notify' => 'Notify', // Button label
+       'notify-address-or-name' => 'Notify $1', // Button label
+       'revs-not-from-same-title' => 'Revision IDs are not from the same 
title/article', // Unlikely to be seen by the user
+       'return-to' => 'Return to', // Return to <link> - at the bottom of the 
special page
+       'special-page-accessed-directly' => 'This special page cannot be 
accessed directly. It is intended to be used through a Notificator button.',
+       'e-mail-address-invalid' => 'The provided e-mail address is invalid.',
+       'notification-not-sent' => 'Notification <em>not</em> sent.',
+       'change-tag' => 'change',
+       'new-tag' => 'new',
+       'notification-text-changes' => '$1 wants to notify you about the 
following changes to $2:',
+       'notification-text-new' => '$1 wants to notify you about $2.',
+       'following-e-mail-sent-to' => 'The following e-mail has been sent to 
<em>$1</em>:',
+       'subject' => 'Subject:', // The subject line of an e-mail
+       'error-sending-e-mail' => 'There was an error when sending the 
notification e-mail to <em>$1</em>.',
+       'error-parameter-missing' => 'Error: Missing parameter.', // Unlikely 
to be seen by the user
+       'notified-already' => '$1 has been notified about this page or page 
change before.',
+);
+
+$messages['de'] = array(
+       'notificator' => 'Notificator',
+       'notificator-description' => 'Sendet Benachrichtungs-Mails über 
Seitenänderungen, wenn ein Knopf auf der entsprechenden Seite betätigt wird.',
+       'notificator-db-table-does-not-exist' => 'Datenbanktabelle 
\'notificator\' existiert nicht. Das update.php Maintenance Script muss 
ausgeführt werden, bevor die Notificator-Extension verwendet werden kann.',
+       'e-mail-address' => 'E-Mail-Adresse',
+       'notify' => 'Benachrichtigen',
+       'notify-address-or-name' => '$1 benachrichtigen',
+       'revs-not-from-same-title' => 'Revision-IDs gehören nicht zum selben 
Titel/Artikel',
+       'return-to' => 'Zurück zu',
+       'special-page-accessed-directly' => 'Auf diese Spezial-Seite kann nicht 
direkt zugegriffen werden. Sie sollte über einen Notificator-Knopf verwendet 
werden.',
+       'e-mail-address-invalid' => 'Die angegebene E-Mail-Adresse ist 
ungültig.',
+       'notification-not-sent' => 'Benachrichtigung <em>nicht</em> gesendet.',
+       'change-tag' => 'Änderung',
+       'new-tag' => 'Neu',
+       'notification-text-changes' => '$1 möchte Sie zu folgenden Änderungen 
an $2 benachrichtigen:',
+       'notification-text-new' => '$1 möchte Sie zu $2 benachrichtigen.',
+       'following-e-mail-sent-to' => 'Folgende E-Mail wurde an <em>$1</em> 
gesendet:',
+       'subject' => 'Betreff:',
+       'error-sending-e-mail' => 'Beim Versenden der Benachrichtigungs-Mail an 
<em>$1</em> ist ein Fehler aufgetreten.',
+       'error-parameter-missing' => 'Fehler: Fehlender Parameter.',
+       'notified-already' => '$1 wurde bereits zu dieser Seite oder 
Seitenänderung benachrichtigt.',
+);
\ No newline at end of file

Added: trunk/extensions/Notificator/Notificator.php
===================================================================
--- trunk/extensions/Notificator/Notificator.php                                
(rev 0)
+++ trunk/extensions/Notificator/Notificator.php        2011-06-07 09:20:13 UTC 
(rev 89637)
@@ -0,0 +1,51 @@
+<?php
+
+if (!defined('MEDIAWIKI')) {
+       echo "Not a valid entry point";
+       exit(1);
+}
+
+$wgExtensionCredits['parserhook'][] = array(
+       'path' => __FILE__,     // Magic so that svn revision number can be 
shown
+       'name' => 'Notificator',
+       'descriptionmsg' => 'notificator-description',
+       'version' => '1.0.2',
+       'author' => 'Patrick Nagel',
+       'url' => "http://www.mediawiki.org/wiki/Extension:Notificator";,
+);
+
+$wgAutoloadClasses['Notificator'] = dirname(__FILE__) . 
'/Notificator.body.php';
+$wgAutoloadClasses['SpecialNotificator'] = dirname(__FILE__) . 
'/SpecialNotificator.php';
+
+$wgHooks['LoadExtensionSchemaUpdates'][] = 'notificator_AddDatabaseTable';
+$wgHooks['ParserTestTables'][]           = 'notificator_ParserTestTables';
+$wgHooks['ParserFirstCallInit'][]        = 'notificator_Setup';
+$wgHooks['LanguageGetMagic'][]           = 'notificator_Magic';
+
+$wgSpecialPages['Notificator'] = 'SpecialNotificator';
+
+$wgExtensionMessagesFiles['Notificator'] = dirname( __FILE__ ) . 
'/Notificator.i18n.php';
+
+global $wgPasswordSender, $ngFromAddress;
+if(! $ngFromAddress) $ngFromAddress = $wgPasswordSender;
+
+function notificator_AddDatabaseTable() {
+       global $wgExtNewTables;
+       $wgExtNewTables[] = array('notificator', dirname( __FILE__ ) . 
'/Notificator.sql');
+       return true;
+}
+
+function notificator_ParserTestTables(&$tables) {
+  $tables[] = 'notificator';
+  return true;
+}
+
+function notificator_Setup(&$parser) {
+       $parser->setFunctionHook('notificator', 
'Notificator::notificator_Render');
+       return true;
+}
+
+function notificator_Magic(&$magicWords, $langCode) {
+       $magicWords['notificator'] = array( 0, 'notificator' );
+       return true;
+}

Added: trunk/extensions/Notificator/Notificator.sql
===================================================================
--- trunk/extensions/Notificator/Notificator.sql                                
(rev 0)
+++ trunk/extensions/Notificator/Notificator.sql        2011-06-07 09:20:13 UTC 
(rev 89637)
@@ -0,0 +1,6 @@
+CREATE TABLE IF NOT EXISTS notificator (
+  page_id int(10) NOT NULL,
+  rev_id int(10) NOT NULL,
+  receiver_email tinytext NOT NULL,
+  PRIMARY KEY (page_id, rev_id, receiver_email(10))
+);
\ No newline at end of file

Added: trunk/extensions/Notificator/SpecialNotificator.php
===================================================================
--- trunk/extensions/Notificator/SpecialNotificator.php                         
(rev 0)
+++ trunk/extensions/Notificator/SpecialNotificator.php 2011-06-07 09:20:13 UTC 
(rev 89637)
@@ -0,0 +1,74 @@
+<?php
+
+if (!defined('MEDIAWIKI')) {
+       echo "Not a valid entry point";
+       exit(1);
+}
+
+class SpecialNotificator extends SpecialPage {
+
+function __construct() {
+       parent::__construct( 'Notificator' );
+       wfLoadExtensionMessages('Notificator');
+}
+
+function execute($par) {
+       global $wgRequest, $wgOut, $wgUser;
+
+       $this->setHeaders();
+
+       # Get request data from, e.g.
+       $pageId = $wgRequest->getText('pageId');
+       $revId = $wgRequest->getText('revId');
+       $receiver = $wgRequest->getText('receiver');
+
+       if(! $pageId || ! $revId || ! $receiver ) {
+               $output = '<span class="error">' . 
wfMsg('special-page-accessed-directly') . '</span>';
+       } else {
+               $titleObj = Title::newFromID($pageId);
+               $pageTitle = $titleObj->getFullText();
+               $linkToPage = $titleObj->getFullURL();
+
+               if(! Notificator::checkEmailAddress($receiver)) {
+                       $output = '<span class="error">' . 
wfMsg('e-mail-address-invalid') . ' ' . wfMsg('notification-not-sent') . 
'</span>';
+                       $output .= Notificator::getReturnToText($linkToPage, 
$pageTitle);
+                       $wgOut->addHTML($output);
+                       return;
+               }
+
+               $oldRevId = Notificator::getLastNotifiedRevId($pageId, $revId, 
$receiver);
+
+               if($oldRevId >= 0) {
+                       if($oldRevId > 0) {
+                               // Receiver has been notified before - send the 
diff to the last notified revision
+                               $mailSubjectPrefix = '[' . wfMsg('change-tag') 
. '] ';
+
+                               $wgOut->addModules('mediawiki.legacy.diff');
+                               $diff = 
Notificator::getNotificationDiffHtml($oldRevId, $revId);
+                               $notificationText = 
wfMsg('notification-text-changes', htmlspecialchars($wgUser->getName()), '<a 
href="' . $linkToPage . '">' . $pageTitle . '</a>') . '<div style="margin-top: 
1em;">' . $diff . '</div>';
+                       } else {
+                               // Receiver has never been notified about this 
page - so don't send a diff, just the link
+                               $mailSubjectPrefix = '[' . wfMsg('new-tag') . 
'] ';
+                               $notificationText = 
wfMsg('notification-text-new', htmlspecialchars($wgUser->getName()), '<a 
href="' . $linkToPage . '">' . $pageTitle . '</a>');
+                       }
+                       $mailSubject = htmlspecialchars($mailSubjectPrefix . 
$pageTitle);
+
+                       if (Notificator::sendNotificationMail($receiver, 
$mailSubject, $notificationText)) {
+                               $output = '<strong>' . 
wfMsg('following-e-mail-sent-to', htmlspecialchars($receiver)) . '</strong><div 
style="margin-top: 1em;"><h3>' . wfMsg('subject') . ' ' . $mailSubject . 
'</h3><p>' . $notificationText . '</p></div>';
+                               
Notificator::recordNotificationInDatabase($pageId, $revId, $receiver);
+                       } else {
+                               $output = '<span class="error">' . 
wfMsg('error-sending-e-mail', htmlspecialchars($receiver)) . '</span>';
+                       }
+               } elseif($oldRevId == -1) {
+                       $output = '<span class="error">' . 
wfMsg('error-parameter-missing') . '</span>';
+               } elseif($oldRevId == -2) {
+                       $output = '<strong>' . wfMsg('notified-already', 
htmlspecialchars($receiver)) . ' ' . wfMsg('notification-not-sent') . 
'</strong>';
+               }
+
+               $output .= Notificator::getReturnToText($linkToPage, 
$pageTitle);
+       }
+
+       $wgOut->addHTML($output);
+}
+
+}

Added: trunk/extensions/Notificator/diff-in-mail.css
===================================================================
--- trunk/extensions/Notificator/diff-in-mail.css                               
(rev 0)
+++ trunk/extensions/Notificator/diff-in-mail.css       2011-06-07 09:20:13 UTC 
(rev 89637)
@@ -0,0 +1,49 @@
+td.diff-otitle,
+td.diff-ntitle {
+        text-align: center;
+}
+td.diff-marker {
+        text-align: right;
+}
+td.diff-lineno {
+        font-weight: bold;
+}
+td.diff-addedline {
+        background: #cfc;
+        font-size: smaller;
+}
+td.diff-deletedline {
+        background: #ffa;
+        font-size: smaller;
+}
+td.diff-context {
+        background: #eee;
+        font-size: smaller;
+}
+.diffchange {
+        color: red;
+        font-weight: bold;
+        text-decoration: none;
+        white-space: pre-wrap;
+        white-space: -moz-pre-wrap;
+}
+
+table.diff {
+        border: none;
+        width: 98%;
+        border-spacing: 4px;
+        table-layout: fixed;
+}
+table.diff td {
+        padding: 0;
+}
+table.diff col.diff-marker {
+        width: 2%;
+}
+table.diff col.diff-content {
+        width: 48%;
+}
+table.diff td div {
+        word-wrap: break-word;
+        overflow: auto;
+} 


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

Reply via email to