From 7175e7c7a10222cef0bbf69c06c70464b757e00b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 2 Mar 2010 15:38:52 -0800 Subject: [PATCH 01/33] OStatus fix: look for s in the current element's children, not in all its descendants. Was breaking notice URL transfer, pulling a profile link by mistake. --- lib/activity.php | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/activity.php b/lib/activity.php index b201532138..7926d05697 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -344,16 +344,18 @@ class ActivityUtils static function getLink(DOMNode $element, $rel, $type=null) { - $links = $element->getElementsByTagnameNS(self::ATOM, self::LINK); + $els = $element->childNodes; - foreach ($links as $link) { + foreach ($els as $link) { + if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) { - $linkRel = $link->getAttribute(self::REL); - $linkType = $link->getAttribute(self::TYPE); + $linkRel = $link->getAttribute(self::REL); + $linkType = $link->getAttribute(self::TYPE); - if ($linkRel == $rel && - (is_null($type) || $linkType == $type)) { - return $link->getAttribute(self::HREF); + if ($linkRel == $rel && + (is_null($type) || $linkType == $type)) { + return $link->getAttribute(self::HREF); + } } } @@ -362,17 +364,19 @@ class ActivityUtils static function getLinks(DOMNode $element, $rel, $type=null) { - $links = $element->getElementsByTagnameNS(self::ATOM, self::LINK); + $els = $element->childNodes; $out = array(); - foreach ($links as $link) { + foreach ($els as $link) { + if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) { - $linkRel = $link->getAttribute(self::REL); - $linkType = $link->getAttribute(self::TYPE); + $linkRel = $link->getAttribute(self::REL); + $linkType = $link->getAttribute(self::TYPE); - if ($linkRel == $rel && - (is_null($type) || $linkType == $type)) { - $out[] = $link; + if ($linkRel == $rel && + (is_null($type) || $linkType == $type)) { + $out[] = $link; + } } } From 8da1b71d6957b4fc2c9032a10e5be0613bafbde7 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 1 Mar 2010 16:35:36 -0800 Subject: [PATCH 02/33] Fix a bunch of notice & warning-level messages that were breaking my inter-instance communications --- plugins/OStatus/classes/Magicsig.php | 4 +++- plugins/OStatus/classes/Ostatus_profile.php | 2 +- plugins/OStatus/lib/discovery.php | 2 +- plugins/OStatus/lib/xrd.php | 11 ++++++++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/plugins/OStatus/classes/Magicsig.php b/plugins/OStatus/classes/Magicsig.php index 96900d8761..5a46aeeb6e 100644 --- a/plugins/OStatus/classes/Magicsig.php +++ b/plugins/OStatus/classes/Magicsig.php @@ -146,8 +146,10 @@ class Magicsig extends Memcached_DataObject $mod = base64_url_decode($matches[1]); $exp = base64_url_decode($matches[2]); - if ($matches[4]) { + if (!empty($matches[4])) { $private_exp = base64_url_decode($matches[4]); + } else { + $private_exp = false; } $params['public_key'] = new Crypt_RSA_KEY($mod, $exp, 'public'); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 7b1aec76ba..93e8934c9e 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1145,7 +1145,7 @@ class Ostatus_profile extends Memcached_DataObject if (!empty($poco)) { $url = $poco->getPrimaryURL(); - if ($url->type == 'homepage') { + if ($url && $url->type == 'homepage') { $homepage = $url->value; } } diff --git a/plugins/OStatus/lib/discovery.php b/plugins/OStatus/lib/discovery.php index 388df0a28f..f8449b309e 100644 --- a/plugins/OStatus/lib/discovery.php +++ b/plugins/OStatus/lib/discovery.php @@ -94,7 +94,7 @@ class Discovery $links = call_user_func(array($class, 'discover'), $uri); if ($link = Discovery::getService($links, Discovery::LRDD_REL)) { // Load the LRDD XRD - if ($link['template']) { + if (!empty($link['template'])) { $xrd_uri = Discovery::applyTemplate($link['template'], $uri); } else { $xrd_uri = $link['href']; diff --git a/plugins/OStatus/lib/xrd.php b/plugins/OStatus/lib/xrd.php index 16d27f8eb7..1de065db9f 100644 --- a/plugins/OStatus/lib/xrd.php +++ b/plugins/OStatus/lib/xrd.php @@ -53,17 +53,22 @@ class XRD $xrd = new XRD(); $dom = new DOMDocument(); - $dom->loadXML($xml); + if (!$dom->loadXML($xml)) { + throw new Exception("Invalid XML"); + } $xrd_element = $dom->getElementsByTagName('XRD')->item(0); // Check for host-meta host - $host = $xrd_element->getElementsByTagName('Host')->item(0)->nodeValue; + $host = $xrd_element->getElementsByTagName('Host')->item(0); if ($host) { - $xrd->host = $host; + $xrd->host = $host->nodeValue; } // Loop through other elements foreach ($xrd_element->childNodes as $node) { + if (!($node instanceof DOMElement)) { + continue; + } switch ($node->tagName) { case 'Expires': $xrd->expires = $node->nodeValue; From 49a872b56f82a3f1ba59f0751c11dfe7754393dd Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 1 Mar 2010 16:36:33 -0800 Subject: [PATCH 03/33] OStatus: support @example.com/path/to/profile mentions as well as @profile@example.com (latter requires webfinger, former doesn't) Plus misc warnings/notices cleanup in the submission path. --- actions/newnotice.php | 3 ++ plugins/OStatus/OStatusPlugin.php | 55 ++++++++++++++++----- plugins/OStatus/classes/Ostatus_profile.php | 2 +- plugins/OStatus/lib/xrd.php | 10 ++-- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/actions/newnotice.php b/actions/newnotice.php index 78480ababb..ed0fa1b2b5 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -294,6 +294,9 @@ class NewnoticeAction extends Action if ($profile) { $content = '@' . $profile->nickname . ' '; } + } else { + // @fixme most of these bits above aren't being passed on above + $inreplyto = null; } $notice_form = new NoticeForm($this, '', $content, null, $inreplyto); diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 720dedd0a0..4ffbba45b9 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -222,31 +222,62 @@ class OStatusPlugin extends Plugin } /** - * + * Find any explicit remote mentions. Accepted forms: + * Webfinger: @user@example.com + * Profile link: @example.com/mublog/user + * @param Profile $sender (os user?) + * @param string $text input markup text + * @param array &$mention in/out param: set of found mentions + * @return boolean hook return value */ function onEndFindMentions($sender, $text, &$mentions) { - preg_match_all('/(?:^|\s+)@((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)/', + preg_match_all('!(?:^|\s+) + @( # Webfinger: + (?:\w+\.)*\w+ # user + @ # @ + (?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+ # domain + | # Profile: + (?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+ # domain + (?:/\w+)+ # /path1(/path2...) + )!x', $text, $wmatches, PREG_OFFSET_CAPTURE); foreach ($wmatches[1] as $wmatch) { + $target = $wmatch[0]; + $oprofile = null; - $webfinger = $wmatch[0]; - - $this->log(LOG_INFO, "Checking Webfinger for address '$webfinger'"); - - $oprofile = Ostatus_profile::ensureWebfinger($webfinger); + if (strpos($target, '/') === false) { + $this->log(LOG_INFO, "Checking Webfinger for address '$target'"); + try { + $oprofile = Ostatus_profile::ensureWebfinger($target); + } catch (Exception $e) { + $this->log(LOG_ERR, "Webfinger check failed: " . $e->getMessage()); + } + } else { + $schemes = array('https', 'http'); + foreach ($schemes as $scheme) { + $url = "$scheme://$target"; + $this->log(LOG_INFO, "Checking profile address '$url'"); + try { + $oprofile = Ostatus_profile::ensureProfile($url); + if ($oprofile) { + continue; + } + } catch (Exception $e) { + $this->log(LOG_ERR, "Profile check failed: " . $e->getMessage()); + } + } + } if (empty($oprofile)) { - - $this->log(LOG_INFO, "No Ostatus_profile found for address '$webfinger'"); - + $this->log(LOG_INFO, "No Ostatus_profile found for address '$target'"); } else { - $this->log(LOG_INFO, "Ostatus_profile found for address '$webfinger'"); + $this->log(LOG_INFO, "Ostatus_profile found for address '$target'"); if ($oprofile->isGroup()) { continue; @@ -261,7 +292,7 @@ class OStatusPlugin extends Plugin } } $mentions[] = array('mentioned' => array($profile), - 'text' => $wmatch[0], + 'text' => $target, 'position' => $pos, 'url' => $profile->profileurl); } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 93e8934c9e..a33e95d932 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -698,7 +698,7 @@ class Ostatus_profile extends Memcached_DataObject { // Get the canonical feed URI and check it $discover = new FeedDiscovery(); - if ($hints['feedurl']) { + if (isset($hints['feedurl'])) { $feeduri = $hints['feedurl']; $feeduri = $discover->discoverFromFeedURL($feeduri); } else { diff --git a/plugins/OStatus/lib/xrd.php b/plugins/OStatus/lib/xrd.php index 1de065db9f..85df26c54c 100644 --- a/plugins/OStatus/lib/xrd.php +++ b/plugins/OStatus/lib/xrd.php @@ -161,20 +161,20 @@ class XRD function saveLink($doc, $link) { $link_element = $doc->createElement('Link'); - if ($link['rel']) { + if (!empty($link['rel'])) { $link_element->setAttribute('rel', $link['rel']); } - if ($link['type']) { + if (!empty($link['type'])) { $link_element->setAttribute('type', $link['type']); } - if ($link['href']) { + if (!empty($link['href'])) { $link_element->setAttribute('href', $link['href']); } - if ($link['template']) { + if (!empty($link['template'])) { $link_element->setAttribute('template', $link['template']); } - if (is_array($link['title'])) { + if (!empty($link['title']) && is_array($link['title'])) { foreach($link['title'] as $title) { $title = $doc->createElement('Title', $title); $link_element->appendChild($title); From 1fd91de82c0be74ae2305f1412b1cd1b2948dfbc Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 1 Mar 2010 14:58:06 -0800 Subject: [PATCH 04/33] Upgrade XML output scrubbing to better deal with newline and a few other chars --- lib/util.php | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/util.php b/lib/util.php index 8381bc63c0..f793cc10e9 100644 --- a/lib/util.php +++ b/lib/util.php @@ -770,8 +770,28 @@ function common_shorten_links($text) function common_xml_safe_str($str) { - // Neutralize control codes and surrogates - return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str); + // Replace common eol and extra whitespace input chars + $unWelcome = array( + "\t", // tab + "\n", // newline + "\r", // cr + "\0", // null byte eos + "\x0B" // vertical tab + ); + + $replacement = array( + ' ', // single space + ' ', + '', // nothing + '', + ' ' + ); + + $str = str_replace($unWelcome, $replacement, $str); + + // Neutralize any additional control codes and UTF-16 surrogates + // (Twitter uses '*') + return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str); } function common_tag_link($tag) From de65b15f9df6703268eeff92502152605ec0f536 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 1 Mar 2010 21:34:50 -0800 Subject: [PATCH 05/33] Initial Twitter bridge admin panel --- lib/default.php | 5 +- plugins/TwitterBridge/README | 32 +- plugins/TwitterBridge/TwitterBridgePlugin.php | 129 ++++++-- plugins/TwitterBridge/twitteradminpanel.php | 280 ++++++++++++++++++ .../TwitterBridge/twitterauthorization.php | 2 +- 5 files changed, 403 insertions(+), 45 deletions(-) create mode 100644 plugins/TwitterBridge/twitteradminpanel.php diff --git a/lib/default.php b/lib/default.php index d849055c21..668206acf0 100644 --- a/lib/default.php +++ b/lib/default.php @@ -177,8 +177,9 @@ $default = array('source' => 'StatusNet', # source attribute for Twitter 'taguri' => null), # base for tag URIs 'twitter' => - array('enabled' => true, - 'consumer_key' => null, + array('enabled' => true, + 'signin' => true, + 'consumer_key' => null, 'consumer_secret' => null), 'cache' => array('base' => null), diff --git a/plugins/TwitterBridge/README b/plugins/TwitterBridge/README index d3bcda5984..91b34eb497 100644 --- a/plugins/TwitterBridge/README +++ b/plugins/TwitterBridge/README @@ -1,7 +1,7 @@ This Twitter "bridge" plugin allows you to integrate your StatusNet instance with Twitter. Installing it will allow your users to: - - automatically post notices to thier Twitter accounts + - automatically post notices to their Twitter accounts - automatically subscribe to other Twitter users who are also using your StatusNet install, if possible (requires running a daemon) - import their Twitter friends' tweets (requires running a daemon) @@ -9,18 +9,14 @@ instance with Twitter. Installing it will allow your users to: Installation ------------ -To enable the plugin, add the following to your config.php: - - addPlugin("TwitterBridge"); - -OAuth is used to to access protected resources on Twitter (as opposed to -HTTP Basic Auth)*. To use Twitter bridging you will need to register -your instance of StatusNet as an application on Twitter -(http://twitter.com/apps), and update the following variables in your -config.php with the consumer key and secret Twitter generates for you: - - $config['twitter']['consumer_key'] = 'YOURKEY'; - $config['twitter']['consumer_secret'] = 'YOURSECRET'; +OAuth (http://oauth.net) is used to to access protected resources on +Twitter (as opposed to HTTP Basic Auth)*. To use Twitter bridging you +will need to register your instance of StatusNet as an application on +Twitter (http://twitter.com/apps). During the application registration +process your application will be assigned a "consumer" key and secret, +which the plugin will use to make OAuth requests to Twitter. You can +either pass the consumer key and secret in when you enable the plugin, +or set it using the Twitter administration panel. When registering your application with Twitter set the type to "Browser" and your Callback URL to: @@ -29,6 +25,16 @@ and your Callback URL to: The default access type should be, "Read & Write". +To enable the plugin, add the following to your config.php: + + addPlugin( + 'TwitterBridge', + array( + 'consumer_key' => 'YOUR_CONSUMER_KEY', + 'consumer_secret' => 'YOUR_CONSUMER_SECRET' + ) + ); + * Note: The plugin will still push notices to Twitter for users who have previously setup the Twitter bridge using their Twitter name and password under an older versions of StatusNet, but all new Twitter diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index c7f57ffc77..ac08cc593f 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -23,7 +23,7 @@ * @author Julien C * @copyright 2009-2010 Control Yourself, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ + * @link http://status.net/ */ if (!defined('STATUSNET')) { @@ -32,8 +32,6 @@ if (!defined('STATUSNET')) { require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php'; -define('TWITTERBRIDGEPLUGIN_VERSION', '0.9'); - /** * Plugin for sending and importing Twitter statuses * @@ -44,19 +42,41 @@ define('TWITTERBRIDGEPLUGIN_VERSION', '0.9'); * @author Zach Copley * @author Julien C * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ + * @link http://status.net/ * @link http://twitter.com/ */ class TwitterBridgePlugin extends Plugin { + + const VERSION = STATUSNET_VERSION; + /** * Initializer for the plugin. */ - function __construct() + function initialize() { - parent::__construct(); + // Allow the key and secret to be passed in + // Control panel will override + + if (isset($this->consumer_key)) { + $key = common_config('twitter', 'consumer_key'); + if (empty($key)) { + Config::save('twitter', 'consumer_key', $this->consumer_key); + } + } + + if (isset($this->consumer_secret)) { + $secret = common_config('twitter', 'consumer_secret'); + if (empty($secret)) { + Config::save( + 'twitter', + 'consumer_secret', + $this->consumer_secret + ); + } + } } /** @@ -71,10 +91,13 @@ class TwitterBridgePlugin extends Plugin function onRouterInitialized($m) { - $m->connect('twitter/authorization', - array('action' => 'twitterauthorization')); + $m->connect( + 'twitter/authorization', + array('action' => 'twitterauthorization') + ); $m->connect('settings/twitter', array('action' => 'twittersettings')); $m->connect('main/twitterlogin', array('action' => 'twitterlogin')); + $m->connect('admin/twitter', array('action' => 'twitteradminpanel')); return true; } @@ -88,13 +111,14 @@ class TwitterBridgePlugin extends Plugin */ function onEndLoginGroupNav(&$action) { - $action_name = $action->trimmed('action'); - $action->menuItem(common_local_url('twitterlogin'), - _('Twitter'), - _('Login or register using Twitter'), - 'twitterlogin' === $action_name); + $action->menuItem( + common_local_url('twitterlogin'), + _m('Twitter'), + _m('Login or register using Twitter'), + 'twitterlogin' === $action_name + ); return true; } @@ -110,10 +134,12 @@ class TwitterBridgePlugin extends Plugin { $action_name = $action->trimmed('action'); - $action->menuItem(common_local_url('twittersettings'), - _m('Twitter'), - _m('Twitter integration options'), - $action_name === 'twittersettings'); + $action->menuItem( + common_local_url('twittersettings'), + _m('Twitter'), + _m('Twitter integration options'), + $action_name === 'twittersettings' + ); return true; } @@ -132,6 +158,7 @@ class TwitterBridgePlugin extends Plugin case 'TwittersettingsAction': case 'TwitterauthorizationAction': case 'TwitterloginAction': + case 'TwitteradminpanelAction': include_once INSTALLDIR . '/plugins/TwitterBridge/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; @@ -173,12 +200,18 @@ class TwitterBridgePlugin extends Plugin */ function onGetValidDaemons($daemons) { - array_push($daemons, INSTALLDIR . - '/plugins/TwitterBridge/daemons/synctwitterfriends.php'); + array_push( + $daemons, + INSTALLDIR + . '/plugins/TwitterBridge/daemons/synctwitterfriends.php' + ); if (common_config('twitterimport', 'enabled')) { - array_push($daemons, INSTALLDIR - . '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php'); + array_push( + $daemons, + INSTALLDIR + . '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php' + ); } return true; @@ -197,17 +230,55 @@ class TwitterBridgePlugin extends Plugin return true; } + /** + * Add a Twitter tab to the admin panel + * + * @param Widget $nav Admin panel nav + * + * @return boolean hook value + */ + + function onEndAdminPanelNav($nav) + { + if (AdminPanelAction::canAdmin('twitter')) { + + $action_name = $nav->action->trimmed('action'); + + $nav->out->menuItem( + common_local_url('twitteradminpanel'), + _m('Twitter'), + _m('Twitter bridge configuration'), + $action_name == 'twitteradminpanel', + 'nav_twitter_admin_panel' + ); + } + + return true; + } + + /** + * Plugin version data + * + * @param array &$versions array of version blocks + * + * @return boolean hook value + */ + function onPluginVersion(&$versions) { - $versions[] = array('name' => 'TwitterBridge', - 'version' => TWITTERBRIDGEPLUGIN_VERSION, - 'author' => 'Zach Copley', - 'homepage' => 'http://status.net/wiki/Plugin:TwitterBridge', - 'rawdescription' => - _m('The Twitter "bridge" plugin allows you to integrate ' . - 'your StatusNet instance with ' . - 'Twitter.')); + $versions[] = array( + 'name' => 'TwitterBridge', + 'version' => self::VERSION, + 'author' => 'Zach Copley, Julien C', + 'homepage' => 'http://status.net/wiki/Plugin:TwitterBridge', + 'rawdescription' => _m( + 'The Twitter "bridge" plugin allows you to integrate ' . + 'your StatusNet instance with ' . + 'Twitter.' + ) + ); return true; } } + diff --git a/plugins/TwitterBridge/twitteradminpanel.php b/plugins/TwitterBridge/twitteradminpanel.php new file mode 100644 index 0000000000..b22e6d99fe --- /dev/null +++ b/plugins/TwitterBridge/twitteradminpanel.php @@ -0,0 +1,280 @@ +. + * + * @category Settings + * @package StatusNet + * @author Zach Copley + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Administer global Twitter bridge settings + * + * @category Admin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class TwitteradminpanelAction extends AdminPanelAction +{ + /** + * Returns the page title + * + * @return string page title + */ + + function title() + { + return _m('Twitter'); + } + + /** + * Instructions for using this form. + * + * @return string instructions + */ + + function getInstructions() + { + return _m('Twitter bridge settings'); + } + + /** + * Show the Twitter admin panel form + * + * @return void + */ + + function showForm() + { + $form = new TwitterAdminPanelForm($this); + $form->show(); + return; + } + + /** + * Save settings from the form + * + * @return void + */ + + function saveSettings() + { + static $settings = array( + 'twitter' => array('consumer_key', 'consumer_secret'), + 'integration' => array('source') + ); + + static $booleans = array( + 'twitter' => array('signin'), + 'twitterimport' => array('enabled') + ); + + $values = array(); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] + = $this->trimmed($setting); + } + } + + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] + = ($this->boolean($setting)) ? 1 : 0; + } + } + + // This throws an exception on validation errors + + $this->validate($values); + + // assert(all values are valid); + + $config = new Config(); + + $config->query('BEGIN'); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + foreach ($booleans as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + $config->query('COMMIT'); + + return; + } + + function validate(&$values) + { + // Validate consumer key and secret (can't be too long) + + if (mb_strlen($values['twitter']['consumer_key']) > 255) { + $this->clientError( + _m("Invalid consumer key. Max length is 255 characters.") + ); + } + + if (mb_strlen($values['twitter']['consumer_secret']) > 255) { + $this->clientError( + _m("Invalid consumer secret. Max length is 255 characters.") + ); + } + } +} + +class TwitterAdminPanelForm extends AdminForm +{ + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + return 'twitteradminpanel'; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_settings'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('twitteradminpanel'); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_twitter-application') + ); + $this->out->element('legend', null, _m('Twitter application settings')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->input( + 'consumer_key', + _m('Consumer key'), + _m('Consumer key assigned by Twitter'), + 'twitter' + ); + $this->unli(); + + $this->li(); + $this->input( + 'consumer_secret', + _m('Consumer secret'), + _m('Consumer secret assigned by Twitter'), + 'twitter' + ); + $this->unli(); + + $this->li(); + $this->input( + 'source', + _m('Integration source'), + _m('Name of your Twitter application'), + 'integration' + ); + $this->unli(); + + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_twitter-options') + ); + $this->out->element('legend', null, _m('Options')); + + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + + $this->out->checkbox( + 'signin', _m('Enable "Sign-in with Twitter"'), + (bool) $this->value('signin', 'twitter'), + _m('Allow users to login with their Twitter credentials') + ); + $this->unli(); + + $this->li(); + $this->out->checkbox( + 'enabled', _m('Enable Twitter import'), + (bool) $this->value('enabled', 'twitterimport'), + _m('Allow users to import their Twitter friends\' timelines') + ); + $this->unli(); + + $this->out->elementEnd('ul'); + + $this->out->elementEnd('fieldset'); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Save'), 'submit', null, _('Save Twitter settings')); + } +} diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php index cabf69d7a8..c93f6666bc 100644 --- a/plugins/TwitterBridge/twitterauthorization.php +++ b/plugins/TwitterBridge/twitterauthorization.php @@ -47,7 +47,7 @@ require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php'; * @author Zach Copley * @author Julien C * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ + * @link http://status.net/ * */ class TwitterauthorizationAction extends Action From 705891f9bef09b59d957a4fbd48c1bab3e025942 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 1 Mar 2010 21:52:31 -0800 Subject: [PATCH 06/33] Remove un-needed config variable for enabling/disabling Twitter integration --- lib/action.php | 2 -- lib/default.php | 3 +-- plugins/Facebook/FacebookPlugin.php | 2 -- plugins/MobileProfile/MobileProfilePlugin.php | 2 -- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/action.php b/lib/action.php index fa9ddb9110..94b1fa5358 100644 --- a/lib/action.php +++ b/lib/action.php @@ -425,8 +425,6 @@ class Action extends HTMLOutputter // lawsuit $connect = 'imsettings'; } else if (common_config('sms', 'enabled')) { $connect = 'smssettings'; - } else if (common_config('twitter', 'enabled')) { - $connect = 'twittersettings'; } $this->elementStart('dl', array('id' => 'site_nav_global_primary')); diff --git a/lib/default.php b/lib/default.php index 668206acf0..7b50242ae2 100644 --- a/lib/default.php +++ b/lib/default.php @@ -177,8 +177,7 @@ $default = array('source' => 'StatusNet', # source attribute for Twitter 'taguri' => null), # base for tag URIs 'twitter' => - array('enabled' => true, - 'signin' => true, + array('signin' => true, 'consumer_key' => null, 'consumer_secret' => null), 'cache' => diff --git a/plugins/Facebook/FacebookPlugin.php b/plugins/Facebook/FacebookPlugin.php index 4266b886d9..8fb81aea02 100644 --- a/plugins/Facebook/FacebookPlugin.php +++ b/plugins/Facebook/FacebookPlugin.php @@ -359,8 +359,6 @@ class FacebookPlugin extends Plugin $connect = 'imsettings'; } else if (common_config('sms', 'enabled')) { $connect = 'smssettings'; - } else if (common_config('twitter', 'enabled')) { - $connect = 'twittersettings'; } if (!empty($user)) { diff --git a/plugins/MobileProfile/MobileProfilePlugin.php b/plugins/MobileProfile/MobileProfilePlugin.php index cd2531fa72..f788639aed 100644 --- a/plugins/MobileProfile/MobileProfilePlugin.php +++ b/plugins/MobileProfile/MobileProfilePlugin.php @@ -312,8 +312,6 @@ class MobileProfilePlugin extends WAP20Plugin $connect = 'imsettings'; } else if (common_config('sms', 'enabled')) { $connect = 'smssettings'; - } else if (common_config('twitter', 'enabled')) { - $connect = 'twittersettings'; } $action->elementStart('ul', array('id' => 'site_nav_global_primary')); From 61036953decc021e4de2ce575160d5fe4a0460f1 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 1 Mar 2010 22:41:07 -0800 Subject: [PATCH 07/33] - Make 'Sign in with Twitter' optional - Updates to the Twitter bridge plugin README --- plugins/TwitterBridge/README | 86 +++++++++++++------ plugins/TwitterBridge/TwitterBridgePlugin.php | 20 +++-- 2 files changed, 74 insertions(+), 32 deletions(-) diff --git a/plugins/TwitterBridge/README b/plugins/TwitterBridge/README index 91b34eb497..a386989b7a 100644 --- a/plugins/TwitterBridge/README +++ b/plugins/TwitterBridge/README @@ -5,25 +5,29 @@ instance with Twitter. Installing it will allow your users to: - automatically subscribe to other Twitter users who are also using your StatusNet install, if possible (requires running a daemon) - import their Twitter friends' tweets (requires running a daemon) + - allow users to authenticate using Twitter ('Sign in with Twitter') Installation ------------ -OAuth (http://oauth.net) is used to to access protected resources on -Twitter (as opposed to HTTP Basic Auth)*. To use Twitter bridging you -will need to register your instance of StatusNet as an application on -Twitter (http://twitter.com/apps). During the application registration -process your application will be assigned a "consumer" key and secret, -which the plugin will use to make OAuth requests to Twitter. You can -either pass the consumer key and secret in when you enable the plugin, -or set it using the Twitter administration panel. +OAuth 1.0a (http://oauth.net) is used to to access protected resources +on Twitter (as opposed to HTTP Basic Auth)*. To use Twitter bridging +you will need to register your instance of StatusNet as an application +on Twitter (http://twitter.com/apps). During the application +registration process your application will be assigned a "consumer" key +and secret, which the plugin will use to make OAuth requests to Twitter. +You can either pass the consumer key and secret in when you enable the +plugin, or set it using the Twitter administration panel. When registering your application with Twitter set the type to "Browser" and your Callback URL to: http://example.org/mublog/twitter/authorization -The default access type should be, "Read & Write". +(Change "example.org" to your site domain and "mublog" to your site +path.) + +The default access type should be "Read & Write". To enable the plugin, add the following to your config.php: @@ -36,18 +40,47 @@ To enable the plugin, add the following to your config.php: ); * Note: The plugin will still push notices to Twitter for users who - have previously setup the Twitter bridge using their Twitter name and - password under an older versions of StatusNet, but all new Twitter + have previously set up the Twitter bridge using their Twitter name and + password under an older version of StatusNet, but all new Twitter bridge connections will use OAuth. -Deamons +Admin panel +----------- + +As of StatusNet 0.9.0 there is a new administration panel that allows +you to configure Twitter bridge settings within StatusNet itself, +instead of having to specify them manually in your config.php. To enable +the administration panel, you will need to add it to the list of active +administration panels. You can do this via your config.php. E.g.: + + $config['admin']['panels'][] = 'twitter'; + +And to access it, you'll need to use a user with the "administrator" +role (see: scripts/userrole.php). + +Sign in with Twitter +-------------------- + +As of 0.9.0 you StatusNet optionally allows users to register and +authenticate using their Twitter credentials via the "Sign in with +Twitter" pattern described here: + + http://apiwiki.twitter.com/Sign-in-with-Twitter + +The option is _on_ by default when you install the plugin, but it can +disabled via the Twitter bridge admin panel, or by adding the following +line to your config.php: + + $config['twitter']['signin'] = false; + +Daemons ------- -For friend syncing and importing notices running two additional daemon -scripts is necessary (synctwitterfriends.php and -twitterstatusfetcher.php). +For friend syncing and importing Twitter tweets, running two +additional daemon scripts is necessary: synctwitterfriends.php and +twitterstatusfetcher.php. -In the daemons subidrectory of the plugin are three scripts: +In the daemons subdirectory of the plugin are three scripts: * Twitter Friends Syncing (daemons/synctwitterfriends.php) @@ -57,13 +90,13 @@ subscribe to "friends" (people they "follow") on Twitter who also have accounts on your StatusNet system, and who have previously set up a link for automatically posting notices to Twitter. -The plugin will try to start this daemon when you run -scripts/startdaemons.sh. +The plugin will start this daemon when you run scripts/startdaemons.sh. * Importing statuses from Twitter (daemons/twitterstatusfetcher.php) -To allow your users to import their friends' Twitter statuses, you will -need to enable the bidirectional Twitter bridge in your config.php: +You can allow uses to enable importing of your friends' Twitter +timelines either in the Twitter bridge administration panel or in your +config.php using the following configuration line: $config['twitterimport']['enabled'] = true; @@ -72,8 +105,9 @@ other daemons when you run scripts/startdaemons.sh. Additionally, you will want to set the integration source variable, which will keep notices posted to Twitter via StatusNet from looping -back. The integration source should be set to the name of your -application, exactly as you specified it on the settings page for your +back. You can do this in the Twitter bridge administration panel, or +via config.php. The integration source should be set to the name of your +application _exactly_ as you specified it on the settings page for your StatusNet application on Twitter, e.g.: $config['integration']['source'] = 'YourApp'; @@ -85,7 +119,9 @@ set up Twitter bridging. It's not strictly necessary to run this queue handler, and sites that haven't enabled queuing are still able to push notices to Twitter, but -for larger sites and sites that wish to improve performance, this -script allows notices to be sent "offline" via a separate process. +for larger sites and sites that wish to improve performance, this script +allows notices to be sent "offline" via a separate process. -The plugin will start this script when you run scripts/startdaemons.sh. +StatusNet will automatically use the TwitterQueueHandler if you have +enabled the queuing system. See the "Queues and daemons" section of the +main README file for more information about how to do that. diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index ac08cc593f..6ce69d5e2b 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -96,7 +96,11 @@ class TwitterBridgePlugin extends Plugin array('action' => 'twitterauthorization') ); $m->connect('settings/twitter', array('action' => 'twittersettings')); - $m->connect('main/twitterlogin', array('action' => 'twitterlogin')); + + if (common_config('twitter', 'signin')) { + $m->connect('main/twitterlogin', array('action' => 'twitterlogin')); + } + $m->connect('admin/twitter', array('action' => 'twitteradminpanel')); return true; @@ -113,12 +117,14 @@ class TwitterBridgePlugin extends Plugin { $action_name = $action->trimmed('action'); - $action->menuItem( - common_local_url('twitterlogin'), - _m('Twitter'), - _m('Login or register using Twitter'), - 'twitterlogin' === $action_name - ); + if (common_config('twitter', 'signin')) { + $action->menuItem( + common_local_url('twitterlogin'), + _m('Twitter'), + _m('Login or register using Twitter'), + 'twitterlogin' === $action_name + ); + } return true; } From 625215cd80af34a9dd4e68072221d1de5a30ad87 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 1 Mar 2010 22:58:27 -0800 Subject: [PATCH 08/33] Some wording / spelling fixes --- plugins/TwitterBridge/README | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/plugins/TwitterBridge/README b/plugins/TwitterBridge/README index a386989b7a..72278b32e6 100644 --- a/plugins/TwitterBridge/README +++ b/plugins/TwitterBridge/README @@ -1,3 +1,6 @@ +Twitter Bridge Plugin +===================== + This Twitter "bridge" plugin allows you to integrate your StatusNet instance with Twitter. Installing it will allow your users to: @@ -44,8 +47,8 @@ To enable the plugin, add the following to your config.php: password under an older version of StatusNet, but all new Twitter bridge connections will use OAuth. -Admin panel ------------ +Administration panel +-------------------- As of StatusNet 0.9.0 there is a new administration panel that allows you to configure Twitter bridge settings within StatusNet itself, @@ -61,15 +64,15 @@ role (see: scripts/userrole.php). Sign in with Twitter -------------------- -As of 0.9.0 you StatusNet optionally allows users to register and +With 0.9.0, StatusNet optionally allows users to register and authenticate using their Twitter credentials via the "Sign in with Twitter" pattern described here: http://apiwiki.twitter.com/Sign-in-with-Twitter The option is _on_ by default when you install the plugin, but it can -disabled via the Twitter bridge admin panel, or by adding the following -line to your config.php: +disabled via the Twitter bridge administration panel, or by adding the +following line to your config.php: $config['twitter']['signin'] = false; @@ -119,9 +122,9 @@ set up Twitter bridging. It's not strictly necessary to run this queue handler, and sites that haven't enabled queuing are still able to push notices to Twitter, but -for larger sites and sites that wish to improve performance, this script +for larger sites and sites that wish to improve performance the script allows notices to be sent "offline" via a separate process. StatusNet will automatically use the TwitterQueueHandler if you have -enabled the queuing system. See the "Queues and daemons" section of the -main README file for more information about how to do that. +enabled the queuing subsystem. See the "Queues and daemons" section of +the main README file for more information about how to do that. From 84663dccff4d3ca4e321cef99e9d4d556ba29ec4 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 1 Mar 2010 23:31:56 -0800 Subject: [PATCH 09/33] Initial Facebook admin panel --- plugins/Facebook/FacebookPlugin.php | 85 +++++++-- plugins/Facebook/facebookadminpanel.php | 223 ++++++++++++++++++++++++ 2 files changed, 296 insertions(+), 12 deletions(-) create mode 100644 plugins/Facebook/facebookadminpanel.php diff --git a/plugins/Facebook/FacebookPlugin.php b/plugins/Facebook/FacebookPlugin.php index 8fb81aea02..014d0d1970 100644 --- a/plugins/Facebook/FacebookPlugin.php +++ b/plugins/Facebook/FacebookPlugin.php @@ -22,7 +22,7 @@ * @category Plugin * @package StatusNet * @author Zach Copley - * @copyright 2009 StatusNet, Inc. + * @copyright 2009-2010 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -32,12 +32,12 @@ if (!defined('STATUSNET')) { } define("FACEBOOK_CONNECT_SERVICE", 3); -define('FACEBOOKPLUGIN_VERSION', '0.9'); require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php'; /** - * Facebook plugin to add a StatusNet Facebook application + * Facebook plugin to add a StatusNet Facebook canvas application + * and allow registration and authentication via Facebook Connect * * @category Plugin * @package StatusNet @@ -49,6 +49,36 @@ require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php'; class FacebookPlugin extends Plugin { + const VERSION = STATUSNET_VERSION; + + /** + * Initializer for the plugin. + */ + + function initialize() + { + // Allow the key and secret to be passed in + // Control panel will override + + if (isset($this->apikey)) { + $key = common_config('facebook', 'apikey'); + if (empty($key)) { + Config::save('facebook', 'apikey', $this->apikey); + } + } + + if (isset($this->secret)) { + $secret = common_config('facebook', 'secret'); + if (empty($secret)) { + Config::save( + 'facebook', + 'secret', + $this->secret + ); + } + } + } + /** * Add Facebook app actions to the router table * @@ -70,6 +100,7 @@ class FacebookPlugin extends Plugin array('action' => 'facebooksettings')); $m->connect('facebook/app/invite.php', array('action' => 'facebookinvite')); $m->connect('facebook/app/remove', array('action' => 'facebookremove')); + $m->connect('admin/facebook', array('action' => 'facebookadminpanel')); // Facebook Connect stuff @@ -98,6 +129,7 @@ class FacebookPlugin extends Plugin case 'FacebookinviteAction': case 'FacebookremoveAction': case 'FacebooksettingsAction': + case 'FacebookadminpanelAction': include_once INSTALLDIR . '/plugins/Facebook/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; @@ -122,6 +154,32 @@ class FacebookPlugin extends Plugin } } + /** + * Add a Facebook tab to the admin panels + * + * @param Widget $nav Admin panel nav + * + * @return boolean hook value + */ + + function onEndAdminPanelNav($nav) + { + if (AdminPanelAction::canAdmin('facebook')) { + + $action_name = $nav->action->trimmed('action'); + + $nav->out->menuItem( + common_local_url('facebookadminpanel'), + _m('Facebook'), + _m('Facebook integration configuration'), + $action_name == 'facebookadminpanel', + 'nav_facebook_admin_panel' + ); + } + + return true; + } + /** * Override normal HTML output to force the content type to * text/html and add in xmlns:fb @@ -523,15 +581,18 @@ class FacebookPlugin extends Plugin function onPluginVersion(&$versions) { - $versions[] = array('name' => 'Facebook', - 'version' => FACEBOOKPLUGIN_VERSION, - 'author' => 'Zach Copley', - 'homepage' => 'http://status.net/wiki/Plugin:Facebook', - 'rawdescription' => - _m('The Facebook plugin allows you to integrate ' . - 'your StatusNet instance with ' . - 'Facebook ' . - 'and Facebook Connect.')); + $versions[] = array( + 'name' => 'Facebook', + 'version' => self::VERSION, + 'author' => 'Zach Copley', + 'homepage' => 'http://status.net/wiki/Plugin:Facebook', + 'rawdescription' => _m( + 'The Facebook plugin allows you to integrate ' . + 'your StatusNet instance with ' . + 'Facebook ' . + 'and Facebook Connect.' + ) + ); return true; } diff --git a/plugins/Facebook/facebookadminpanel.php b/plugins/Facebook/facebookadminpanel.php new file mode 100644 index 0000000000..ae1c7302f9 --- /dev/null +++ b/plugins/Facebook/facebookadminpanel.php @@ -0,0 +1,223 @@ +. + * + * @category Settings + * @package StatusNet + * @author Zach Copley + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Administer global Facebook integration settings + * + * @category Admin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class FacebookadminpanelAction extends AdminPanelAction +{ + /** + * Returns the page title + * + * @return string page title + */ + + function title() + { + return _m('Facebook'); + } + + /** + * Instructions for using this form. + * + * @return string instructions + */ + + function getInstructions() + { + return _m('Facebook integration settings'); + } + + /** + * Show the Facebook admin panel form + * + * @return void + */ + + function showForm() + { + $form = new FacebookAdminPanelForm($this); + $form->show(); + return; + } + + /** + * Save settings from the form + * + * @return void + */ + + function saveSettings() + { + static $settings = array( + 'facebook' => array('apikey', 'secret'), + ); + + $values = array(); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + $values[$section][$setting] + = $this->trimmed($setting); + } + } + + // This throws an exception on validation errors + + $this->validate($values); + + // assert(all values are valid); + + $config = new Config(); + + $config->query('BEGIN'); + + foreach ($settings as $section => $parts) { + foreach ($parts as $setting) { + Config::save($section, $setting, $values[$section][$setting]); + } + } + + $config->query('COMMIT'); + + return; + } + + function validate(&$values) + { + // Validate consumer key and secret (can't be too long) + + if (mb_strlen($values['facebook']['apikey']) > 255) { + $this->clientError( + _m("Invalid Facebook API key. Max length is 255 characters.") + ); + } + + if (mb_strlen($values['facebook']['secret']) > 255) { + $this->clientError( + _m("Invalid Facebook API secret. Max length is 255 characters.") + ); + } + } +} + +class FacebookAdminPanelForm extends AdminForm +{ + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + return 'facebookadminpanel'; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_settings'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('facebookadminpanel'); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->elementStart( + 'fieldset', + array('id' => 'settings_facebook-application') + ); + $this->out->element('legend', null, _m('Facebook application settings')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->input( + 'apikey', + _m('API key'), + _m('API key provided by Facebook'), + 'facebook' + ); + $this->unli(); + + $this->li(); + $this->input( + 'secret', + _m('Secret'), + _m('API secret provided by Facebook'), + 'facebook' + ); + $this->unli(); + + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Save'), 'submit', null, _('Save Facebook settings')); + } +} From b533e0e7356ce99922334a0f381a14044e109d6a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 2 Mar 2010 00:38:00 -0800 Subject: [PATCH 10/33] Update Facebook plugin README with info about new admin panel --- plugins/Facebook/README | 84 +++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/plugins/Facebook/README b/plugins/Facebook/README index bf2f4a1800..14c1d32419 100644 --- a/plugins/Facebook/README +++ b/plugins/Facebook/README @@ -1,6 +1,9 @@ -This plugin allows you to use Facebook Connect with StatusNet, provides a -Facebook application for your users, and allows them to update their -Facebook statuses from StatusNet. +Facebook Plugin +=============== + +This plugin allows you to use Facebook Connect with StatusNet, provides +a Facebook canvas application for your users, and allows them to update +their Facebook statuses from StatusNet. Facebook Connect ---------------- @@ -15,12 +18,12 @@ Facebook credentials. With Facebook Connect, your users can: Built-in Facebook Application ----------------------------- -The plugin also installs a StatusNet Facebook application that allows your -users to automatically update their Facebook statuses with their latest -notices, invite their friends to use the app (and thus your site), view -their notice timelines, and post notices -- all from within Facebook. The -application is built into the StatusNet Facebook plugin and runs on your -host. +The plugin also installs a StatusNet Facebook canvas application that +allows your users to automatically update their Facebook status with +their latest notices, invite their friends to use the app (and thus your +site), view their notice timelines and post notices -- all from within +Facebook. The application is built into the StatusNet Facebook plugin +and runs on your host. Quick setup instructions* ------------------------- @@ -29,13 +32,9 @@ Install the Facebook Developer application on Facebook: http://www.facebook.com/developers/ -Use it to create a new application and generate an API key and secret. Add a -Facebook app section of your config.php and copy in the key and secret, -e.g.: - - // Config section for the built-in Facebook application - $config['facebook']['apikey'] = 'APIKEY'; - $config['facebook']['secret'] = 'SECRET'; +Use it to create a new application and generate an API key and secret. +You will need the key and secret so cut-n-paste them into your text +editor or write them down. In Facebook's application editor, specify the following URLs for your app: @@ -67,11 +66,36 @@ can be left with default values. http://wiki.developers.facebook.com/index.php/Connect/Setting_Up_Your_Site http://wiki.developers.facebook.com/index.php/Creating_your_first_application -Finally you must activate the plugin by adding the following line to your -config.php: +Finally you must activate the plugin by adding it in your config.php +(this is where you'll need the API key and secret generated earlier): + + addPlugin( + 'Facebook', + array( + 'apikey' => 'YOUR_APIKEY', + 'secret' => 'YOUR_SECRET' + ) + ); + +Administration Panel +-------------------- + +As of StatusNet 0.9.0 you can alternatively specify the key and secret +via a Facebook administration panel from within StatusNet, in which case +you can just add: addPlugin('Facebook'); +to activate the plugin. + +NOTE: To enable the administration panel you'll need to add it to the +list of active administration panels, e.g.: + + $config['admin']['panels'][] = 'facebook'; + +and of course you'll need a user with the administrative role to access +it and input the API key and secret (see: scripts/userrole.php). + Testing It Out -------------- @@ -81,11 +105,11 @@ disconnect* to their Facebook accounts from it. To try out the plugin, fire up your browser and connect to: - http://SITE/PATH_TO_STATUSNET/main/facebooklogin + http://example.net/mublog/main/facebooklogin or, if you do not have fancy URLs turned on: - http://SITE/PATH_TO_STATUSNET/index.php/main/facebooklogin + http://example.net/mublog/index.php/main/facebooklogin You should see a page with a blue button that says: "Connect with Facebook" and you should be able to login or register. @@ -101,7 +125,7 @@ the app, you are given the option to update their Facebook status via StatusNet. * Note: Before a user can disconnect from Facebook, she must set a normal - StatusNet password. Otherwise, she might not be able to login in to her + StatusNet password. Otherwise, she might not be able to login in to her account in the future. This is usually only required for users who have used Facebook Connect to register their StatusNet account, and therefore haven't already set a local password. @@ -109,16 +133,20 @@ StatusNet. Offline Queue Handling ---------------------- -For larger sites needing better performance it's possible to enable queuing -and have users' notices posted to Facebook via a separate "offline" -FacebookQueueHandler (facebookqueuhandler.php in the Facebook plugin -directory), which will be started by the plugin along with their other -daemons when you run scripts/startdaemons.sh. See the StatusNet README for -more about queuing and daemons. +For larger sites needing better performance it's possible to enable +queuing and have users' notices posted to Facebook via a separate +"offline" process -- FacebookQueueHandler (facebookqueuhandler.php in +the Facebook plugin directory). It will run automatically if you have +enabled StatusNet's offline queueing subsystem. See the "Queues and +daemons" section in the StatusNet README for more about queuing. + TODO ---- +- Make Facebook Connect work for authentication for multi-site setups + (e.g.: *.status.net) +- Posting to Facebook user streams using only Facebook Connect - Invite Facebook friends to use your StatusNet installation via Facebook Connect - Auto-subscribe Facebook friends already using StatusNet @@ -126,4 +154,4 @@ TODO - Allow users to update their Facebook statuses once they have authenticated with Facebook Connect (no need for them to use the Facebook app if they don't want to). -- Re-design the whole thing to support multiple instances of StatusNet +- Import a user's Facebook updates into StatusNet From 8a3f27ac9102029f7c8b8eb44431e1df4d82a9b9 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Fri, 22 Jan 2010 10:12:26 -0500 Subject: [PATCH 11/33] Updated some references to the long gnone "isEnclosure" function to the new "getEnclosure" --- classes/File.php | 2 ++ lib/apiaction.php | 9 +++++---- lib/util.php | 15 ++++----------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/classes/File.php b/classes/File.php index 91b12d2e28..189e04ce02 100644 --- a/classes/File.php +++ b/classes/File.php @@ -279,6 +279,8 @@ class File extends Memcached_DataObject if($oembed->modified) $enclosure->modified=$oembed->modified; unset($oembed->size); } + } else { + return false; } } } diff --git a/lib/apiaction.php b/lib/apiaction.php index 2af150ab99..f7b4ef473e 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -289,11 +289,12 @@ class ApiAction extends Action $twitter_status['attachments'] = array(); foreach ($attachments as $attachment) { - if ($attachment->isEnclosure()) { + $enclosure_o=$attachment->getEnclosure(); + if ($attachment_enclosure) { $enclosure = array(); - $enclosure['url'] = $attachment->url; - $enclosure['mimetype'] = $attachment->mimetype; - $enclosure['size'] = $attachment->size; + $enclosure['url'] = $enclosure_o->url; + $enclosure['mimetype'] = $enclosure_o->mimetype; + $enclosure['size'] = $enclosure_o->size; $twitter_status['attachments'][] = $enclosure; } } diff --git a/lib/util.php b/lib/util.php index f793cc10e9..77a332b5ec 100644 --- a/lib/util.php +++ b/lib/util.php @@ -731,20 +731,13 @@ function common_linkify($url) { } if (!empty($f)) { - if ($f->isEnclosure()) { + if ($f->getEnclosure()) { $is_attachment = true; $attachment_id = $f->id; - } else { - $foe = File_oembed::staticGet('file_id', $f->id); - if (!empty($foe)) { - // if it has OEmbed info, it's an attachment, too - $is_attachment = true; - $attachment_id = $f->id; - $thumb = File_thumbnail::staticGet('file_id', $f->id); - if (!empty($thumb)) { - $has_thumb = true; - } + $thumb = File_thumbnail::staticGet('file_id', $f->id); + if (!empty($thumb)) { + $has_thumb = true; } } } From b1e172a3d9bdeb8f9b7a5559d45b843245a1a3b0 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Fri, 22 Jan 2010 10:40:21 -0500 Subject: [PATCH 12/33] stupid mistake... let's not talk about this. --- lib/apiaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/apiaction.php b/lib/apiaction.php index f7b4ef473e..9bfca3b66e 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -290,7 +290,7 @@ class ApiAction extends Action foreach ($attachments as $attachment) { $enclosure_o=$attachment->getEnclosure(); - if ($attachment_enclosure) { + if ($enclosure_o) { $enclosure = array(); $enclosure['url'] = $enclosure_o->url; $enclosure['mimetype'] = $enclosure_o->mimetype; From ca86a4efb8c533dd709f1574d5e9e7e0ac0c4787 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 2 Mar 2010 16:49:29 -0800 Subject: [PATCH 13/33] - Have Twitter bridge check for a global key and secret if it can't find one in the local config - Refuse to work at all if the consumer key and secret aren't set --- plugins/TwitterBridge/README | 17 +++- plugins/TwitterBridge/TwitterBridgePlugin.php | 98 +++++++++++++------ plugins/TwitterBridge/twitteroauthclient.php | 21 +++- 3 files changed, 101 insertions(+), 35 deletions(-) diff --git a/plugins/TwitterBridge/README b/plugins/TwitterBridge/README index 72278b32e6..5117cf69ac 100644 --- a/plugins/TwitterBridge/README +++ b/plugins/TwitterBridge/README @@ -20,7 +20,7 @@ on Twitter (http://twitter.com/apps). During the application registration process your application will be assigned a "consumer" key and secret, which the plugin will use to make OAuth requests to Twitter. You can either pass the consumer key and secret in when you enable the -plugin, or set it using the Twitter administration panel. +plugin, or set it using the Twitter administration panel**. When registering your application with Twitter set the type to "Browser" and your Callback URL to: @@ -42,11 +42,26 @@ To enable the plugin, add the following to your config.php: ) ); +or just: + + addPlugin('TwitterBridge'); + +if you want to set the consumer key and secret from the Twitter bridge +administration panel. (The Twitter bridge wont work at all +unless you configure it with a consumer key and secret.) + * Note: The plugin will still push notices to Twitter for users who have previously set up the Twitter bridge using their Twitter name and password under an older version of StatusNet, but all new Twitter bridge connections will use OAuth. +** For multi-site setups you can also set a global consumer key and and + secret. The Twitter bridge will fall back on the global key pair if + it can't find a local pair, e.g.: + + $config['twitter']['global_consumer_key'] = 'YOUR_CONSUMER_KEY' + $config['twitter']['global_consumer_secret'] = 'YOUR_CONSUMER_SECRET' + Administration panel -------------------- diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index 6ce69d5e2b..bc702e745b 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -79,6 +79,30 @@ class TwitterBridgePlugin extends Plugin } } + /** + * Check to see if there is a consumer key and secret defined + * for Twitter integration. + * + * @return boolean result + */ + + static function hasKeys() + { + $key = common_config('twitter', 'consumer_key'); + $secret = common_config('twitter', 'consumer_secret'); + + if (empty($key) && empty($secret)) { + $key = common_config('twitter', 'global_consumer_key'); + $secret = common_config('twitter', 'global_consumer_secret'); + } + + if (!empty($key) && !empty($secret)) { + return true; + } + + return false; + } + /** * Add Twitter-related paths to the router table * @@ -91,14 +115,22 @@ class TwitterBridgePlugin extends Plugin function onRouterInitialized($m) { - $m->connect( - 'twitter/authorization', - array('action' => 'twitterauthorization') - ); - $m->connect('settings/twitter', array('action' => 'twittersettings')); - - if (common_config('twitter', 'signin')) { - $m->connect('main/twitterlogin', array('action' => 'twitterlogin')); + if (self::hasKeys()) { + $m->connect( + 'twitter/authorization', + array('action' => 'twitterauthorization') + ); + $m->connect( + 'settings/twitter', array( + 'action' => 'twittersettings' + ) + ); + if (common_config('twitter', 'signin')) { + $m->connect( + 'main/twitterlogin', + array('action' => 'twitterlogin') + ); + } } $m->connect('admin/twitter', array('action' => 'twitteradminpanel')); @@ -117,7 +149,7 @@ class TwitterBridgePlugin extends Plugin { $action_name = $action->trimmed('action'); - if (common_config('twitter', 'signin')) { + if (self::hasKeys() && common_config('twitter', 'signin')) { $action->menuItem( common_local_url('twitterlogin'), _m('Twitter'), @@ -138,15 +170,16 @@ class TwitterBridgePlugin extends Plugin */ function onEndConnectSettingsNav(&$action) { - $action_name = $action->trimmed('action'); - - $action->menuItem( - common_local_url('twittersettings'), - _m('Twitter'), - _m('Twitter integration options'), - $action_name === 'twittersettings' - ); + if (self::hasKeys()) { + $action_name = $action->trimmed('action'); + $action->menuItem( + common_local_url('twittersettings'), + _m('Twitter'), + _m('Twitter integration options'), + $action_name === 'twittersettings' + ); + } return true; } @@ -188,12 +221,12 @@ class TwitterBridgePlugin extends Plugin */ function onStartEnqueueNotice($notice, &$transports) { - // Avoid a possible loop - - if ($notice->source != 'twitter') { - array_push($transports, 'twitter'); + if (self::hasKeys()) { + // Avoid a possible loop + if ($notice->source != 'twitter') { + array_push($transports, 'twitter'); + } } - return true; } @@ -206,18 +239,19 @@ class TwitterBridgePlugin extends Plugin */ function onGetValidDaemons($daemons) { - array_push( - $daemons, - INSTALLDIR - . '/plugins/TwitterBridge/daemons/synctwitterfriends.php' - ); - - if (common_config('twitterimport', 'enabled')) { + if (self::hasKeys()) { array_push( $daemons, INSTALLDIR - . '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php' + . '/plugins/TwitterBridge/daemons/synctwitterfriends.php' ); + if (common_config('twitterimport', 'enabled')) { + array_push( + $daemons, + INSTALLDIR + . '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php' + ); + } } return true; @@ -232,7 +266,9 @@ class TwitterBridgePlugin extends Plugin */ function onEndInitializeQueueManager($manager) { - $manager->connect('twitter', 'TwitterQueueHandler'); + if (self::hasKeys()) { + $manager->connect('twitter', 'TwitterQueueHandler'); + } return true; } diff --git a/plugins/TwitterBridge/twitteroauthclient.php b/plugins/TwitterBridge/twitteroauthclient.php index ba45b533dc..93f6aadd1e 100644 --- a/plugins/TwitterBridge/twitteroauthclient.php +++ b/plugins/TwitterBridge/twitteroauthclient.php @@ -22,7 +22,7 @@ * @category Integration * @package StatusNet * @author Zach Copley - * @copyright 2009 StatusNet, Inc. + * @copyright 2009-2010 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ @@ -61,8 +61,23 @@ class TwitterOAuthClient extends OAuthClient $consumer_key = common_config('twitter', 'consumer_key'); $consumer_secret = common_config('twitter', 'consumer_secret'); - parent::__construct($consumer_key, $consumer_secret, - $oauth_token, $oauth_token_secret); + if (empty($consumer_key) && empty($consumer_secret)) { + $consumer_key = common_config( + 'twitter', + 'global_consumer_key' + ); + $consumer_secret = common_config( + 'twitter', + 'global_consumer_secret' + ); + } + + parent::__construct( + $consumer_key, + $consumer_secret, + $oauth_token, + $oauth_token_secret + ); } // XXX: the following two functions are to support the horrible hack From 9342e6f818fb35bd7f64412e9765205b5b0af849 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 2 Mar 2010 16:53:37 -0800 Subject: [PATCH 14/33] Remove double word from Twitter bridge README --- plugins/TwitterBridge/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/TwitterBridge/README b/plugins/TwitterBridge/README index 5117cf69ac..d0d34b7ef2 100644 --- a/plugins/TwitterBridge/README +++ b/plugins/TwitterBridge/README @@ -55,7 +55,7 @@ unless you configure it with a consumer key and secret.) password under an older version of StatusNet, but all new Twitter bridge connections will use OAuth. -** For multi-site setups you can also set a global consumer key and and +** For multi-site setups you can also set a global consumer key and secret. The Twitter bridge will fall back on the global key pair if it can't find a local pair, e.g.: From ecccb344e0bb5427ed8a3a82fdf2512da67184b6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 3 Mar 2010 01:49:14 +0000 Subject: [PATCH 15/33] Show global key and secret, if defined, in Twitter bridge admin panel --- plugins/TwitterBridge/TwitterBridgePlugin.php | 16 +++---- plugins/TwitterBridge/twitteradminpanel.php | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index bc702e745b..1a0a69682a 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -88,15 +88,15 @@ class TwitterBridgePlugin extends Plugin static function hasKeys() { - $key = common_config('twitter', 'consumer_key'); - $secret = common_config('twitter', 'consumer_secret'); + $ckey = common_config('twitter', 'consumer_key'); + $csecret = common_config('twitter', 'consumer_secret'); - if (empty($key) && empty($secret)) { - $key = common_config('twitter', 'global_consumer_key'); - $secret = common_config('twitter', 'global_consumer_secret'); + if (empty($ckey) && empty($csecret)) { + $ckey = common_config('twitter', 'global_consumer_key'); + $csecret = common_config('twitter', 'global_consumer_secret'); } - if (!empty($key) && !empty($secret)) { + if (!empty($ckey) && !empty($csecret)) { return true; } @@ -115,6 +115,8 @@ class TwitterBridgePlugin extends Plugin function onRouterInitialized($m) { + $m->connect('admin/twitter', array('action' => 'twitteradminpanel')); + if (self::hasKeys()) { $m->connect( 'twitter/authorization', @@ -133,8 +135,6 @@ class TwitterBridgePlugin extends Plugin } } - $m->connect('admin/twitter', array('action' => 'twitteradminpanel')); - return true; } diff --git a/plugins/TwitterBridge/twitteradminpanel.php b/plugins/TwitterBridge/twitteradminpanel.php index b22e6d99fe..0ed53bc05b 100644 --- a/plugins/TwitterBridge/twitteradminpanel.php +++ b/plugins/TwitterBridge/twitteradminpanel.php @@ -225,6 +225,49 @@ class TwitterAdminPanelForm extends AdminForm ); $this->unli(); + $globalConsumerKey = common_config('twitter', 'global_consumer_key'); + $globalConsumerSec = common_config('twitter', 'global_consumer_secret'); + + if (!empty($globalConsumerKey)) { + $this->li(); + $this->out->element( + 'label', + array('for' => 'global_consumer_key'), + '' + ); + $this->out->element( + 'input', + array( + 'name' => 'global_consumer_key', + 'type' => 'text', + 'id' => 'global_consumer_key', + 'value' => $globalConsumerKey, + 'disabled' => 'true' + ) + ); + $this->out->element('p', 'form_guide', _('Global consumer key')); + $this->unli(); + + $this->li(); + $this->out->element( + 'label', + array('for' => 'global_consumer_secret'), + '' + ); + $this->out->element( + 'input', + array( + 'name' => 'global_consumer_secret', + 'type' => 'text', + 'id' => 'global_consumer_secret', + 'value' => $globalConsumerSec, + 'disabled' => 'true' + ) + ); + $this->out->element('p', 'form_guide', _('Global consumer secret')); + $this->unli(); + } + $this->li(); $this->input( 'source', From 4aa516db454f56c5f6307b17503b6c524bd918ae Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 2 Mar 2010 18:27:37 -0800 Subject: [PATCH 16/33] Make Facebook plugin look for API key and secret before doing anything --- plugins/Facebook/FacebookPlugin.php | 161 +++++++++++++++++----------- 1 file changed, 99 insertions(+), 62 deletions(-) diff --git a/plugins/Facebook/FacebookPlugin.php b/plugins/Facebook/FacebookPlugin.php index 014d0d1970..90ed7351f3 100644 --- a/plugins/Facebook/FacebookPlugin.php +++ b/plugins/Facebook/FacebookPlugin.php @@ -79,6 +79,25 @@ class FacebookPlugin extends Plugin } } + /** + * Check to see if there is an API key and secret defined + * for Facebook integration. + * + * @return boolean result + */ + + static function hasKeys() + { + $apiKey = common_config('facebook', 'apikey'); + $apiSecret = common_config('facebook', 'secret'); + + if (!empty($apiKey) && !empty($apiSecret)) { + return true; + } + + return false; + } + /** * Add Facebook app actions to the router table * @@ -91,23 +110,26 @@ class FacebookPlugin extends Plugin function onStartInitializeRouter($m) { - - // Facebook App stuff - - $m->connect('facebook/app', array('action' => 'facebookhome')); - $m->connect('facebook/app/index.php', array('action' => 'facebookhome')); - $m->connect('facebook/app/settings.php', - array('action' => 'facebooksettings')); - $m->connect('facebook/app/invite.php', array('action' => 'facebookinvite')); - $m->connect('facebook/app/remove', array('action' => 'facebookremove')); $m->connect('admin/facebook', array('action' => 'facebookadminpanel')); - // Facebook Connect stuff + if (self::hasKeys()) { - $m->connect('main/facebookconnect', array('action' => 'FBConnectAuth')); - $m->connect('main/facebooklogin', array('action' => 'FBConnectLogin')); - $m->connect('settings/facebook', array('action' => 'FBConnectSettings')); - $m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver')); + // Facebook App stuff + + $m->connect('facebook/app', array('action' => 'facebookhome')); + $m->connect('facebook/app/index.php', array('action' => 'facebookhome')); + $m->connect('facebook/app/settings.php', + array('action' => 'facebooksettings')); + $m->connect('facebook/app/invite.php', array('action' => 'facebookinvite')); + $m->connect('facebook/app/remove', array('action' => 'facebookremove')); + + // Facebook Connect stuff + + $m->connect('main/facebookconnect', array('action' => 'FBConnectAuth')); + $m->connect('main/facebooklogin', array('action' => 'FBConnectLogin')); + $m->connect('settings/facebook', array('action' => 'FBConnectSettings')); + $m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver')); + } return true; } @@ -338,6 +360,9 @@ class FacebookPlugin extends Plugin function reqFbScripts($action) { + if (!self::hasKeys()) { + return false; + } // If you're logged in w/FB Connect, you always need the FB stuff @@ -410,42 +435,45 @@ class FacebookPlugin extends Plugin function onStartPrimaryNav($action) { - $user = common_current_user(); + if (self::hasKeys()) { - $connect = 'FBConnectSettings'; - if (common_config('xmpp', 'enabled')) { - $connect = 'imsettings'; - } else if (common_config('sms', 'enabled')) { - $connect = 'smssettings'; - } + $user = common_current_user(); - if (!empty($user)) { + $connect = 'FBConnectSettings'; + if (common_config('xmpp', 'enabled')) { + $connect = 'imsettings'; + } else if (common_config('sms', 'enabled')) { + $connect = 'smssettings'; + } - $fbuid = $this->loggedIn(); + if (!empty($user)) { - if (!empty($fbuid)) { + $fbuid = $this->loggedIn(); - /* Default FB silhouette pic for FB users who haven't - uploaded a profile pic yet. */ + if (!empty($fbuid)) { - $silhouetteUrl = - 'http://static.ak.fbcdn.net/pics/q_silhouette.gif'; + /* Default FB silhouette pic for FB users who haven't + uploaded a profile pic yet. */ - $url = $this->getProfilePicURL($fbuid); + $silhouetteUrl = + 'http://static.ak.fbcdn.net/pics/q_silhouette.gif'; - $action->elementStart('li', array('id' => 'nav_fb')); + $url = $this->getProfilePicURL($fbuid); - $action->element('img', array('id' => 'fbc_profile-pic', - 'src' => (!empty($url)) ? $url : $silhouetteUrl, - 'alt' => 'Facebook Connect User', - 'width' => '16'), ''); + $action->elementStart('li', array('id' => 'nav_fb')); - $iconurl = common_path('plugins/Facebook/fbfavicon.ico'); - $action->element('img', array('id' => 'fb_favicon', - 'src' => $iconurl)); + $action->element('img', array('id' => 'fbc_profile-pic', + 'src' => (!empty($url)) ? $url : $silhouetteUrl, + 'alt' => 'Facebook Connect User', + 'width' => '16'), ''); - $action->elementEnd('li'); + $iconurl = common_path('plugins/Facebook/fbfavicon.ico'); + $action->element('img', array('id' => 'fb_favicon', + 'src' => $iconurl)); + $action->elementEnd('li'); + + } } } @@ -462,14 +490,15 @@ class FacebookPlugin extends Plugin function onEndLoginGroupNav(&$action) { + if (self::hasKeys()) { - $action_name = $action->trimmed('action'); - - $action->menuItem(common_local_url('FBConnectLogin'), - _m('Facebook'), - _m('Login or register using Facebook'), - 'FBConnectLogin' === $action_name); + $action_name = $action->trimmed('action'); + $action->menuItem(common_local_url('FBConnectLogin'), + _m('Facebook'), + _m('Login or register using Facebook'), + 'FBConnectLogin' === $action_name); + } return true; } @@ -483,13 +512,15 @@ class FacebookPlugin extends Plugin function onEndConnectSettingsNav(&$action) { - $action_name = $action->trimmed('action'); + if (self::hasKeys()) { - $action->menuItem(common_local_url('FBConnectSettings'), - _m('Facebook'), - _m('Facebook Connect Settings'), - $action_name === 'FBConnectSettings'); + $action_name = $action->trimmed('action'); + $action->menuItem(common_local_url('FBConnectSettings'), + _m('Facebook'), + _m('Facebook Connect Settings'), + $action_name === 'FBConnectSettings'); + } return true; } @@ -503,20 +534,22 @@ class FacebookPlugin extends Plugin function onStartLogout($action) { - $action->logout(); - $fbuid = $this->loggedIn(); + if (self::hasKeys()) { - if (!empty($fbuid)) { - try { - $facebook = getFacebook(); - $facebook->expire_session(); - } catch (Exception $e) { - common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . - 'Could\'t logout of Facebook: ' . - $e->getMessage()); + $action->logout(); + $fbuid = $this->loggedIn(); + + if (!empty($fbuid)) { + try { + $facebook = getFacebook(); + $facebook->expire_session(); + } catch (Exception $e) { + common_log(LOG_WARNING, 'Facebook Connect Plugin - ' . + 'Could\'t logout of Facebook: ' . + $e->getMessage()); + } } } - return true; } @@ -562,7 +595,9 @@ class FacebookPlugin extends Plugin function onStartEnqueueNotice($notice, &$transports) { - array_push($transports, 'facebook'); + if (self::hasKeys()) { + array_push($transports, 'facebook'); + } return true; } @@ -575,7 +610,9 @@ class FacebookPlugin extends Plugin */ function onEndInitializeQueueManager($manager) { - $manager->connect('facebook', 'FacebookQueueHandler'); + if (self::hasKeys()) { + $manager->connect('facebook', 'FacebookQueueHandler'); + } return true; } From 9f861e9d895325adbb2dc7f1d540a442be2c1b2f Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 06:39:46 -0800 Subject: [PATCH 17/33] Fix on sitenotice admin panel save --- actions/sitenoticeadminpanel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/sitenoticeadminpanel.php b/actions/sitenoticeadminpanel.php index 613a2e96be..3931aa9825 100644 --- a/actions/sitenoticeadminpanel.php +++ b/actions/sitenoticeadminpanel.php @@ -99,7 +99,7 @@ class SitenoticeadminpanelAction extends AdminPanelAction $result = Config::save('site', 'notice', $siteNotice); - if (!result) { + if (!$result) { $this->ServerError(_("Unable to save site notice.")); } } From 8b3febab5539a3c08da15c78578650ffca41f75e Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 07:45:26 -0800 Subject: [PATCH 18/33] Installer tweaks: maintain form values when redisplaying form after error, add pass confirmation and optional email forms for administrator. Caveat: fancy URLs value isn't currently maintained; JS needs updating to not overwrite the value or we should kill it entirely. --- install.php | 85 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/install.php b/install.php index 41024c901f..51c86683a0 100644 --- a/install.php +++ b/install.php @@ -435,15 +435,39 @@ E_O_T; E_O_T; } +/** + * Helper class for building form + */ +class Posted { + function value($name) + { + if (isset($_POST[$name])) { + return htmlspecialchars(strval($_POST[$name])); + } else { + return ''; + } + } +} + function showForm() { global $dbModules; + $post = new Posted(); $dbRadios = ''; - $checked = 'checked="checked" '; // Check the first one which exists + if (isset($_POST['dbtype'])) { + $dbtype = $_POST['dbtype']; + } else { + $dbtype = null; + } foreach ($dbModules as $type => $info) { if (checkExtension($info['check_module'])) { + if ($dbtype == null || $dbtype == $type) { + $checked = 'checked="checked" '; + $dbtype = $type; // if we didn't have one checked, hit the first + } else { + $checked = ''; + } $dbRadios .= " $info[name]
\n"; - $checked = ''; } } echo<<
  • - +

    The name of your site

  • @@ -475,7 +499,7 @@ function showForm()
  • - +

    Database hostname

  • @@ -487,29 +511,38 @@ function showForm()
  • - +

    Database name

  • - - + +

    Database username

  • - - + +

    Database password (optional)

  • - +

    Nickname for the initial StatusNet user (administrator)

  • - - + +

    Password for the initial StatusNet user (administrator)

  • +
  • + + +
  • +
  • + + +

    Optional email address for the initial StatusNet user (administrator)

    +
  • @@ -528,13 +561,15 @@ function handlePost() $host = $_POST['host']; $dbtype = $_POST['dbtype']; $database = $_POST['database']; - $username = $_POST['username']; - $password = $_POST['password']; + $username = $_POST['dbusername']; + $password = $_POST['dbpassword']; $sitename = $_POST['sitename']; $fancy = !empty($_POST['fancy']); $adminNick = $_POST['admin_nickname']; $adminPass = $_POST['admin_password']; + $adminPass2 = $_POST['admin_password2']; + $adminEmail = $_POST['admin_email']; $server = $_SERVER['HTTP_HOST']; $path = substr(dirname($_SERVER['PHP_SELF']), 1); @@ -576,6 +611,11 @@ STR; updateStatus("No initial StatusNet user password specified.", true); $fail = true; } + + if ($adminPass != $adminPass2) { + updateStatus("Administrator passwords do not match. Did you mistype?", true); + $fail = true; + } if ($fail) { showForm(); @@ -600,7 +640,7 @@ STR; } // Okay, cross fingers and try to register an initial user - if (registerInitialUser($adminNick, $adminPass)) { + if (registerInitialUser($adminNick, $adminPass, $adminEmail)) { updateStatus( "An initial user with the administrator role has been created." ); @@ -797,19 +837,20 @@ function runDbScript($filename, $conn, $type = 'mysqli') return true; } -function registerInitialUser($nickname, $password) +function registerInitialUser($nickname, $password, $email) { define('STATUSNET', true); define('LACONICA', true); // compatibility require_once INSTALLDIR . '/lib/common.php'; - $user = User::register( - array('nickname' => $nickname, - 'password' => $password, - 'fullname' => $nickname - ) - ); + $data = array('nickname' => $nickname, + 'password' => $password, + 'fullname' => $nickname); + if ($email) { + $data['email'] = $email; + } + $user = User::register($data); if (empty($user)) { return false; From 0cf0a684ce32a4c79cf05d108d6da38052be5bd8 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 4 Mar 2010 11:32:30 -0500 Subject: [PATCH 19/33] Updated SN install UI. Using separate fieldsets --- install.php | 136 +++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/install.php b/install.php index 51c86683a0..47a09b67c7 100644 --- a/install.php +++ b/install.php @@ -474,76 +474,80 @@ function showForm() -
    -
    Page notice
    -
    -
    -

    Enter your database connection information below to initialize the database.

    -
    -
    -
    - Connection settings -
      -
    • - - -

      The name of your site

      -
    • -
    • - - enable
      - disable
      -

      Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.

      -
    • -
    • - - -

      Database hostname

      -
    • -
    • +
      + Site settings +
        +
      • + + +

        The name of your site

        +
      • +
      • + + enable
        + disable
        +

        Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.

        +
      • +
      • + + +

        Database hostname

        +
      • +
      +
      - - $dbRadios -

      Database type

      -
    • +
      + Database settings +
        +
      • + + $dbRadios +

        Database type

        +
      • +
      • + + +

        Database name

        +
      • +
      • + + +

        Database username

        +
      • +
      • + + +

        Database password (optional)

        +
      • +
      +
      -
    • - - -

      Database name

      -
    • -
    • - - -

      Database username

      -
    • -
    • - - -

      Database password (optional)

      -
    • -
    • - - -

      Nickname for the initial StatusNet user (administrator)

      -
    • -
    • - - -

      Password for the initial StatusNet user (administrator)

      -
    • -
    • - - -
    • -
    • - - -

      Optional email address for the initial StatusNet user (administrator)

      -
    • -
    +
    + Administrator settings +
      +
    • + + +

      Nickname for the initial StatusNet user (administrator)

      +
    • +
    • + + +

      Password for the initial StatusNet user (administrator)

      +
    • +
    • + + +
    • +
    • + + +

      Optional email address for the initial StatusNet user (administrator)

      +
    • +
    +
    From 67e4c5d43be2228169f3d08feafbb6a980d4a40a Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 08:32:45 -0800 Subject: [PATCH 20/33] Added oauth_appication tables to 08to09.sql Conflicts: db/08to09.sql --- db/08to09.sql | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/db/08to09.sql b/db/08to09.sql index f305721541..3ebb141bf6 100644 --- a/db/08to09.sql +++ b/db/08to09.sql @@ -110,8 +110,36 @@ insert into queue_item_new (frame,transport,created,claimed) alter table queue_item rename to queue_item_old; alter table queue_item_new rename to queue_item; +create table oauth_application ( + id integer auto_increment primary key comment 'unique identifier', + owner integer not null comment 'owner of the application' references profile (id), + consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key), + name varchar(255) not null comment 'name of the application', + description varchar(255) comment 'description of the application', + icon varchar(255) not null comment 'application icon', + source_url varchar(255) comment 'application homepage - used for source link', + organization varchar(255) comment 'name of the organization running the application', + homepage varchar(255) comment 'homepage for the organization', + callback_url varchar(255) comment 'url to redirect to after authentication', + type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop', + access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified' +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table oauth_application_user ( + profile_id integer not null comment 'user of the application' references profile (id), + application_id integer not null comment 'id of the application' references oauth_application (id), + access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked', + token varchar(255) comment 'request or access token', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified', + constraint primary key (profile_id, application_id) +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + alter table file_to_post add index post_id_idx (post_id); alter table group_inbox add index group_inbox_notice_id_idx (notice_id); + From 3d2bf5ce20d494c1d9e890e1d666008ef66e5703 Mon Sep 17 00:00:00 2001 From: Ciaran Gultnieks Date: Mon, 1 Feb 2010 21:05:50 +0000 Subject: [PATCH 21/33] Create new field in consumer table in 08to09.sql --- db/08to09.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/08to09.sql b/db/08to09.sql index 3ebb141bf6..05958f6123 100644 --- a/db/08to09.sql +++ b/db/08to09.sql @@ -110,6 +110,9 @@ insert into queue_item_new (frame,transport,created,claimed) alter table queue_item rename to queue_item_old; alter table queue_item_new rename to queue_item; +alter table consumer + add column consumer_secret varchar(255) not null comment 'secret value'; + create table oauth_application ( id integer auto_increment primary key comment 'unique identifier', owner integer not null comment 'owner of the application' references profile (id), From 1831506885ad31c14eb1c4c87274c299fbf39957 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 4 Mar 2010 11:35:18 -0500 Subject: [PATCH 22/33] Moved database hostname in install to db fieldset --- install.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/install.php b/install.php index 47a09b67c7..32b0447c88 100644 --- a/install.php +++ b/install.php @@ -490,17 +490,17 @@ function showForm() disable

    Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.

    -
  • - - -

    Database hostname

    -
  • Database settings
      +
    • + + +

      Database hostname

      +
    • $dbRadios From fd4eefe6b4a2a64b21e1f924afe1d8d749cd89e0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 4 Mar 2010 11:43:31 -0500 Subject: [PATCH 23/33] OStatus enabled by default --- lib/default.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/default.php b/lib/default.php index 8e99a0e1c3..bdd78d4d86 100644 --- a/lib/default.php +++ b/lib/default.php @@ -280,6 +280,7 @@ $default = 'TightUrl' => array('shortenerName' => '2tu.us', 'freeService' => true,'serviceUrl'=>'http://2tu.us/?save=y&url=%1$s'), 'Geonames' => null, 'Mapstraction' => null, + 'OStatus' => null, 'WikiHashtags' => null, 'OpenID' => null), ), From af04973e9e49c7867a26357ed85d64f04d6bb263 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 08:49:04 -0800 Subject: [PATCH 24/33] Roll up some missing items from 08to09.sql; now hits all changed tables/columns/keys in core. Added partial data conversions: user_groups -> local_user: ids, names filled out; mainpage, uri left null notice -> conversation: stub entry added to push the autoincrement past existing notice items --- db/08to09.sql | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/db/08to09.sql b/db/08to09.sql index 05958f6123..ba6f382005 100644 --- a/db/08to09.sql +++ b/db/08to09.sql @@ -111,7 +111,11 @@ alter table queue_item rename to queue_item_old; alter table queue_item_new rename to queue_item; alter table consumer - add column consumer_secret varchar(255) not null comment 'secret value'; + add consumer_secret varchar(255) not null comment 'secret value'; + +alter table token + add verifier varchar(255) comment 'verifier string for OAuth 1.0a', + add verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a'; create table oauth_application ( id integer auto_increment primary key comment 'unique identifier', @@ -140,6 +144,44 @@ create table oauth_application_user ( constraint primary key (profile_id, application_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; +create table inbox ( + + user_id integer not null comment 'user receiving the notice' references user (id), + notice_ids blob comment 'packed list of notice ids', + + constraint primary key (user_id) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table conversation ( + id integer auto_increment primary key comment 'unique identifier', + uri varchar(225) unique comment 'URI of the conversation', + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified' +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +-- stub entry to push the autoincrement past existing notice ids +insert into conversation (id,created) + select max(id)+1, now() from notice; + +alter table user_group + add uri varchar(255) unique key comment 'universal identifier', + add mainpage varchar(255) comment 'page for group info to link to', + drop index nickname; + +create table local_group ( + + group_id integer primary key comment 'group represented' references user_group (id), + nickname varchar(64) unique key comment 'group represented', + + created datetime not null comment 'date this record was created', + modified timestamp comment 'date this record was modified' + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +insert into local_group (group_id, nickname, created) + select id, nickname, created from user_group; + alter table file_to_post add index post_id_idx (post_id); From 02f49193d5eaee108899b38678334f775dee596f Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 4 Mar 2010 11:48:51 -0500 Subject: [PATCH 25/33] adding checkschema to setup script --- scripts/setup_status_network.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh index 89d15415f9..4ebb696c71 100755 --- a/scripts/setup_status_network.sh +++ b/scripts/setup_status_network.sh @@ -54,6 +54,8 @@ for top in $AVATARBASE $FILEBASE $BACKGROUNDBASE; do chmod a+w $top/$nickname done +php $PHPBASE/scripts/checkschema.php -s"$server" + php $PHPBASE/scripts/registeruser.php \ -s"$server" \ -n"$nickname" \ From 0ddd1ef191389ed38988091d098463b19aa86f68 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 08:55:36 -0800 Subject: [PATCH 26/33] Ignore API 'since' silently as Twitter does instead of throwing a 403 error. Getting extra results is less disruptive than total failure. Threw in an X-StatusNet-Warning header on the off chance some API client developer notices it. :) --- lib/apiaction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/apiaction.php b/lib/apiaction.php index eef0ba637d..e4a1df3d19 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -86,7 +86,7 @@ class ApiAction extends Action $this->since_id = (int)$this->arg('since_id', 0); if ($this->arg('since')) { - $this->clientError(_("since parameter is disabled for performance; use since_id"), 403); + header('X-StatusNet-Warning: since parameter is disabled; use since_id'); } return true; From 45f11d9637c90c0bc7348c6bc5707516ea457d6c Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 4 Mar 2010 12:02:01 -0500 Subject: [PATCH 27/33] adding plugin version to OStatus --- plugins/OStatus/OStatusPlugin.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index ad4f613891..bdcaae366b 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -836,4 +836,17 @@ class OStatusPlugin extends Plugin return true; } + + function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'OStatus', + 'version' => STATUSNET_VERSION, + 'author' => 'Evan Prodromou, James Walker, Brion Vibber, Zach Copley', + 'homepage' => 'http://status.net/wiki/Plugin:OStatus', + 'rawdescription' => + _m('Follow people across social networks that implement '. + 'OStatus.')); + + return true; + } } From 8f1762cb9580c3f444ff5fd53bcefcbab6b54980 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 09:24:47 -0800 Subject: [PATCH 28/33] OStatus: fix for remote group join via non-logged-in 'join' button. Bad lookup was sending us to the first group instead of the selected group. --- plugins/OStatus/actions/ostatusinit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/OStatus/actions/ostatusinit.php b/plugins/OStatus/actions/ostatusinit.php index 1e45025b09..22aea9f709 100644 --- a/plugins/OStatus/actions/ostatusinit.php +++ b/plugins/OStatus/actions/ostatusinit.php @@ -186,7 +186,7 @@ class OStatusInitAction extends Action $this->clientError("No such user."); } } else if ($this->group) { - $group = Local_group::staticGet('id', $this->group); + $group = Local_group::staticGet('nickname', $this->group); if ($group) { return common_local_url('groupbyid', array('id' => $group->group_id)); } else { From a6a056026d645154e7172b47a046d7ba91d74d65 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 17:33:56 +0000 Subject: [PATCH 29/33] Dropping the earlier PubSubHubbub plugin; OStatus plugin is taking that portion over (with both internal and external hub options for user and group feeds). Todo: add support for other feeds to OStatus PuSH hub implementation. --- plugins/PubSubHubBub/PubSubHubBubPlugin.php | 285 -------------------- plugins/PubSubHubBub/publisher.php | 86 ------ 2 files changed, 371 deletions(-) delete mode 100644 plugins/PubSubHubBub/PubSubHubBubPlugin.php delete mode 100644 plugins/PubSubHubBub/publisher.php diff --git a/plugins/PubSubHubBub/PubSubHubBubPlugin.php b/plugins/PubSubHubBub/PubSubHubBubPlugin.php deleted file mode 100644 index a880dc8666..0000000000 --- a/plugins/PubSubHubBub/PubSubHubBubPlugin.php +++ /dev/null @@ -1,285 +0,0 @@ -. - * - * @category Plugin - * @package StatusNet - * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -define('DEFAULT_HUB', 'http://pubsubhubbub.appspot.com'); - -require_once INSTALLDIR.'/plugins/PubSubHubBub/publisher.php'; - -/** - * Plugin to provide publisher side of PubSubHubBub (PuSH) - * relationship. - * - * PuSH is a real-time or near-real-time protocol for Atom - * and RSS feeds. More information here: - * - * http://code.google.com/p/pubsubhubbub/ - * - * To enable, add the following line to your config.php: - * - * addPlugin('PubSubHubBub'); - * - * This will use the Google default hub. If you'd like to use - * another, try: - * - * addPlugin('PubSubHubBub', - * array('hub' => 'http://yourhub.example.net/')); - * - * @category Plugin - * @package StatusNet - * @author Craig Andrews - * @copyright 2009 Craig Andrews http://candrews.integralblue.com - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 - * @link http://status.net/ - */ - -class PubSubHubBubPlugin extends Plugin -{ - /** - * URL of the hub to advertise and publish to. - */ - - public $hub = DEFAULT_HUB; - - /** - * Default constructor. - */ - - function __construct() - { - parent::__construct(); - } - - /** - * Check if plugin should be active; may be mass-enabled. - * @return boolean - */ - - function enabled() - { - if (common_config('site', 'private')) { - // PuSH relies on public feeds - return false; - } - // @fixme check for being on a private network? - return true; - } - - /** - * Hooks the StartApiAtom event - * - * Adds the necessary bits to advertise PubSubHubBub - * for the Atom feed. - * - * @param Action $action The API action being shown. - * - * @return boolean hook value - */ - - function onStartApiAtom($action) - { - if ($this->enabled()) { - $action->element('link', array('rel' => 'hub', 'href' => $this->hub), null); - } - return true; - } - - /** - * Hooks the StartApiRss event - * - * Adds the necessary bits to advertise PubSubHubBub - * for the RSS 2.0 feeds. - * - * @param Action $action The API action being shown. - * - * @return boolean hook value - */ - - function onStartApiRss($action) - { - if ($this->enabled()) { - $action->element('atom:link', array('rel' => 'hub', - 'href' => $this->hub), - null); - } - return true; - } - - /** - * Hook for a queued notice. - * - * When a notice has been queued, will ping the - * PuSH hub for each Atom and RSS feed in which - * the notice appears. - * - * @param Notice $notice The notice that's been queued - * - * @return boolean hook value - */ - - function onHandleQueuedNotice($notice) - { - if (!$this->enabled()) { - return false; - } - $publisher = new Publisher($this->hub); - - $feeds = array(); - - //public timeline feeds - $feeds[] = common_local_url('ApiTimelinePublic', array('format' => 'rss')); - $feeds[] = common_local_url('ApiTimelinePublic', array('format' => 'atom')); - - //author's own feeds - $user = User::staticGet('id', $notice->profile_id); - - $feeds[] = common_local_url('ApiTimelineUser', - array('id' => $user->nickname, - 'format' => 'rss')); - $feeds[] = common_local_url('ApiTimelineUser', - array('id' => $user->nickname, - 'format' => 'atom')); - - //tag feeds - $tag = new Notice_tag(); - - $tag->notice_id = $notice->id; - if ($tag->find()) { - while ($tag->fetch()) { - $feeds[] = common_local_url('ApiTimelineTag', - array('tag' => $tag->tag, - 'format' => 'rss')); - $feeds[] = common_local_url('ApiTimelineTag', - array('tag' => $tag->tag, - 'format' => 'atom')); - } - } - - //group feeds - $group_inbox = new Group_inbox(); - - $group_inbox->notice_id = $notice->id; - if ($group_inbox->find()) { - while ($group_inbox->fetch()) { - $group = User_group::staticGet('id', $group_inbox->group_id); - - $feeds[] = common_local_url('ApiTimelineGroup', - array('id' => $group->nickname, - 'format' => 'rss')); - $feeds[] = common_local_url('ApiTimelineGroup', - array('id' => $group->nickname, - 'format' => 'atom')); - } - } - - //feed of each user that subscribes to the notice's author - - $ni = $notice->whoGets(); - - foreach (array_keys($ni) as $user_id) { - $user = User::staticGet('id', $user_id); - if (empty($user)) { - continue; - } - $feeds[] = common_local_url('ApiTimelineFriends', - array('id' => $user->nickname, - 'format' => 'rss')); - $feeds[] = common_local_url('ApiTimelineFriends', - array('id' => $user->nickname, - 'format' => 'atom')); - } - - $replies = $notice->getReplies(); - - //feed of user replied to - foreach ($replies as $recipient) { - $user = User::staticGet('id', $recipient); - if (!empty($user)) { - $feeds[] = common_local_url('ApiTimelineMentions', - array('id' => $user->nickname, - 'format' => 'rss')); - $feeds[] = common_local_url('ApiTimelineMentions', - array('id' => $user->nickname, - 'format' => 'atom')); - } - } - $feeds = array_unique($feeds); - - ob_start(); - $ok = $publisher->publish_update($feeds); - $push_last_response = ob_get_clean(); - - if (!$ok) { - common_log(LOG_WARNING, - 'Failure publishing ' . count($feeds) . ' feeds to hub at '. - $this->hub.': '.$push_last_response); - } else { - common_log(LOG_INFO, - 'Published ' . count($feeds) . ' feeds to hub at '. - $this->hub.': '.$push_last_response); - } - - return true; - } - - /** - * Provide version information - * - * Adds this plugin's version data to the global - * version array, for e.g. displaying on the version page. - * - * @param array &$versions array of array of versions - * - * @return boolean hook value - */ - - function onPluginVersion(&$versions) - { - $about = _m('The PubSubHubBub plugin pushes RSS/Atom updates '. - 'to a PubSubHubBub hub.'); - if (!$this->enabled()) { - $about = '' . $about . ' ' . - _m('(inactive on private site)'); - } - $versions[] = array('name' => 'PubSubHubBub', - 'version' => STATUSNET_VERSION, - 'author' => 'Craig Andrews', - 'homepage' => - 'http://status.net/wiki/Plugin:PubSubHubBub', - 'rawdescription' => - $about); - - return true; - } -} diff --git a/plugins/PubSubHubBub/publisher.php b/plugins/PubSubHubBub/publisher.php deleted file mode 100644 index f176a9b8a4..0000000000 --- a/plugins/PubSubHubBub/publisher.php +++ /dev/null @@ -1,86 +0,0 @@ -hub_url = $hub_url; - } - - // accepts either a single url or an array of urls - public function publish_update($topic_urls, $http_function = false) { - if (!isset($topic_urls)) - throw new Exception('Please specify a topic url'); - - // check that we're working with an array - if (!is_array($topic_urls)) { - $topic_urls = array($topic_urls); - } - - // set the mode to publish - $post_string = "hub.mode=publish"; - // loop through each topic url - foreach ($topic_urls as $topic_url) { - - // lightweight check that we're actually working w/ a valid url - if (!preg_match("|^https?://|i",$topic_url)) - throw new Exception('The specified topic url does not appear to be valid: '.$topic_url); - - // append the topic url parameters - $post_string .= "&hub.url=".urlencode($topic_url); - } - - // make the http post request and return true/false - // easy to over-write to use your own http function - if ($http_function) - return $http_function($this->hub_url,$post_string); - else - return $this->http_post($this->hub_url,$post_string); - } - - // returns any error message from the latest request - public function last_response() { - return $this->last_response; - } - - // default http function that uses curl to post to the hub endpoint - private function http_post($url, $post_string) { - - // add any additional curl options here - $options = array(CURLOPT_URL => $url, - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => $post_string, - CURLOPT_USERAGENT => "PubSubHubbub-Publisher-PHP/1.0"); - - $ch = curl_init(); - curl_setopt_array($ch, $options); - - $response = curl_exec($ch); - $this->last_response = $response; - $info = curl_getinfo($ch); - - curl_close($ch); - - // all good - if ($info['http_code'] == 204) - return true; - return false; - } -} - -?> \ No newline at end of file From 74dbd37e9af4dabd5c157b78dc331ccfb6d69131 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 4 Mar 2010 12:49:42 -0500 Subject: [PATCH 30/33] Bringing aside back because it is needed for Design values. Will hide from CSS instead. --- lib/adminpanelaction.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/adminpanelaction.php b/lib/adminpanelaction.php index d1aab3dfcb..d43ea76984 100644 --- a/lib/adminpanelaction.php +++ b/lib/adminpanelaction.php @@ -189,16 +189,6 @@ class AdminPanelAction extends Action $this->elementEnd('div'); } - /** - * There is no data for aside, so, we don't output - * - * @return nothing - */ - function showAside() - { - - } - /** * show human-readable instructions for the page, or * a success/failure on save. From 6b4c3e59fa8f4a2acf18ce5e9bab34656edeae00 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 4 Mar 2010 12:50:29 -0500 Subject: [PATCH 31/33] Showing a vertical navigation for admin panels. --- theme/base/css/display.css | 61 +++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/theme/base/css/display.css b/theme/base/css/display.css index 01d5dd134d..9647558327 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -345,10 +345,14 @@ list-style-type:none; float:left; text-decoration:none; padding:4px 11px; +border-radius-topleft:4px; +border-radius-topright:4px; -moz-border-radius-topleft:4px; -moz-border-radius-topright:4px; -webkit-border-top-left-radius:4px; -webkit-border-top-right-radius:4px; +border-radius-topleft:0; +border-radius-topright:0; border-width:1px; border-style:solid; border-bottom:0; @@ -359,6 +363,56 @@ float:left; width:100%; } +body[id$=adminpanel] #site_nav_local_views { +float:right; +margin-right:18.9%; + +margin-right:189px; +position:relative; +width:14.01%; + +width:141px; +z-index:9; +} +body[id$=adminpanel] #site_nav_local_views li { +width:100%; +margin-right:0; +margin-bottom:7px; +} +body[id$=adminpanel] #site_nav_local_views a { +display:block; +width:100%; +border-radius-toprleft:0; +-moz-border-radius-topleft:0; +-webkit-border-top-left-radius:0; +border-radius-topright:4px; +-moz-border-radius-topright:4px; +-webkit-border-top-right-radius:4px; +border-radius-bottomright:4px; +-moz-border-radius-bottomright:4px; +-webkit-border-bottom-right-radius:4px; +} +body[id$=adminpanel] #site_nav_local_views li.current { +box-shadow:none; +-moz-box-shadow:none; +-webkit-box-shadow:none; +} + +body[id$=adminpanel] #content { +border-radius-topleft:7px; +border-radius-topright:7px; +-moz-border-radius-topleft:7px; +-moz-border-radius-topright:7px; +-webkit-border-top-left-radius:7px; +-webkit-border-top-right-radius:7px; +border-radius-topright:0; +-moz-border-radius-topright:0; +-webkit-border-top-right-radius:0; +} +body[id$=adminpanel] #aside_primary { +display:none; +} + #site_nav_global_primary dt, #site_nav_global_secondary dt { display:none; @@ -452,13 +506,6 @@ width:100%; float:left; } -#content.admin { -width:95.5%; -} -#content.admin #content_inner { -width:66.3%; -} - #aside_primary { width:27.917%; min-height:259px; From a3cb285da8fc712caadcc65c9eab9bd98ce79414 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Thu, 4 Mar 2010 09:50:54 -0800 Subject: [PATCH 32/33] Add link to http://status.net/wiki/Getting_started on installer success screen. --- install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.php b/install.php index 32b0447c88..bb53e2b55b 100644 --- a/install.php +++ b/install.php @@ -664,7 +664,7 @@ STR; updateStatus("StatusNet has been installed at $link"); updateStatus( - "You can visit your new StatusNet site (login as '$adminNick')." + "DONE! You can visit your new StatusNet site (login as '$adminNick'). If this is your first StatusNet install, you may want to poke around our Getting Started guide." ); } From 26f78f5777144d4a04c20fedf0b03df5315b3744 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 4 Mar 2010 13:04:22 -0500 Subject: [PATCH 33/33] change changelog and version --- README | 262 ++++++++++++--------------------------------------------- 1 file changed, 55 insertions(+), 207 deletions(-) diff --git a/README b/README index 75336eb83f..caa4a2acd2 100644 --- a/README +++ b/README @@ -2,8 +2,8 @@ README ------ -StatusNet 0.9.0 ("Stand") Beta 5 -1 Feb 2010 +StatusNet 0.9.0 ("Stand") +4 Mar 2010 This is the README file for StatusNet (formerly Laconica), the Open Source microblogging platform. It includes installation instructions, @@ -14,21 +14,21 @@ for administrators. Information on using StatusNet can be found in the About ===== -StatusNet (formerly Laconica) is a Free and Open Source microblogging -platform. It helps people in a community, company or group to exchange -short (140 characters, by default) messages over the Web. Users can -choose which people to "follow" and receive only their friends' or -colleagues' status messages. It provides a similar service to sites -like Twitter, Jaiku, Yammer, and Plurk. +StatusNet is a Free and Open Source microblogging platform. It helps +people in a community, company or group to exchange short (140 +characters, by default) messages over the Web. Users can choose which +people to "follow" and receive only their friends' or colleagues' +status messages. It provides a similar service to sites like Twitter, +Google Buzz, or Yammer. With a little work, status messages can be sent to mobile phones, instant messenger programs (GTalk/Jabber), and specially-designed desktop clients that support the Twitter API. -StatusNet supports an open standard called OpenMicroBlogging - that lets users on different Web sites -or in different companies subscribe to each others' notices. It -enables a distributed social network spread all across the Web. +StatusNet supports an open standard called OStatus + that lets users in different networks follow +each other. It enables a distributed social network spread all across +the Web. StatusNet was originally developed for the Open Software Service, Identi.ca . It is shared with you in hope that you @@ -77,203 +77,51 @@ for additional terms. New this version ================ -This is a major feature release since version 0.8.2, released Nov 1 2009. -It is also a security release since 0.9.0beta4 January 27 2010. Beta -users are strongly encouraged to upgrade to deal with a security alert. - -http://status.net/wiki/Security_alert_0000002 +This is a major feature release since version 0.8.3, released Feb 1 +2010. It is the final release version of 0.9.0. Notable changes this version: -- Records of deleted notices are stored without the notice content. -- Much of the optional core featureset has been moved to plugins. -- OpenID support moved from core to a plugin. Helps test the strength of - our plugin architecture and makes it easy to disable this - functionality for e.g. intranet sites. -- Many additional hook events (see EVENTS.txt for details). -- OMB 0.1 support re-implemented using libomb. -- Re-structure database so notices, messages, bios and group - descriptions can be over 140 characters. Limit defined by - site administrator as configuration option; can be unlimited. -- Configuration data now optionally stored in the database, which - overrides any settings in config files. -- Twitter integration re-implemented as a plugin. -- Facebook integration re-implemented as a plugin. -- Role-based authorization framework. Users can have named roles, and - roles can have rights (e.g., to delete notices, change configuration - data, or ban uncooperative users). Default roles 'admin' (for - configuration) and 'moderator' (for community management) added. -- Plugin for PubSubHubBub (PuSH) support. -- Considerable code style cleanup to meet PEAR code standards. -- Made a common library for HTTP-client access which uses available - HTTP libraries where possible. -- Added statuses/home_timeline method to API. -- Hooks for plugins to handle notices offline, either by defining - their own queue handler scripts or to use a default plugin queue - handler script. -- Plugins can now modify the database schema, adding their own tables - or modifying existing ones. -- Groups API. -- Twitter API supports Web caching for some methods. -- Twitter API refactored into one-action-per-method. -- Realtime plugin supports a tear-off window. -- FOAF for groups. -- Moved all JavaScript tags to just before by default, - significantly speeding up apparent page load time. -- Added a Realtime plugin for Orbited server. -- Added a mobile plugin to give a more mobile-phone-friendly layout - when a mobile browser is detected. -- Use CSS sprites for most common icons. -- Fixes for images and buttons on Web output. -- New plugin requires that users validate their email before posting. -- New plugin UserFlag lets users flag other profiles for review. -- Considerably better i18n support. Use TranslateWiki to update - translations. -- Notices and profiles now store location information. -- New plugin, Geonames, for turning location names and lat/long pairs - into structured IDs and vice versa. Architecture reusable for other - systems. -- Better check of license compatibility between site licenses. -- Some improvements in XMPP output. -- Media upload in the API. -- Replies appear in the user's inbox. -- Improved the UI on the bookmarklet. -- StatusNet identities can be used as OpenID identities. -- Script to register a user. -- Script to make someone a group admin. -- Script to make someone a site admin or moderator. -- 'login' command. -- Pluggable authentication. -- LDAP authentication plugin. -- Script for console interaction with the site (!). -- Users don't see group posts from people they've blocked. -- Admin panel interface for changing site configuration. -- Users can be sandboxed (limited contributions) or silenced - (no contributions) by moderators. -- Many changes to make language usage more consistent. -- Sphinx search moved to a plugin. -- GeoURL plugin. -- Profile and group lists support hAtom. -- Massive refactoring of util.js. -- Mapstraction plugin to show maps on inbox and profile pages. -- Play/pause buttons for realtime notices. -- Support for geo microformat. -- Partial support for feed subscriptions, RSSCloud, PubSubHubBub. -- Support for geolocation in browser (Chrome, Firefox). -- Quit trying to negotiate HTML format. Always use text/html. - We lose, and so do Web standards. Boo. -- Better logging of request info. -- Better output for errors in Web interface. -- No longer store .mo files; these need to be generated. -- Minify plugin. -- Events to allow pluginizing logger. -- New framework for plugin localization. -- Gravatar plugin. -- Add support for "repeats" (similar to Twitter's "retweets"). -- Support for repeats in Twitter API. -- Better notification of direct messages. -- New plugin to add "powered by StatusNet" to logo. -- Returnto works for private sites. -- Localisation updates, including new Persian translation. -- CAS authentication plugin -- Get rid of DB_DataObject native cache (big memory leaker) -- setconfig.php script to set configuration variables -- Blacklist plugin, to blacklist URLs and nicknames -- Users can set flag whether they want to share location - both in notice form (for one notice) and profile settings - (any notice) -- notice inboxes moved from normalized notice_inbox table to - denormalized inbox table -- Automatic compression of Memcache -- Memory caching pluginized -- Memcache, XCache, APC and Diskcache plugins -- A script to update user locations -- cache empty query results -- A sample plugin to show best plugin practices -- CacheLog plugin to debug cache accesses -- Require users to login to view attachments on private sites -- Plugin to use Mollom spam detection service -- Plugin for RSSCloud -- Add an array of default plugins -- A version action to give credit to contributors and plugin - developers -- Daemon to read IMAP mailbox instead of using a mailbox script -- Pass session information between SSL and non-SSL server - when SSL set to 'sometimes' -- Major refactoring of queue handlers to manage very - large hosting site (like status.net) -- SubscriptionThrottle plugin to prevent subscription spamming -- Don't enqueue into plugin or SMS queues when disabled (breaks unqueuehandler if SMS queue isn't attached) -- Improve name validation checks on local File references -- fix local file include vulnerability in doc.php -- Reusing fixed selector name for 'processing' in util.js -- Removed hAtom pattern from registration page. -- restructuring of User::registerNew() lost password munging -- Add a script to clear the cache for a given key -- buggy fetch for site owner -- Added missing concat of
    • in Realtime response -- Updated XHR binded events to work better in jQuery 1.4.1. Using .live() for event delegation instead of jQuery.data() and checking to see if an element was previously binded. -- Updated jQuery Form Plugin from v2.17 to v2.36 -- Updated jQuery JavaScript Library from v1.3.2 to v1.4.1 -- move schema.type.php to typeschema.php like other files -- Add Really Simple Discovery (RSD) support -- Add a robots.txt URL to the site root -- error clearing tags for profiles from memcached -- on exceptions, stomp logs the error and reenqueues -- add lat, lon, location and remove closing tag from geocode.php -- Use passed-in lat long in geocode.php -- better handling of null responses from geonames.org -- Globalized form notice data geo values -- Using jQuery chaining in FormNoticeXHR -- Using form object instead of form_id and find(). Slightly faster and easier to read. -- removed describeTable from base class, and fixed it up in pgsql -- getTableDef() mostly working in postgres -- move the schema DDL sql off into seperate files for each db we support -- plugin to limit number of registered users -- add hooks for user registration -- live fast, die young in bash scripts -- for single-user mode, retrieve either site owner or defined nickname -- method to get the site owner -- define a constant for the 'owner' role of a site -- add simple cache getter/setter static functions to Memcached_DataObject -- Adds notice author's name to @title in Realtime response -- Hides .author from XHR response in showstream -- Hides .author from XHR response in showstream -- Fix more fatal errors in queue edge cases -- Don't attempt to resend XMPP messages that can't be broadcast due to the profile being deleted. -- Wrap each bit of distrib queue handler's saving operation in a try/catch; log exceptions but let everything else continue. -- Log exceptions from queuedaemon.php if they're not already caught -- Move sessions settings to its own panel -- Fixes for status_network db object .ini and tag setter script -- Add a script to set tags for sites -- Adjust API authentication to also check for OAuth protocol params in the HTTP Authorization header, as defined in OAuth HTTP Authorization Scheme. -- Last-chance distribution if enqueueing fails -- Manual failover for stomp queues. -- lost config in index.php made all traffic go to master -- "Revert "move RW setup above user get in index.php so remember_me works"" -- Revert "move RW setup above user get in index.php so remember_me works" -- move RW setup above user get in index.php so remember_me works -- hide most DB_DataObject errors -- always set up database_rw, regardless, so cached sessions work -- update mysqltimestamps on insert and update -- additional debugging data for Sessions -- 'Sign in with Twitter' button img -- Update to biz theme -- Remove redundant session token field from form (was already being added by base class). -- 'Sign in with Twitter' button img -- Can now set $config['queue']['stomp_persistent'] = false; to explicitly disable persistence when we queue items -- Showing processing indicator for form_repeat on submit instead of form -- Removed avatar from repeat of username (matches noticelist) -- Removed unused variable assignment for avatar URL and added missing fn -- Don't preemptively close existing DB connections for web views (needed to keep # of conns from going insane on multi-site queue daemons, so just doing for CLI) May, or may not, help with mystery session problems -- dropping the setcookie() call from common_ensure_session() since we're pretty sure it's unnecessary -- append '/' on cookie path for now (may still need some refactoring) -- set session cookie correctly -- Fix for Mapstraction plugin's zoomed map links -- debug log line for control channel sub -- Move faceboookapp.js to the Facebook plugin -- fix for fix for bad realtime JS load -- default 24-hour expiry on Memcached objects where not specified. +- Support for the new distributed status update standard OStatus + , based on PubSubHubbub, Salmon, Webfinger, + and Activity Streams. +- Support for location. Notices are (optionally) marked with lat-long + information, and can be shown on a map. +- No fixed content size. Notice size is configurable, from 1 to + unlimited number of characters. Default is still 140! +- An authorization framework, allowing different levels of users. +- A Web-based administration panel. +- A moderation system that lets site moderators sandbox, silence, + or delete uncooperative users. +- A flag system that lets users flag profiles for moderator review. +- Support for OAuth authentication in the Twitter + API. +- A pluggable authentication system. +- An authentication plugin for LDAP servers. +- Many features that were core in 0.8.x are now plugins, such + as OpenID, Twitter integration, Facebook integration +- A much-improved offline processing system +- In-browser "realtime" updates using a number of realtime + servers (Meteor, Orbited, Cometd) +- A plugin to provide an interface optimized for mobile browsers +- Support for Facebook Connect +- Support for logging in with a Twitter account +- Vastly improved translation with additional languages and + translation in plugins +- Support for all-SSL instances +- Core support for "repeats" (like Twitter's "retweets") +- Pluggable caching system, with plugins for Memcached, + APC, XCache, and a disk-based cache +- Plugin to support RSSCloud +- A framework for adding advertisements to a public site, + and plugins for Google AdSense and OpenX server + +There are also literally thousands of bugs fixed and minor features +added. A full changelog is available at http://status.net/wiki/StatusNet_0.9.0. + +Under the covers, the software has a vastly improved plugin and +extension mechanism that makes writing powerful and flexible additions +to the core functionality much easier. Prerequisites ============= @@ -806,7 +654,7 @@ management, but host it on a public server. Note that this is an experimental feature; total privacy is not guaranteed or ensured. Also, privacy is all-or-nothing for a site; you can't have some accounts or notices private, and others public. -Finally, the interaction of private sites with OpenMicroBlogging is +Finally, the interaction of private sites with OStatus is undefined. Remote users won't be able to subscribe to users on a private site, but users of the private site may be able to subscribe to users on a remote site. (Or not... it's not well tested.) The