+++ /dev/null
-<?php
-/**
- * Data class for counting greetings
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for counting greetings
- *
- * We use the DB_DataObject framework for data classes in StatusNet. Each
- * table maps to a particular data class, making it easier to manipulate
- * data.
- *
- * Data classes should extend Memcached_DataObject, the (slightly misnamed)
- * extension of DB_DataObject that provides caching, internationalization,
- * and other bits of good functionality to StatusNet-specific data classes.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class User_greeting_count extends Memcached_DataObject
-{
- public $__table = 'user_greeting_count'; // table name
- public $user_id; // int(4) primary_key not_null
- public $greeting_count; // int(4)
-
- /**
- * Get an instance by key
- *
- * This is a utility method to get a single instance with a given key value.
- *
- * @param string $k Key to use to lookup (usually 'user_id' for this class)
- * @param mixed $v Value to lookup
- *
- * @return User_greeting_count object found, or null for no hits
- *
- */
- function staticGet($k, $v=null)
- {
- return Memcached_DataObject::staticGet('User_greeting_count', $k, $v);
- }
-
- /**
- * return table definition for DB_DataObject
- *
- * DB_DataObject needs to know something about the table to manipulate
- * instances. This method provides all the DB_DataObject needs to know.
- *
- * @return array array of column definitions
- */
- function table()
- {
- return array('user_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
- 'greeting_count' => DB_DATAOBJECT_INT);
- }
-
- /**
- * return key definitions for DB_DataObject
- *
- * DB_DataObject needs to know about keys that the table has, since it
- * won't appear in StatusNet's own keys list. In most cases, this will
- * simply reference your keyTypes() function.
- *
- * @return array list of key field names
- */
- function keys()
- {
- return array_keys($this->keyTypes());
- }
-
- /**
- * return key definitions for Memcached_DataObject
- *
- * Our caching system uses the same key definitions, but uses a different
- * method to get them. This key information is used to store and clear
- * cached data, so be sure to list any key that will be used for static
- * lookups.
- *
- * @return array associative array of key definitions, field name to type:
- * 'K' for primary key: for compound keys, add an entry for each component;
- * 'U' for unique keys: compound keys are not well supported here.
- */
- function keyTypes()
- {
- return array('user_id' => 'K');
- }
-
- /**
- * Magic formula for non-autoincrementing integer primary keys
- *
- * If a table has a single integer column as its primary key, DB_DataObject
- * assumes that the column is auto-incrementing and makes a sequence table
- * to do this incrementation. Since we don't need this for our class, we
- * overload this method and return the magic formula that DB_DataObject needs.
- *
- * @return array magic three-false array that stops auto-incrementing.
- */
- function sequenceKey()
- {
- return array(false, false, false);
- }
-
- /**
- * Increment a user's greeting count and return instance
- *
- * This method handles the ins and outs of creating a new greeting_count for a
- * user or fetching the existing greeting count and incrementing its value.
- *
- * @param integer $user_id ID of the user to get a count for
- *
- * @return User_greeting_count instance for this user, with count already incremented.
- */
- static function inc($user_id)
- {
- $gc = User_greeting_count::staticGet('user_id', $user_id);
-
- if (empty($gc)) {
-
- $gc = new User_greeting_count();
-
- $gc->user_id = $user_id;
- $gc->greeting_count = 1;
-
- $result = $gc->insert();
-
- if (!$result) {
- // TRANS: Exception thrown when the user greeting count could not be saved in the database.
- // TRANS: %d is a user ID (number).
- throw Exception(sprintf(_m("Could not save new greeting count for %d."),
- $user_id));
- }
- } else {
- $orig = clone($gc);
-
- $gc->greeting_count++;
-
- $result = $gc->update($orig);
-
- if (!$result) {
- // TRANS: Exception thrown when the user greeting count could not be saved in the database.
- // TRANS: %d is a user ID (number).
- throw Exception(sprintf(_m('Could not increment greeting count for %d.'),
- $user_id));
- }
- }
-
- return $gc;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Plugin for sending email reminders about various things
+ *
+ * PHP version 5
+ *
+ * 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 OnDemand
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Email reminder plugin
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class EmailReminderPlugin extends Plugin
+{
+ /**
+ * Set up email_reminder table
+ *
+ * @see Schema
+ * @see ColumnDef
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ */
+ function onCheckSchema()
+ {
+ $schema = Schema::get();
+ $schema->ensureTable('email_reminder', Email_reminder::schemaDef());
+ return true;
+ }
+
+ /**
+ * Load related modules when needed
+ *
+ * @param string $cls Name of the class to be loaded
+ *
+ * @return boolean hook value; true means continue processing, false
+ * means stop.
+ */
+ function onAutoload($cls) {
+ $base = dirname(__FILE__);
+ $lower = strtolower($cls);
+
+ $files = array("$base/classes/$cls.php",
+ "$base/lib/$lower.php");
+ if (substr($lower, -6) == 'action') {
+ $files[] = "$base/actions/" . substr($lower, 0, -6) . ".php";
+ }
+ foreach ($files as $file) {
+ if (file_exists($file)) {
+ include_once $file;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Register our queue handlers
+ *
+ * @param QueueManager $qm Current queue manager
+ *
+ * @return boolean hook value
+ */
+ function onEndInitializeQueueManager($qm)
+ {
+ $qm->connect('siterem', 'SiteConfirmReminderHandler');
+ $qm->connect('uregrem', 'UserConfirmRegReminderHandler');
+ $qm->connect('uinvrem', 'UserInviteReminderHandler');
+
+ return true;
+ }
+
+ function onEndDocFileForTitle($title, $paths, &$filename)
+ {
+ if (empty($filename)) {
+ $filename = dirname(__FILE__) . '/mail-src/' . $title;
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ *
+ * @param type $object
+ * @param type $subject
+ * @param type $day
+ */
+ static function sendReminder($type, $object, $subject, $day)
+ {
+ common_debug("QQQQQ sendReminder() enter ... ", __FILE__);
+
+ $title = "{$type}-{$day}";
+
+ common_debug("QQQQ title = {$title}", __FILE__);
+
+ // Record the fact that we sent a reminder
+ if (self::sendReminderEmail($type, $object, $subject, $title)) {
+ common_debug("Recording reminder record for {$object->address}", __FILE__);
+ try {
+ Email_reminder::recordReminder($type, $object, $day);
+ } catch (Exception $e) {
+ // oh noez
+ common_log(LOG_ERR, $e->getMessage(), __FILE__);
+ }
+ }
+
+ common_debug("QQQQQ sendReminder() exit ... ", __FILE__);
+
+ return true;
+ }
+
+ /**
+ *
+ * @param type $object
+ * @param type $subject
+ * @param type $title
+ * @return type
+ */
+ static function sendReminderEmail($type, $object, $subject, $title=null) {
+
+ $sitename = common_config('site', 'name');
+ $recipients = array($object->address);
+ $inviter = null;
+ $inviterurl = null;
+
+ if ($type == UserInviteReminderHandler::INVITE_REMINDER) {
+ $user = User::staticGet($object->user_id);
+ if (!empty($user)) {
+ $profile = $user->getProfile();
+ $inviter = $profile->getBestName();
+ $inviterUrl = $profile->profileurl;
+ }
+ }
+
+ $headers['From'] = mail_notify_from();
+ $headers['To'] = trim($object->address);
+ // TRANS: Subject for confirmation e-mail.
+ // TRANS: %s is the StatusNet sitename.
+ $headers['Subject'] = $subject;
+ $headers['Content-Type'] = 'text/html; charset=UTF-8';
+
+ $confirmUrl = common_local_url('register', array('code' => $object->code));
+
+ $template = DocFile::forTitle($title, DocFile::mailPaths());
+
+ $body = $template->toHTML(
+ array(
+ 'confirmurl' => $confirmUrl,
+ 'inviter' => $inviter,
+ 'inviterurl' => $inviterUrl
+ // @todo private invitation message
+ )
+ );
+
+ return mail_send($recipients, $headers, $body);
+ }
+
+ /**
+ *
+ * @param type $versions
+ * @return type
+ */
+ function onPluginVersion(&$versions)
+ {
+ $versions[] = array(
+ 'name' => 'EmailReminder',
+ 'version' => STATUSNET_VERSION,
+ 'author' => 'Zach Copley',
+ 'homepage' => 'http://status.net/wiki/Plugin:EmailReminder',
+ 'rawdescription' => _m('Send email reminders for various things.')
+ );
+ return true;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Data class for email reminders
+ *
+ * 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 Data
+ * @package EmailReminder
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class Email_reminder extends Managed_DataObject
+{
+ const INVITE_REMINDER = 'invite'; // @todo Move this to the invite reminder handler
+
+ public $__table = 'email_reminder';
+
+ public $type; // type of reminder
+ public $code; // confirmation code
+ public $days; // number of days after code was created
+ public $sent; // timestamp
+ public $created; // timestamp
+ public $modified; // timestamp
+
+ /**
+ * Get an instance by key
+ *
+ * This is a utility method to get a single instance with a given key value.
+ *
+ * @param string $k Key to use to lookup
+ * @param mixed $v Value to lookup
+ *
+ * @return QnA_Answer object found, or null for no hits
+ *
+ */
+ function staticGet($k, $v=null)
+ {
+ return Memcached_DataObject::staticGet('email_reminder', $k, $v);
+ }
+
+ /**
+ *
+ * @param type $type
+ * @param type $confirm
+ * @param type $day
+ * @return type
+ */
+ static function needsReminder($type, $confirm, $days) {
+
+ $reminder = new Email_reminder();
+ $reminder->type = $type;
+ $reminder->code = $confirm->code;
+ $reminder->days = $days;
+
+ $result = $reminder->find(true);
+
+ if (empty($result)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ *
+ * @param type $type
+ * @param type $confirm
+ * @param type $day
+ * @return type
+ */
+ static function recordReminder($type, $confirm, $days) {
+
+ $reminder = new Email_reminder();
+ $reminder->type = $type;
+ $reminder->code = $confirm->code;
+ $reminder->days = $days;
+ $reminder->sent = $reminder->created = common_sql_now();
+ $result = $reminder->insert();
+
+ if (empty($result)) {
+ common_log_db_error($reminder, 'INSERT', __FILE__);
+ throw new ServerException(
+ _m('Database error inserting reminder record.')
+ );
+ }
+
+ return $result;
+ }
+
+ /**
+ * Data definition for email reminders
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Record of email reminders that have been sent',
+ 'fields' => array(
+ 'type' => array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true,
+ 'description' => 'type of reminder'
+ ),
+ 'code' => array(
+ 'type' => 'varchar',
+ 'not null' => 'true',
+ 'length' => 255,
+ 'description' => 'confirmation code'
+ ),
+ 'days' => array(
+ 'type' => 'int',
+ 'not null' => 'true',
+ 'description' => 'number of days since code creation'
+ ),
+ 'sent' => array(
+ 'type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'Date and time the reminder was sent'
+ ),
+ 'created' => array(
+ 'type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'Date and time the record was created'
+ ),
+ 'modified' => array(
+ 'type' => 'timestamp',
+ 'not null' => true,
+ 'description' => 'Date and time the record was last modified'
+ ),
+ ),
+ 'primary key' => array('type', 'code', 'days'),
+ 'indexes' => array(
+ 'sent_idx' => array('sent'),
+ ),
+ );
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ *
+ * Handler for reminder queue items which send reminder emails to all users
+ * we would like to complete a given process (e.g.: registration).
+ *
+ * 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 Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 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 reminder queue items which send reminder emails to all users
+ * we would like to complete a given process (e.g.: registration)
+ *
+ * @category Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class SiteConfirmReminderHandler 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 'siterem';
+ }
+
+ /**
+ * Handle the site
+ *
+ * @param string $reminderType type of reminder to send
+ * @return boolean true on success, false on failure
+ */
+ function handle($reminderType)
+ {
+ $qm = QueueManager::get();
+
+ try {
+ switch($reminderType) {
+ case UserConfirmRegReminderHandler::REGISTER_REMINDER:
+ $confirm = new Confirm_address();
+ $confirm->address_type = $object;
+ $confirm->find();
+ while ($confirm->fetch()) {
+ try {
+ $qm->enqueue($confirm, 'uregrem');
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $e->getMessage());
+ continue;
+ }
+ }
+ break;
+ case UserInviteReminderHandler::INVITE_REMINDER:
+ $invitation = new Invitation();
+ $invitation->find();
+ while ($invitation->fetch()) {
+ try {
+ $qm->enqueue($invitation, 'uinvrem');
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $e->getMessage());
+ continue;
+ }
+ }
+ break;
+ default:
+ // WTF?
+ common_log(
+ LOG_ERR,
+ "Received unknown confirmation address type",
+ __FILE__
+ );
+ }
+ } catch (Exception $e) {
+ common_log(LOG_ERR, $e->getMessage());
+ return false;
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ *
+ * Handler for queue items of type 'uregem' - sends email registration
+ * confirmation reminders 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 Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 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 'uregrem'
+ *
+ * @category Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class UserConfirmRegReminderHandler extends UserReminderHandler {
+
+ const REGISTER_REMINDER = 'register';
+
+ /**
+ * 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 'uregrem';
+ }
+
+ /**
+ * Send an email registration confirmation reminder until the user
+ * confirms her registration. We'll send a reminder after one day,
+ * three days, and a full week.
+ *
+ * @todo abstract this bit further
+ *
+ * @param Confirm_address $confirm
+ * @return boolean success value
+ */
+ function sendNextReminder($confirm)
+ {
+ $regDate = strtotime($confirm->modified); // Seems like my best bet
+ $now = strtotime('now');
+
+ // Days since registration
+ $days = ($now - $regDate) / 86499; // 60*60*24 = 86499
+
+ // Welcome to one of the ugliest switch statement I've ever written
+
+ switch($days) {
+ case ($days > 1 && $days < 2):
+ if (Email_reminder::needsReminder(self::REGISTER_REMINDER, $confirm, 1)) {
+ common_log(LOG_INFO, "Sending one day registration confirmation reminder to {$confirm->address}", __FILE__);
+ $subject = _m("Reminder - please confirm your registration!");
+ return EmailReminderPlugin::sendReminder(
+ self::REGISTER_REMINDER,
+ $confirm,
+ $subject,
+ 1);
+ } else {
+ return true;
+ }
+ break;
+ case ($days > 3 && $days < 4):
+ if (Email_reminder::needsReminder(self::REGISTER_REMINDER, $confirm, 3)) {
+ common_log(LOG_INFO, "Sending three day registration confirmation reminder to {$confirm->address}", __FILE__);
+ $subject = _m("Second reminder - please confirm your registration!");
+ return EmailReminderPlugin::sendReminder(
+ self::REGISTER_REMINDER,
+ $confirm,
+ $subject,
+ 3
+ );
+ } else {
+ return true;
+ }
+ break;
+ case ($days > 7 && $days < 8):
+ if (Email_reminder::needsReminder(self::REGISTER_REMINDER, $confirm, 7)) {
+ common_log(LOG_INFO, "Sending one week registration confirmation reminder to {$confirm->address}", __FILE__);
+ $subject = _m("Final reminder - please confirm your registration!");
+ return EmailReminderPlugin::sendReminder(
+ self::REGISTER_REMINDER,
+ $confirm,
+ $subject,
+ 7
+ );
+ } else {
+ return true;
+ }
+ break;
+ }
+ return true;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ *
+ * Handler for queue items of type 'uinvrem' - sends an email reminder to
+ * an email address of someone who has been invited to 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 Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 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 'uinvrem' (user invite reminder)
+ *
+ * @category Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class UserInviteReminderHandler extends UserReminderHandler {
+
+ const INVITE_REMINDER = 'invite';
+
+ /**
+ * 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 'uinvrem';
+ }
+
+ /**
+ * Send an invitation reminder. We'll send one after one day, and then
+ * one after three days.
+ *
+ * @todo Abstract this stuff further
+ *
+ * @param Invitation $invitation
+ * @return boolean success value
+ */
+ function sendNextReminder($invitation)
+ {
+ $invDate = strtotime($invitation->created);
+ $now = strtotime('now');
+
+ // Days since first invitation was sent
+ $days = ($now - $invDate) / 86499; // 60*60*24 = 86499
+
+ $siteName = common_config('site', 'name');
+
+ switch($days) {
+ case ($days > 1 && $days < 2):
+ if (Email_reminder::needsReminder(self::INVITE_REMINDER, $invitation, 1)) {
+ common_log(LOG_INFO, "Sending one day invitation reminder to {$invitation->address}", __FILE__);
+ $subject = _m("Reminder - You have been invited to join {$siteName}!");
+ return EmailReminderPlugin::sendReminder(
+ self::INVITE_REMINDER,
+ $invitation,
+ $subject,
+ 1);
+ } else {
+ return true;
+ }
+ break;
+ case ($days > 3 && $days < 4):
+ if (Email_reminder::needsReminder(self::INVITE_REMINDER, $invitation, 3)) {
+ common_log(LOG_INFO, "Sending three day invitation reminder to {$invitation->address}", __FILE__);
+ $subject = _m("Final reminder - you have been invited to join {$siteName}!");
+ return EmailReminderPlugin::sendReminder(
+ self::INVITE_REMINDER,
+ $invitation,
+ $subject,
+ 3
+ );
+ } else {
+ return true;
+ }
+ break;
+ }
+ return true;
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ *
+ * Base handler for email reminders
+ *
+ * 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 Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 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 email reminder queue items
+ *
+ * @category Email
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class UserReminderHandler extends QueueHandler {
+
+ /**
+ * Send the next email reminder to the confirm address
+ *
+ * @param Confirm_address $confirm the confirmation email/code
+ * @return boolean true on success, false on failure
+ */
+ function handle($confirm) {
+ return $this->sendNextReminder($confirm);
+ }
+
+ /**
+ * Send the next reminder if one needs sending.
+ * Subclasses must override
+ *
+ * @param Confirm_address $confirm the confirmation email/code
+ */
+ function sendNextReminder($confirm)
+ {
+ }
+}
--- /dev/null
+First reminder...
+
+%%arg.inviter%% has invited you to join them on %%site.name%%.
+
+%%site.name%% is a micro-blogging service that lets you keep
+up-to-date with people you know and people who interest you.
+
+You can also share news about yourself, your thoughts, or your life
+online with people who know about you.
+
+It's great for meeting new people who share your interests.
+
+You can see %%arg.inviter%%'s profile page on %%site.name%% here:
+
+> [%%arg.inviterurl%%](%%arg.inviterurl%%)
+
+If you'd like to try the service, click on the link below to accept
+the invitation.
+
+> [%%arg.confirmurl%%](%%arg.confirmurl%%)
+
+If not, you can ignore this message. Thanks for your patience and your time.
+
+Sincerely,
+
+%%site.name%%
--- /dev/null
+Second and final reminder...
+
+%%arg.inviter%% has invited you to join them on %%site.name%%.
+
+%%site.name%% is a micro-blogging service that lets you keep
+up-to-date with people you know and people who interest you.
+
+You can also share news about yourself, your thoughts, or your life
+online with people who know about you.
+
+It's great for meeting new people who share your interests.
+
+You can see %%arg.inviter%%'s profile page on %%site.name%% here:
+
+> [%%arg.inviterurl%%](%%arg.inviterurl%%)
+
+If you'd like to try the service, click on the link below to accept
+the invitation.
+
+> [%%arg.confirmurl%%](%%arg.confirmurl%%)
+
+If not, you can ignore this message. Thanks for your patience and your time.
+
+Sincerely,
+
+%%site.name%%
--- /dev/null
+Hey, it's been a whole day!
+
+Someone (probably you) has requested an account on %%site.name%% using this email address.
+
+To confirm the address, click the following URL or copy it into the address bar of your browser.
+
+> [%%arg.confirmurl%%](%%arg.confirmurl%%)
+
+If it was not you, you can safely ignore this message.
--- /dev/null
+Hey, it's been three days!!
+
+Someone (probably you) has requested an account on %%site.name%% using this email address.
+
+To confirm the address, click the following URL or copy it into the address bar of your browser.
+
+> [%%arg.confirmurl%%](%%arg.confirmurl%%)
+
+If it was not you, you can safely ignore this message.
--- /dev/null
+IT'S BEEN A WHOLE WEEK! Final reminder...
+
+Someone (probably you) has requested an account on %%site.name%% using this email address.
+
+To confirm the address, click the following URL or copy it into the address bar of your browser.
+
+> [%%arg.confirmurl%%](%%arg.confirmurl%%)
+
+If it was not you, you can safely ignore this message.
--- /dev/null
+* * * * * /opt/local/bin/php /path/to/statusnet/plugins/EmailReminder/scripts/sendemailreminder.php -t all -a -q > /tmp/cron.log
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+* StatusNet - a distributed open-source microblogging tool
+* Copyright (C) 2011, 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 = 't:e:au';
+$longoptions = array('type=', 'email=', 'all', 'universe');
+
+$helptext = <<<END_OF_SENDEMAILREMINDER_HELP
+sendemailreminder.php [options]
+Send an email summary of the inbox to users
+
+ -t --type type of reminder to send (register | invite | all)
+ -e --email email address to send reminder to
+ -a --all send reminder to all addresses
+ -u --universe send reminder to all addresses on all sites
+
+END_OF_SENDEMAILREMINDER_HELP;
+
+require_once INSTALLDIR . '/scripts/commandline.inc';
+
+$quiet = have_option('q', 'quiet');
+
+$types = array(
+ // registration confirmation reminder
+ 'register' => array(
+ 'type' => 'register',
+ 'className' => 'Confirm_address',
+ 'utransport' => 'uregrem'
+ ),
+ // invitation confirmation reminder
+ 'invite' => array(
+ 'type' => 'invite',
+ 'className' => 'Invitation',
+ 'utransport' => 'uinvrem'
+ )
+ // ... add more here
+);
+
+$type = null;
+
+if (have_option('t', 'type')) {
+ $type = trim(get_option_value('t', 'type'));
+ if (!in_array($type, array_keys($types)) && $type !== 'all') {
+ print _m("Unknown reminder type: {$type}.\n");
+ exit(1);
+ }
+} else {
+ show_help();
+ exit(1);
+}
+
+$reminders = array();
+
+switch($type) {
+case 'register':
+ $reminders[] = $types['register'];
+ break;
+case 'invite':
+ $reminders[] = $types['invite'];
+ break;
+case 'all':
+ $reminders = $types;
+ break;
+}
+
+if (have_option('u', 'universe')) {
+ $sn = new Status_network();
+ if ($sn->find()) {
+ while ($sn->fetch()) {
+ $server = $sn->getServerName();
+ StatusNet::init($server);
+ // Different queue manager, maybe!
+ $qm = QueueManager::get();
+ foreach ($reminders as $reminder) {
+ extract($reminder);
+ $qm->enqueue($type, 'siterem');
+ if (!$quiet) { print "Sent pending {$type} reminders to all unconfirmed addresses in the known universe.\n"; }
+ }
+ }
+ }
+} else {
+ $qm = QueueManager::get();
+ try {
+ // enqueue reminder for specific email address or all unconfirmed addresses
+ if (have_option('e', 'email')) {
+ $address = trim(get_option_value('e', 'email'));
+ foreach ($reminders as $reminder) {
+ // real bad voodoo here
+ extract($reminder);
+ $confirm = new $className;
+ $confirm->address = $address;
+ $result = $confirm->find(true);
+ if (empty($result)) {
+ throw new Exception("No confirmation code found for {$address}.");
+ }
+ $qm->enqueue($confirm, $utransport);
+ if (!$quiet) { print "Sent all pending {$type} reminder to {$address}.\n"; }
+ }
+ } else if (have_option('a', 'all')) {
+ foreach ($reminders as $reminder) {
+ extract($reminder);
+ $qm->enqueue($type, 'siterem');
+ if (!$quiet) { print "Sent pending {$type} reminders to all unconfirmed addresses on the site.\n"; }
+ }
+ } else {
+ show_help();
+ exit(1);
+ }
+ } catch (Exception $e) {
+ if (!$quiet) { print $e->getMessage() . "\n"; }
+ common_log(LOG_ERR, $e->getMessage(), __FILE__);
+ exit(1);
+ }
+}