]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Complete email summary sending system
authorEvan Prodromou <evan@status.net>
Mon, 8 Nov 2010 18:10:09 +0000 (13:10 -0500)
committerEvan Prodromou <evan@status.net>
Mon, 8 Nov 2010 18:10:09 +0000 (13:10 -0500)
Added the necessary classes to send email summaries. First, added a
script to run on a daily basis. Second, added a queue handler for
sending email summaries for users, and another to queue summaries for
all users on the site. Fixed up the email_summary_status table to
store the last-sent notice id, rather than a datetime (since we don't
support 'since' parameters anymore). Finally, made the plugin class
load the right modules when needed.

plugins/EmailSummary/EmailSummaryPlugin.php
plugins/EmailSummary/Email_summary_status.php
plugins/EmailSummary/sendemailsummary.php [new file with mode: 0644]
plugins/EmailSummary/siteemailsummaryhandler.php [new file with mode: 0644]
plugins/EmailSummary/useremailsummaryhandler.php [new file with mode: 0644]

index dd72329f8887f48c0b61b7823bd1ae6fe98bbe49..03577bb4a7fb1c15623aa069f4d1eab114180466 100644 (file)
@@ -63,7 +63,7 @@ class EmailSummaryPlugin extends Plugin
                                                  false, 'PRI'),
                                    new ColumnDef('send_summary', 'tinyint', null,
                                                 false, null, 1),
-                                   new ColumnDef('last_summary', 'datetime', null,
+                                   new ColumnDef('last_summary_id', 'integer', null,
                                                 true),
                                    new ColumnDef('created', 'datetime', null,
                                                 false),
@@ -89,6 +89,10 @@ class EmailSummaryPlugin extends Plugin
 
         switch ($cls)
         {
+        case 'SiteEmailSummaryHandler':
+        case 'UserEmailSummaryHandler':
+            include_once $dir . '/'.strtolower($cls).'.php';
+           return false;
         case 'Email_summary_status':
             include_once $dir . '/'.$cls.'.php';
             return false;
@@ -116,4 +120,19 @@ class EmailSummaryPlugin extends Plugin
                             _m('Send an email summary of the inbox to users.'));
         return true;
     }
+
+    /**
+     * Register our queue handlers
+     * 
+     * @param QueueManager $qm Current queue manager
+     * 
+     * @return boolean hook value
+     */
+    
+    function onEndInitializeQueueManager($qm)
+    {
+       $qm->connect('sitesum', 'SiteEmailSummaryHandler');
+       $qm->connect('usersum', 'UserEmailSummaryHandler');
+       return true;
+    }
 }
index a0462fd04cedb8d355e6a72452bf5b508ef8e8c6..5b5b231e349b2e2aad76d8e7aeb4ce011634e46b 100644 (file)
@@ -52,9 +52,9 @@ class Email_summary_status extends Memcached_DataObject
     public $__table = 'email_summary_status'; // table name
     public $user_id;                         // int(4)  primary_key not_null
     public $send_summary;                    // tinyint not_null
-    public $last_summary;                    // int(4)  primary_key not_null
-    public $created;                         // int(4)  primary_key not_null
-    public $modified;                        // int(4)  primary_key not_null
+    public $last_summary_id;                 // int(4)  null
+    public $created;                         // datetime not_null
+    public $modified;                        // datetime not_null
 
     /**
      * Get an instance by key
@@ -83,9 +83,9 @@ class Email_summary_status extends Memcached_DataObject
     {
         return array('user_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
                     'send_summary' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
-                    'last_summary' => DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME,
-                    'created' => DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME,
-                    'modified' => DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME);
+                    'last_summary_id' => DB_DATAOBJECT_INT,
+                    'created' => DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
+                    'modified' => DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
     }
 
     /**
@@ -154,14 +154,14 @@ class Email_summary_status extends Memcached_DataObject
      * @return Email_summary_status instance for this user, with count already incremented.
      */
 
-    static function getLastSummary($user_id)
+    static function getLastSummaryID($user_id)
     {
         $ess = Email_summary_status::staticGet('user_id', $user_id);
        
        if (!empty($ess)) {
-           return $ess->last_summary;
+           return $ess->last_summary_id;
        } else {
-           return 1;
+           return null;
        }
     }
 }
