summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorZach Copley <zach@status.net>2010-11-16 02:32:46 +0000
committerZach Copley <zach@status.net>2010-11-16 02:32:46 +0000
commitbd566b6f855a19efb1d74eeaa39ab4e621903b12 (patch)
treebefc30688421cc1fc99b1aef7e64d45f08614cd2 /plugins
parentca4c0a160122d20f95877102f9712aee45c7afb8 (diff)
parenteb0495d10719f2be86f8f97e82aaa1b8bf923c7d (diff)
Merge branch '0.9.x' into facebook-upgrade
Diffstat (limited to 'plugins')
-rw-r--r--plugins/EmailSummary/EmailSummaryPlugin.php202
-rw-r--r--plugins/EmailSummary/Email_summary_status.php167
-rw-r--r--plugins/EmailSummary/sendemailsummary.php47
-rw-r--r--plugins/EmailSummary/siteemailsummaryhandler.php96
-rw-r--r--plugins/EmailSummary/useremailsummaryhandler.php226
-rw-r--r--plugins/Mapstraction/MapstractionPlugin.php3
-rw-r--r--plugins/ModPlus/ModPlusPlugin.php116
-rw-r--r--plugins/ModPlus/modplus.css23
-rw-r--r--plugins/ModPlus/modplus.js23
-rw-r--r--plugins/ModPlus/remoteprofileaction.php106
-rw-r--r--plugins/TwitterBridge/Notice_to_status.php7
-rw-r--r--plugins/TwitterBridge/twitter.php32
-rw-r--r--plugins/TwitterBridge/twitterimport.php17
13 files changed, 1063 insertions, 2 deletions
diff --git a/plugins/EmailSummary/EmailSummaryPlugin.php b/plugins/EmailSummary/EmailSummaryPlugin.php
new file mode 100644
index 000000000..58c40e43c
--- /dev/null
+++ b/plugins/EmailSummary/EmailSummaryPlugin.php
@@ -0,0 +1,202 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Sends an email summary of the inbox to users in the network
+ *
+ * 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 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);
+}
+
+/**
+ * Plugin for sending email summaries to users
+ *
+ * @category Email
+ * @package StatusNet
+ * @author Brion Vibber <brionv@status.net>
+ * @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 EmailSummaryPlugin extends Plugin
+{
+ /**
+ * Database schema setup
+ *
+ * @return boolean hook value
+ */
+
+ function onCheckSchema()
+ {
+ $schema = Schema::get();
+
+ // For storing user-submitted flags on profiles
+
+ $schema->ensureTable('email_summary_status',
+ array(new ColumnDef('user_id', 'integer', null,
+ false, 'PRI'),
+ new ColumnDef('send_summary', 'tinyint', null,
+ false, null, 1),
+ new ColumnDef('last_summary_id', 'integer', null,
+ true),
+ new ColumnDef('created', 'datetime', null,
+ false),
+ new ColumnDef('modified', 'datetime', null,
+ false),
+ )
+ );
+ 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)
+ {
+ $dir = dirname(__FILE__);
+
+ 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;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Version info for this plugin
+ *
+ * @param array &$versions array of version data
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ *
+ */
+
+ function onPluginVersion(&$versions)
+ {
+ $versions[] = array('name' => 'EmailSummary',
+ 'version' => STATUSNET_VERSION,
+ 'author' => 'Evan Prodromou',
+ 'homepage' => 'http://status.net/wiki/Plugin:EmailSummary',
+ 'rawdescription' =>
+ _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;
+ }
+
+ /**
+ * Add a checkbox to turn off email summaries
+ *
+ * @param Action $action Action being executed (emailsettings)
+ *
+ * @return boolean hook value
+ */
+
+ function onEndEmailFormData($action)
+ {
+ $user = common_current_user();
+
+ $action->elementStart('li');
+ $action->checkbox('emailsummary',
+ // TRANS: Checkbox label in e-mail preferences form.
+ _('Send me a periodic summary of updates from my network.'),
+ Email_summary_status::getSendSummary($user->id));
+ $action->elementEnd('li');
+ return true;
+ }
+
+ /**
+ * Add a checkbox to turn off email summaries
+ *
+ * @param Action $action Action being executed (emailsettings)
+ *
+ * @return boolean hook value
+ */
+
+ function onEndEmailSaveForm($action)
+ {
+ $sendSummary = $action->boolean('emailsummary');
+
+ $user = common_current_user();
+
+ if (!empty($user)) {
+
+ $ess = Email_summary_status::staticGet('user_id', $user->id);
+
+ if (empty($ess)) {
+
+ $ess = new Email_summary_status();
+
+ $ess->user_id = $user->id;
+ $ess->send_summary = $sendSummary;
+ $ess->created = common_sql_now();
+ $ess->modified = common_sql_now();
+
+ $ess->insert();
+
+ } else {
+
+ $orig = clone($ess);
+
+ $ess->send_summary = $sendSummary;
+ $ess->modified = common_sql_now();
+
+ $ess->update($orig);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/plugins/EmailSummary/Email_summary_status.php b/plugins/EmailSummary/Email_summary_status.php
new file mode 100644
index 000000000..5b5b231e3
--- /dev/null
+++ b/plugins/EmailSummary/Email_summary_status.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * Data class for email summary status
+ *
+ * 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) 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for email summaries
+ *
+ * Email summary information for users
+ *
+ * @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 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_id; // int(4) null
+ public $created; // datetime not_null
+ public $modified; // datetime not_null
+
+ /**
+ * Get an instance by key
+ *
+ * @param string $k Key to use to lookup (usually 'user_id' for this class)
+ * @param mixed $v Value to lookup
+ *
+ * @return Email_summary_status object found, or null for no hits
+ *
+ */
+ function staticGet($k, $v=null)
+ {
+ return Memcached_DataObject::staticGet('email_summary_status', $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,
+ 'send_summary' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ '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);
+ }
+
+ /**
+ * return key definitions for DB_DataObject
+ *
+ * @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
+ *
+ * @return array magic three-false array that stops auto-incrementing.
+ */
+
+ function sequenceKey()
+ {
+ return array(false, false, false);
+ }
+
+ /**
+ * Helper function
+ *
+ * @param integer $user_id ID of the user to get a count for
+ *
+ * @return int flag for whether to send this user a summary email
+ */
+
+ static function getSendSummary($user_id)
+ {
+ $ess = Email_summary_status::staticGet('user_id', $user_id);
+
+ if (!empty($ess)) {
+ return $ess->send_summary;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Get email summary status for a user
+ *
+ * @param integer $user_id ID of the user to get a count for
+ *
+ * @return Email_summary_status instance for this user, with count already incremented.
+ */
+
+ static function getLastSummaryID($user_id)
+ {
+ $ess = Email_summary_status::staticGet('user_id', $user_id);
+
+ if (!empty($ess)) {
+ return $ess->last_summary_id;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/plugins/EmailSummary/sendemailsummary.php b/plugins/EmailSummary/sendemailsummary.php
new file mode 100644
index 000000000..37bfdcfbd
--- /dev/null
+++ b/plugins/EmailSummary/sendemailsummary.php
@@ -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
index 000000000..595c3267a
--- /dev/null
+++ b/plugins/EmailSummary/siteemailsummaryhandler.php
@@ -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
index 000000000..b1ebd0c42
--- /dev/null
+++ b/plugins/EmailSummary/useremailsummaryhandler.php
@@ -0,0 +1,226 @@
+<?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()));
+
+
+ $out->elementStart('table', array('width' => '541px', 'style' => 'border: none'));
+
+ while ($notice->fetch()) {
+
+ $profile = Profile::staticGet('id', $notice->profile_id);
+
+ if (empty($profile)) {
+ continue;
+ }
+
+ $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+
+ $out->elementStart('tr');
+ $out->elementStart('td', array('width' => AVATAR_STREAM_SIZE,
+ 'height' => AVATAR_STREAM_SIZE,
+ 'align' => 'left',
+ 'valign' => 'top'));
+ $out->element('img', array('src' => ($avatar) ?
+ $avatar->displayUrl() :
+ Avatar::defaultImage($avatar_size),
+ 'class' => 'avatar photo',
+ 'width' => AVATAR_STREAM_SIZE,
+ 'height' => AVATAR_STREAM_SIZE,
+ 'alt' => $profile->getBestName()));
+ $out->elementEnd('td');
+ $out->elementStart('td', array('align' => 'left',
+ 'valign' => 'top'));
+ $out->element('a', array('href' => $profile->profileurl),
+ $profile->nickname);
+ $out->text(' ');
+ $out->raw($notice->rendered);
+ $out->element('br'); // yeah, you know it. I just wrote a <br> in the middle of my table layout.
+ $noticeurl = $notice->bestUrl();
+ // above should always return an URL
+ assert(!empty($noticeurl));
+ $out->elementStart('a', array('rel' => 'bookmark',
+ 'class' => 'timestamp',
+ 'href' => $noticeurl));
+ $dt = common_date_iso8601($notice->created);
+ $out->element('abbr', array('class' => 'published',
+ 'title' => $dt),
+ common_date_string($notice->created));
+ $out->elementEnd('a');
+ if ($notice->hasConversation()) {
+ $conv = Conversation::staticGet('id', $notice->conversation);
+ $convurl = $conv->uri;
+ if (!empty($convurl)) {
+ $out->text(' ');
+ $out->element('a',
+ array('href' => $convurl.'#notice-'.$notice->id,
+ 'class' => 'response'),
+ _('in context'));
+ }
+ }
+ $out->elementEnd('td');
+ $out->elementEnd('tr');
+ }
+
+ $out->elementEnd('table');
+
+ $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($orig);
+ }
+
+ return true;
+ }
+}
diff --git a/plugins/Mapstraction/MapstractionPlugin.php b/plugins/Mapstraction/MapstractionPlugin.php
index c4ba6464e..d5261d8bc 100644
--- a/plugins/Mapstraction/MapstractionPlugin.php
+++ b/plugins/Mapstraction/MapstractionPlugin.php
@@ -156,7 +156,8 @@ class MapstractionPlugin extends Plugin
' var user = null; '.
(($actionName == 'showstream') ? ' user = scrapeUser(); ' : '') .
' var notices = scrapeNotices(user); ' .
- ' showMapstraction($("#map_canvas"), notices); '.
+ ' var canvas = $("#map_canvas")[0]; ' .
+ ' if (typeof(canvas) != "undefined") { showMapstraction(canvas, notices); } '.
'});');
}
diff --git a/plugins/ModPlus/ModPlusPlugin.php b/plugins/ModPlus/ModPlusPlugin.php
new file mode 100644
index 000000000..3e7a8c745
--- /dev/null
+++ b/plugins/ModPlus/ModPlusPlugin.php
@@ -0,0 +1,116 @@
+<?php
+/*
+ * StatusNet - the 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Some UI extras for now...
+ *
+ * @package ModPlusPlugin
+ * @maintainer Brion Vibber <brion@status.net>
+ */
+class ModPlusPlugin extends Plugin
+{
+ function onPluginVersion(&$versions)
+ {
+ $versions[] = array('name' => 'ModPlus',
+ 'version' => STATUSNET_VERSION,
+ 'author' => 'Brion Vibber',
+ 'homepage' => 'http://status.net/wiki/Plugin:ModPlus',
+ 'rawdescription' =>
+ _m('UI extensions for profile moderation actions.'));
+
+ return true;
+ }
+
+ /**
+ * Load JS at runtime if we're logged in.
+ *
+ * @param Action $action
+ * @return boolean hook result
+ */
+ function onEndShowScripts($action)
+ {
+ $user = common_current_user();
+ if ($user) {
+ $action->script('plugins/ModPlus/modplus.js');
+ }
+ return true;
+ }
+
+ function onEndShowStatusNetStyles($action) {
+ $action->cssLink('plugins/ModPlus/modplus.css');
+ return true;
+ }
+
+ /**
+ * Autoloader
+ *
+ * Loads our classes if they're requested.
+ *
+ * @param string $cls Class requested
+ *
+ * @return boolean hook return
+ */
+ function onAutoload($cls)
+ {
+ switch ($cls)
+ {
+ case 'RemoteprofileAction':
+ case 'RemoteProfileAction':
+ require_once dirname(__FILE__) . '/remoteprofileaction.php';
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Add OpenID-related paths to the router table
+ *
+ * Hook for RouterInitialized event.
+ *
+ * @param Net_URL_Mapper $m URL mapper
+ *
+ * @return boolean hook return
+ */
+ function onStartInitializeRouter($m)
+ {
+ $m->connect('user/remote/:id',
+ array('action' => 'remoteprofile'),
+ array('id' => '[\d]+'));
+
+ return true;
+ }
+
+ function onStartShowNoticeItem($item)
+ {
+ $profile = $item->profile;
+ $isRemote = !(User::staticGet('id', $profile->id));
+ if ($isRemote) {
+ $target = common_local_url('remoteprofile', array('id' => $profile->id));
+ $label = _m('Remote profile options...');
+ $item->out->elementStart('div', 'remote-profile-options');
+ $item->out->element('a', array('href' => $target), $label);
+ $item->out->elementEnd('div');
+ }
+ }
+}
diff --git a/plugins/ModPlus/modplus.css b/plugins/ModPlus/modplus.css
new file mode 100644
index 000000000..8d2fc8fba
--- /dev/null
+++ b/plugins/ModPlus/modplus.css
@@ -0,0 +1,23 @@
+.remote-profile-options {
+ position: absolute;
+ z-index: 999;
+
+ background: url(../../theme/base/images/icons/twotone/green/admin.gif) no-repeat 8px 8px white;
+ border: solid 1px #c0c0c0;
+
+ margin-top: 56px;
+
+ padding: 6px 16px;
+ padding-left: 32px;
+
+ -moz-border-radius: 8px;
+ -webkit-border-radius: 8px;
+ -msie-border-radius: 8px;
+ border-radius: 8px;
+
+ box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
+ -moz-box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
+ -webkit-box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
+
+ display: none;
+}
diff --git a/plugins/ModPlus/modplus.js b/plugins/ModPlus/modplus.js
new file mode 100644
index 000000000..2e90de4f1
--- /dev/null
+++ b/plugins/ModPlus/modplus.js
@@ -0,0 +1,23 @@
+/**
+ * modplus.js
+ * (c) 2010 StatusNet, Inc
+ */
+
+$(function() {
+ function ModPlus_setup(notice) {
+ if ($(notice).find('.remote-profile-options').size()) {
+ var $options = $(notice).find('.remote-profile-options');
+ $options.prepend($())
+ $(notice).find('.author').mouseenter(function(event) {
+ $(notice).find('.remote-profile-options').fadeIn();
+ });
+ $(notice).mouseleave(function(event) {
+ $(notice).find('.remote-profile-options').fadeOut();
+ });
+ }
+ }
+
+ $('.notice').each(function() {
+ ModPlus_setup(this);
+ });
+});
diff --git a/plugins/ModPlus/remoteprofileaction.php b/plugins/ModPlus/remoteprofileaction.php
new file mode 100644
index 000000000..caa5e6fbf
--- /dev/null
+++ b/plugins/ModPlus/remoteprofileaction.php
@@ -0,0 +1,106 @@
+<?php
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+class RemoteProfileAction extends ShowstreamAction
+{
+ function prepare($args)
+ {
+ OwnerDesignAction::prepare($args); // skip the ProfileAction code and replace it...
+
+ $id = $this->arg('id');
+ $this->user = false;
+ $this->profile = Profile::staticGet('id', $id);
+
+ if (!$this->profile) {
+ $this->serverError(_('User has no profile.'));
+ return false;
+ }
+
+ $user = User::staticGet('id', $this->profile->id);
+ if ($user) {
+ // This is a local user -- send to their regular profile.
+ $url = common_local_url('showstream', array('nickname' => $user->nickname));
+ common_redirect($url);
+ return false;
+ }
+
+ $this->tag = $this->trimmed('tag');
+ $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+ common_set_returnto($this->selfUrl());
+ return true;
+ }
+
+ function handle($args)
+ {
+ // skip yadis thingy
+ $this->showPage();
+ }
+
+ function title()
+ {
+ // maybe fixed in 0.9.x
+ if (!empty($this->profile->fullname)) {
+ $base = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
+ } else {
+ $base = $this->profile->nickname;
+ }
+ $host = parse_url($this->profile->profileurl, PHP_URL_HOST);
+ return sprintf(_m('%s on %s'), $base, $host);
+ }
+
+ /**
+ * Instead of showing notices, link to the original offsite profile.
+ */
+ function showNotices()
+ {
+ $url = $this->profile->profileurl;
+ $host = parse_url($url, PHP_URL_HOST);
+ $markdown = sprintf(
+ _m('This remote profile is registered on another site; see [%s\'s original profile page on %s](%s).'),
+ $this->profile->nickname,
+ $host,
+ $url);
+ $html = common_markup_to_html($markdown);
+ $this->raw($html);
+
+ if ($this->profile->hasRole(Profile_role::SILENCED)) {
+ $markdown = _m('Site moderators have silenced this profile, which prevents delivery of new messages to any users on this site.');
+ $this->raw(common_markup_to_html($markdown));
+ }
+ }
+
+ function getFeeds()
+ {
+ // none
+ }
+
+ /**
+ * Don't do various extra stuff, and also trim some things to avoid crawlers.
+ */
+ function extraHead()
+ {
+ $this->element('meta', array('name' => 'robots',
+ 'content' => 'noindex,nofollow'));
+ }
+
+ function showLocalNav()
+ {
+ $nav = new PublicGroupNav($this);
+ $nav->show();
+ }
+
+ function showSections()
+ {
+ ProfileAction::showSections();
+ // skip tag cloud
+ }
+
+ function showStatistics()
+ {
+ // skip
+ }
+
+} \ No newline at end of file
diff --git a/plugins/TwitterBridge/Notice_to_status.php b/plugins/TwitterBridge/Notice_to_status.php
index 2e32ba963..3b8f816cf 100644
--- a/plugins/TwitterBridge/Notice_to_status.php
+++ b/plugins/TwitterBridge/Notice_to_status.php
@@ -144,6 +144,7 @@ class Notice_to_status extends Memcached_DataObject
/**
* Save a mapping between a notice and a status
+ * Warning: status_id values may not fit in 32-bit integers.
*
* @param integer $notice_id ID of the notice in StatusNet
* @param integer $status_id ID of the status in Twitter
@@ -153,12 +154,18 @@ class Notice_to_status extends Memcached_DataObject
static function saveNew($notice_id, $status_id)
{
+ if (empty($notice_id)) {
+ throw new Exception("Invalid notice_id $notice_id");
+ }
$n2s = Notice_to_status::staticGet('notice_id', $notice_id);
if (!empty($n2s)) {
return $n2s;
}
+ if (empty($status_id)) {
+ throw new Exception("Invalid status_id $status_id");
+ }
$n2s = Notice_to_status::staticGet('status_id', $status_id);
if (!empty($n2s)) {
diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php
index cd1ad70b9..b34488069 100644
--- a/plugins/TwitterBridge/twitter.php
+++ b/plugins/TwitterBridge/twitter.php
@@ -128,6 +128,16 @@ function is_twitter_notice($id)
return (!empty($n2s));
}
+/**
+ * Check if we need to broadcast a notice over the Twitter bridge, and
+ * do so if necessary. Will determine whether to do a straight post or
+ * a repeat/retweet
+ *
+ * This function is meant to be called directly from TwitterQueueHandler.
+ *
+ * @param Notice $notice
+ * @return boolean true if complete or successful, false if we should retry
+ */
function broadcast_twitter($notice)
{
$flink = Foreign_link::getByUserID($notice->profile_id,
@@ -137,8 +147,13 @@ function broadcast_twitter($notice)
if (!empty($flink) && TwitterOAuthClient::isPackedToken($flink->credentials)) {
if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) {
$retweet = retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of));
- if (!empty($retweet)) {
+ if (is_object($retweet)) {
Notice_to_status::saveNew($notice->id, $retweet->id);
+ return true;
+ } else {
+ // Our error processing will have decided if we need to requeue
+ // this or can discard safely.
+ return $retweet;
}
} else if (is_twitter_bound($notice, $flink)) {
return broadcast_oauth($notice, $flink);
@@ -148,6 +163,21 @@ function broadcast_twitter($notice)
return true;
}
+/**
+ * Send a retweet to Twitter for a notice that has been previously bridged
+ * in or out.
+ *
+ * Warning: the return value is not guaranteed to be an object; some error
+ * conditions will return a 'true' which should be passed on to a calling
+ * queue handler.
+ *
+ * No local information about the resulting retweet is saved: it's up to
+ * caller to save new mappings etc if appropriate.
+ *
+ * @param Foreign_link $flink
+ * @param Notice $notice
+ * @return mixed object with resulting Twitter status data on success, or true/false/null on error conditions.
+ */
function retweet_notice($flink, $notice)
{
$token = TwitterOAuthClient::unpackToken($flink->credentials);
diff --git a/plugins/TwitterBridge/twitterimport.php b/plugins/TwitterBridge/twitterimport.php
index 07a9cf95f..498e9b1fc 100644
--- a/plugins/TwitterBridge/twitterimport.php
+++ b/plugins/TwitterBridge/twitterimport.php
@@ -189,6 +189,7 @@ class TwitterImport
Notice_to_status::saveNew($notice->id, $status->id);
$this->saveStatusMentions($notice, $status);
+ $this->saveStatusAttachments($notice, $status);
$notice->blowOnInsert();
@@ -648,4 +649,20 @@ class TwitterImport
}
}
}
+
+ /**
+ * Record URL links from the notice. Needed to get thumbnail records
+ * for referenced photo and video posts, etc.
+ *
+ * @param Notice $notice
+ * @param object $status
+ */
+ function saveStatusAttachments($notice, $status)
+ {
+ if (!empty($status->entities) && !empty($status->entities->urls)) {
+ foreach ($status->entities->urls as $url) {
+ File::processNew($url->url, $notice->id);
+ }
+ }
+ }
} \ No newline at end of file