diff --git a/plugins/EmailSummary/sendemailsummary.php b/plugins/EmailSummary/sendemailsummary.php
new file mode 100644 (file)
index 0000000..37bfdcf
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
+
+$shortoptions = 'i:n:a';
+$longoptions = array('id=', 'nickname=', 'all');
+
+$helptext = <<<END_OF_SENDEMAILSUMMARY_HELP
+sendemailsummary.php [options]
+Send an email summary of the inbox to users
+
+  -i --id       ID of user to send summary to
+  -n --nickname nickname of the user to send summary to
+  -a --all      send summary to all users
+
+END_OF_SENDEMAILSUMMARY_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+$qm = QueueManager::get();
+
+// enqueue summary for user or all users
+
+try {
+    $user = getUser();
+    $qm->enqueue($user->id, 'usersum');
+} catch (NoUserArgumentException $nuae) {
+    $qm->enqueue(null, 'sitesum');
+}
diff --git a/plugins/EmailSummary/siteemailsummaryhandler.php b/plugins/EmailSummary/siteemailsummaryhandler.php
new file mode 100644 (file)
index 0000000..595c326
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * 
+ * Handler for queue items of type 'sitesum', sends email summaries
+ * to all users on the site.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Sample
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * 
+ * Handler for queue items of type 'sitesum', sends email summaries
+ * to all users on the site.
+ *
+ * @category  Email
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+class SiteEmailSummaryHandler extends QueueHandler
+{
+
+    /**
+     * Return transport keyword which identifies items this queue handler
+     * services; must be defined for all subclasses.
+     *
+     * Must be 8 characters or less to fit in the queue_item database.
+     * ex "email", "jabber", "sms", "irc", ...
+     *
+     * @return string
+     */
+    
+    function transport()
+    {
+        return 'sitesum';
+    }
+
+    /**
+     * Handle the site
+     * 
+     * @param mixed $object
+     * @return boolean true on success, false on failure
+     */
+    
+    function handle($object)
+    {
+       $qm = QueueManager::get();
+
+       try {
+           // Enqueue a summary for all users
+           
+           $user = new User();
+           $user->find();
+           
+           while ($user->fetch()) {
+               try {
+                   $qm->enqueue($user->id, 'usersum');
+               } catch (Exception $e) {
+                   common_log(LOG_WARNING, $e->getMessage());
+                   continue;
+               }
+           }
+       } catch (Exception $e) {
+           common_log(LOG_WARNING, $e->getMessage());
+       }
+       
+       return true;
+    }
+}
+
diff --git a/plugins/EmailSummary/useremailsummaryhandler.php b/plugins/EmailSummary/useremailsummaryhandler.php
new file mode 100644 (file)
index 0000000..f3151bd
--- /dev/null
@@ -0,0 +1,172 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * 
+ * Handler for queue items of type 'usersum', sends an email summaries
+ * to a particular user.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Sample
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Handler for queue items of type 'usersum', sends an email summaries
+ * to a particular user.
+ *
+ * @category  Email
+ * @package   StatusNet
+ * @author    Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link      http://status.net/
+ */
+
+class UserEmailSummaryHandler extends QueueHandler
+{
+    // Maximum number of notices to include by default. This is probably too much.
+    
+    const MAX_NOTICES = 200;
+    
+    /**
+     * Return transport keyword which identifies items this queue handler
+     * services; must be defined for all subclasses.
+     *
+     * Must be 8 characters or less to fit in the queue_item database.
+     * ex "email", "jabber", "sms", "irc", ...
+     *
+     * @return string
+     */
+    
+    function transport()
+    {
+        return 'sitesum';
+    }
+
+    /**
+     * Send a summary email to the user
+     * 
+     * @param mixed $object
+     * @return boolean true on success, false on failure
+     */
+    
+    function handle($user_id)
+    {
+       // Skip if they've asked not to get summaries
+
+       $ess = Email_summary_status::staticGet('user_id', $user_id);
+       
+       if (!empty($ess) && !$ess->send_summary) {
+           common_log(LOG_INFO, sprintf('Not sending email summary for user %s by request.', $user_id));
+           return true;
+       }
+
+       $since_id = null;
+       
+       if (!empty($ess)) {
+           $since_id = $ess->last_summary_id;
+       }
+         
+       $user = User::staticGet('id', $user_id);
+
+       if (empty($user)) {
+           common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no such user.', $user_id));
+           return true;
+       }
+       
+       if (empty($user->email)) {
+           common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no email address.', $user_id));
+           return true;
+       }
+       
+       $profile = $user->getProfile();
+       
+       if (empty($profile)) {
+           common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no profile.', $user_id));
+           return true;
+       }
+       
+       $notice = $user->ownFriendsTimeline(0, self::MAX_NOTICES, $since_id);
+
+       if (empty($notice) || $notice->N == 0) {
+           common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no notices.', $user_id));
+           return true;
+       }
+
+       // XXX: This is risky fingerpoken in der objektvars, but I didn't feel like
+       // figuring out a better way. -ESP
+
+       $new_top = null;
+       
+       if ($notice instanceof ArrayWrapper) {
+           $new_top = $notice->_items[0]->id;
+       }
+       
+       $out = new XMLStringer();
+
+       $out->raw(sprintf(_('<p>Recent updates from %1s for %2s:</p>'),
+                         common_config('site', 'name'),
+                         $profile->getBestName()));
+       
+       $nl = new NoticeList($notice, $out);
+
+       // Outputs to the string
+       
+       $nl->show();
+       
+       $out->raw(sprintf(_('<p><a href="%1s">change your email settings for %2s</a></p>'),
+                         common_local_url('emailsettings'),
+                         common_config('site', 'name')));
+
+       $body = $out->getString();
+       
+       // FIXME: do something for people who don't like HTML email
+       
+       mail_to_user($user, _('Updates from your network'), $body,
+                    array('Content-Type', 'text/html; charset=UTF-8'));
+
+       if (empty($ess)) {
+           
+           $ess = new Email_summary_status();
+           
+           $ess->user_id         = $user_id;
+           $ess->created         = common_sql_now();
+           $ess->last_summary_id = $new_top;
+           $ess->modified        = common_sql_now();
+
+           $ess->insert();
+           
+       } else {
+           
+           $orig = clone($ess);
+           
+           $ess->last_summary_id = $new_top;
+           $ess->modified        = common_sql_now();
+
+           $ess->update();
+       }
+       
+       return true;
+    }
+}
+