summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/MemcachePlugin.php33
-rw-r--r--plugins/OStatus/OStatusPlugin.php58
-rw-r--r--plugins/OStatus/actions/ostatusinit.php28
-rw-r--r--plugins/OStatus/actions/ostatussub.php4
-rw-r--r--plugins/OStatus/actions/salmon.php2
-rw-r--r--plugins/OStatus/classes/Ostatus_profile.php20
-rw-r--r--plugins/OStatus/js/ostatus.js60
-rw-r--r--plugins/OStatus/lib/activity.php330
-rw-r--r--plugins/OStatus/tests/ActivityParseTests.php147
-rw-r--r--plugins/OStatus/theme/base/css/ostatus.css30
-rw-r--r--plugins/OpenID/finishopenidlogin.php47
-rw-r--r--plugins/PoweredByStatusNet/PoweredByStatusNetPlugin.php1
12 files changed, 661 insertions, 99 deletions
diff --git a/plugins/MemcachePlugin.php b/plugins/MemcachePlugin.php
index c5e74fb41..c3ca5c135 100644
--- a/plugins/MemcachePlugin.php
+++ b/plugins/MemcachePlugin.php
@@ -51,6 +51,8 @@ if (!defined('STATUSNET')) {
class MemcachePlugin extends Plugin
{
+ static $cacheInitialized = false;
+
private $_conn = null;
public $servers = array('127.0.0.1;11211');
@@ -71,10 +73,21 @@ class MemcachePlugin extends Plugin
function onInitializePlugin()
{
- if (is_null($this->persistent)) {
+ if (self::$cacheInitialized) {
+ $this->persistent = true;
+ } else {
+ // If we're a parent command-line process we need
+ // to be able to close out the connection after
+ // forking, so disable persistence.
+ //
+ // We'll turn it back on again the second time
+ // through which will either be in a child process,
+ // or a single-process script which is switching
+ // configurations.
$this->persistent = (php_sapi_name() == 'cli') ? false : true;
}
$this->_ensureConn();
+ self::$cacheInitialized = true;
return true;
}
@@ -122,6 +135,24 @@ class MemcachePlugin extends Plugin
}
/**
+ * Atomically increment an existing numeric key value.
+ * Existing expiration time will not be changed.
+ *
+ * @param string &$key in; Key to use for lookups
+ * @param int &$step in; Amount to increment (default 1)
+ * @param mixed &$value out; Incremented value, or false if key not set.
+ *
+ * @return boolean hook success
+ */
+ function onStartCacheIncrement(&$key, &$step, &$value)
+ {
+ $this->_ensureConn();
+ $value = $this->_conn->increment($key, $step);
+ Event::handle('EndCacheIncrement', array($key, $step, $value));
+ return false;
+ }
+
+ /**
* Delete a value associated with a key
*
* @param string &$key in; Key to lookup
diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php
index 8444c3d73..3b1329d6c 100644
--- a/plugins/OStatus/OStatusPlugin.php
+++ b/plugins/OStatus/OStatusPlugin.php
@@ -63,9 +63,9 @@ class OStatusPlugin extends Plugin
$m->connect('main/ostatus?nickname=:nickname',
array('action' => 'ostatusinit'), array('nickname' => '[A-Za-z0-9_-]+'));
$m->connect('main/ostatussub',
- array('action' => 'ostatussub'));
+ array('action' => 'ostatussub'));
$m->connect('main/ostatussub',
- array('action' => 'ostatussub'), array('feed' => '[A-Za-z0-9\.\/\:]+'));
+ array('action' => 'ostatussub'), array('feed' => '[A-Za-z0-9\.\/\:]+'));
// PuSH actions
$m->connect('main/push/hub', array('action' => 'pushhub'));
@@ -112,35 +112,34 @@ class OStatusPlugin extends Plugin
* Set up a PuSH hub link to our internal link for canonical timeline
* Atom feeds for users and groups.
*/
- function onStartApiAtom(Action $action)
+ function onStartApiAtom(AtomNoticeFeed $feed)
{
- if ($action instanceof ApiTimelineUserAction) {
+ $id = null;
+
+ if ($feed instanceof AtomUserNoticeFeed) {
$salmonAction = 'salmon';
- } else if ($action instanceof ApiTimelineGroupAction) {
+ $id = $feed->getUser()->id;
+ } else if ($feed instanceof AtomGroupNoticeFeed) {
$salmonAction = 'salmongroup';
+ $id = $feed->getGroup()->id;
} else {
return;
}
- $id = $action->arg('id');
- if (strval(intval($id)) === strval($id)) {
- // Canonical form of id in URL? These are used for OStatus syndication.
-
+ if (!empty($id)) {
$hub = common_config('ostatus', 'hub');
if (empty($hub)) {
// Updates will be handled through our internal PuSH hub.
$hub = common_local_url('pushhub');
}
- $action->element('link', array('rel' => 'hub',
- 'href' => $hub));
+ $feed->addLink($hub, array('rel' => 'hub'));
// Also, we'll add in the salmon link
$salmon = common_local_url($salmonAction, array('id' => $id));
- $action->element('link', array('rel' => 'salmon',
- 'href' => $salmon));
+ $feed->addLink($salmon, array('rel' => 'salmon'));
}
}
-
+
/**
* Add the feed settings page to the Connect Settings menu
*
@@ -189,7 +188,7 @@ class OStatusPlugin extends Plugin
/**
* Add in an OStatus subscribe button
*/
- function onStartProfilePageActionsElements($output, $profile)
+ function onStartProfileRemoteSubscribe($output, $profile)
{
$cur = common_current_user();
@@ -200,10 +199,12 @@ class OStatusPlugin extends Plugin
array('nickname' => $profile->nickname));
$output->element('a', array('href' => $url,
'class' => 'entity_remote_subscribe'),
- _m('OStatus'));
-
+ _m('Subscribe'));
+
$output->elementEnd('li');
}
+
+ return false;
}
/**
@@ -217,29 +218,34 @@ class OStatusPlugin extends Plugin
$count = preg_match_all('/(\w+\.)*\w+@(\w+\.)*\w+(\w+\-\w+)*\.\w+/', $notice->content, $matches);
if ($count) {
foreach ($matches[0] as $webfinger) {
+
+ // FIXME: look up locally first
+
// Check to see if we've got an actual webfinger
$w = new Webfinger;
$endpoint_uri = '';
-
+
$result = $w->lookup($webfinger);
if (empty($result)) {
continue;
}
-
+
foreach ($result->links as $link) {
if ($link['rel'] == 'salmon') {
$endpoint_uri = $link['href'];
}
}
-
+
if (empty($endpoint_uri)) {
continue;
}
+ // FIXME: this needs to go out in a queue handler
+
$xml = '<?xml version="1.0" encoding="UTF-8" ?>';
$xml .= $notice->asAtomEntry();
-
+
$salmon = new Salmon();
$salmon->post($endpoint_uri, $xml);
}
@@ -273,4 +279,14 @@ class OStatusPlugin extends Plugin
$schema->ensureTable('hubsub', HubSub::schemaDef());
return true;
}
+
+ function onEndShowStatusNetStyles($action) {
+ $action->cssLink(common_path('plugins/OStatus/theme/base/css/ostatus.css'));
+ return true;
+ }
+
+ function onEndShowStatusNetScripts($action) {
+ $action->script(common_path('plugins/OStatus/js/ostatus.js'));
+ return true;
+ }
}
diff --git a/plugins/OStatus/actions/ostatusinit.php b/plugins/OStatus/actions/ostatusinit.php
index bac2c4d43..d21774420 100644
--- a/plugins/OStatus/actions/ostatusinit.php
+++ b/plugins/OStatus/actions/ostatusinit.php
@@ -67,9 +67,21 @@ class OStatusInitAction extends Action
function showForm($err = null)
{
- $this->err = $err;
- $this->showPage();
-
+ $this->err = $err;
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ $this->element('title', null, _('Subscribe to user'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->showContent();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ $this->showPage();
+ }
}
function showContent()
@@ -79,15 +91,15 @@ class OStatusInitAction extends Action
'class' => 'form_settings',
'action' => common_local_url('ostatusinit')));
$this->elementStart('fieldset');
- $this->element('legend', _('Subscribe to a remote user'));
+ $this->element('legend', null, sprintf(_('Subscribe to %s'), $this->nickname));
$this->hidden('token', common_session_token());
$this->elementStart('ul', 'form_data');
- $this->elementStart('li');
+ $this->elementStart('li', array('id' => 'ostatus_nickname'));
$this->input('nickname', _('User nickname'), $this->nickname,
_('Nickname of the user you want to follow'));
$this->elementEnd('li');
- $this->elementStart('li');
+ $this->elementStart('li', array('id' => 'ostatus_profile'));
$this->input('acct', _('Profile Account'), $this->acct,
_('Your account id (i.e. user@identi.ca)'));
$this->elementEnd('li');
@@ -95,7 +107,7 @@ class OStatusInitAction extends Action
$this->submit('submit', _('Subscribe'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
- }
+ }
function ostatusConnect()
{
@@ -125,4 +137,4 @@ class OStatusInitAction extends Action
return _('OStatus Connect');
}
-} \ No newline at end of file
+}
diff --git a/plugins/OStatus/actions/ostatussub.php b/plugins/OStatus/actions/ostatussub.php
index 9774286fd..239122501 100644
--- a/plugins/OStatus/actions/ostatussub.php
+++ b/plugins/OStatus/actions/ostatussub.php
@@ -76,7 +76,7 @@ class OStatusSubAction extends Action
$this->elementStart('fieldset', array('id' => 'settings_feeds'));
$this->elementStart('ul', 'form_data');
- $this->elementStart('li', array('id' => 'settings_twitter_login_button'));
+ $this->elementStart('li');
$this->input('feedurl', _('Feed URL'), $this->feedurl, _('Enter the URL of a PubSubHubbub-enabled feed'));
$this->elementEnd('li');
$this->elementEnd('ul');
@@ -223,4 +223,4 @@ class OStatusSubAction extends Action
}
-} \ No newline at end of file
+}
diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php
index b616027a9..c79d09c95 100644
--- a/plugins/OStatus/actions/salmon.php
+++ b/plugins/OStatus/actions/salmon.php
@@ -61,7 +61,7 @@ class SalmonAction extends Action
// XXX: check that document element is Atom entry
// XXX: check the signature
- $this->act = Activity::fromAtomEntry($dom->documentElement);
+ $this->act = new Activity($dom->documentElement);
}
function handle($args)
diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php
index 733d8843b..b750e1883 100644
--- a/plugins/OStatus/classes/Ostatus_profile.php
+++ b/plugins/OStatus/classes/Ostatus_profile.php
@@ -29,15 +29,15 @@ PuSH subscription flow:
generate random verification token
save to verify_token
sends a sub request to the hub...
-
+
main/push/callback
hub sends confirmation back to us via GET
We verify the request, then echo back the challenge.
On our end, we save the time we subscribed and the lease expiration
-
+
main/push/callback
hub sends us updates via POST
-
+
*/
class FeedDBException extends FeedSubException
@@ -75,7 +75,6 @@ class Ostatus_profile extends Memcached_DataObject
public $created;
public $lastupdate;
-
public /*static*/ function staticGet($k, $v=null)
{
return parent::staticGet(__CLASS__, $k, $v);
@@ -107,7 +106,7 @@ class Ostatus_profile extends Memcached_DataObject
'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
'lastupdate' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
}
-
+
static function schemaDef()
{
return array(new ColumnDef('id', 'integer',
@@ -486,7 +485,7 @@ class Ostatus_profile extends Memcached_DataObject
}
if ($this->salmonuri) {
$text = 'update'; // @fixme
- $id = 'tag:' . common_config('site', 'server') .
+ $id = 'tag:' . common_config('site', 'server') .
':' . $verb .
':' . $actor->id .
':' . time(); // @fixme
@@ -589,7 +588,7 @@ class Ostatus_profile extends Memcached_DataObject
require_once "XML/Feed/Parser.php";
$feed = new XML_Feed_Parser($xml, false, false, true);
$munger = new FeedMunger($feed);
-
+
$hits = 0;
foreach ($feed as $index => $entry) {
// @fixme this might sort in wrong order if we get multiple updates
@@ -598,9 +597,10 @@ class Ostatus_profile extends Memcached_DataObject
// Double-check for oldies
// @fixme this could explode horribly for multiple feeds on a blog. sigh
- $dupe = new Notice();
- $dupe->uri = $notice->uri;
- if ($dupe->find(true)) {
+
+ $dupe = Notice::staticGet('uri', $notice->uri);
+
+ if (!empty($dupe)) {
common_log(LOG_WARNING, __METHOD__ . ": tried to save dupe notice for entry {$notice->uri} of feed {$this->feeduri}");
continue;
}
diff --git a/plugins/OStatus/js/ostatus.js b/plugins/OStatus/js/ostatus.js
new file mode 100644
index 000000000..671795558
--- /dev/null
+++ b/plugins/OStatus/js/ostatus.js
@@ -0,0 +1,60 @@
+SN.U.DialogBox = {
+ Subscribe: function(a) {
+ var f = a.parent().find('#form_ostatus_connect');
+ if (f.length > 0) {
+ f.show();
+ }
+ else {
+ $.ajax({
+ type: 'GET',
+ dataType: 'xml',
+ url: a[0].href+'&ajax=1',
+ beforeSend: function(formData) {
+ a.addClass('processing');
+ },
+ error: function (xhr, textStatus, errorThrown) {
+ alert(errorThrown || textStatus);
+ },
+ success: function(data, textStatus, xhr) {
+ if (typeof($('form', data)[0]) != 'undefined') {
+ a.after(document._importNode($('form', data)[0], true));
+
+ var form = a.parent().find('#form_ostatus_connect');
+
+ form
+ .addClass('dialogbox')
+ .append('<button class="close">&#215;</button>');
+
+ form
+ .find('.submit')
+ .addClass('submit_dialogbox')
+ .removeClass('submit')
+ .bind('click', function() {
+ form.addClass('processing');
+ });
+
+ form.find('button.close').click(function(){
+ form.hide();
+
+ return false;
+ });
+
+ form.find('#acct').focus();
+ }
+
+ a.removeClass('processing');
+ }
+ });
+ }
+ }
+};
+
+SN.Init.Subscribe = function() {
+ $('.entity_subscribe a').live('click', function() { SN.U.DialogBox.Subscribe($(this)); return false; });
+};
+
+$(document).ready(function() {
+ if ($('.entity_subscribe .entity_remote_subscribe').length > 0) {
+ SN.Init.Subscribe();
+ }
+});
diff --git a/plugins/OStatus/lib/activity.php b/plugins/OStatus/lib/activity.php
index 36e227913..048efda2c 100644
--- a/plugins/OStatus/lib/activity.php
+++ b/plugins/OStatus/lib/activity.php
@@ -31,7 +31,75 @@ if (!defined('STATUSNET')) {
exit(1);
}
-class ActivityNoun
+/**
+ * Utilities for turning DOMish things into Activityish things
+ *
+ * Some common functions that I didn't have the bandwidth to try to factor
+ * into some kind of reasonable superclass, so just dumped here. Might
+ * be useful to have an ActivityObject parent class or something.
+ *
+ * @category OStatus
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+class ActivityUtils
+{
+ const ATOM = 'http://www.w3.org/2005/Atom';
+
+ const LINK = 'link';
+ const REL = 'rel';
+ const TYPE = 'type';
+ const HREF = 'href';
+
+ /**
+ * Get the permalink for an Activity object
+ *
+ * @param DOMElement $element A DOM element
+ *
+ * @return string related link, if any
+ */
+
+ static function getLink($element)
+ {
+ $links = $element->getElementsByTagnameNS(self::ATOM, self::LINK);
+
+ foreach ($links as $link) {
+
+ $rel = $link->getAttribute(self::REL);
+ $type = $link->getAttribute(self::TYPE);
+
+ if ($rel == 'alternate' && $type == 'text/html') {
+ return $link->getAttribute(self::HREF);
+ }
+ }
+
+ return null;
+ }
+}
+
+/**
+ * A noun-ish thing in the activity universe
+ *
+ * The activity streams spec talks about activity objects, while also having
+ * a tag activity:object, which is in fact an activity object. Aaaaaah!
+ *
+ * This is just a thing in the activity universe. Can be the subject, object,
+ * or indirect object (target!) of an activity verb. Rotten name, and I'm
+ * propagating it. *sigh*
+ *
+ * @category OStatus
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+class ActivityObject
{
const ARTICLE = 'http://activitystrea.ms/schema/1.0/article';
const BLOGENTRY = 'http://activitystrea.ms/schema/1.0/blog-entry';
@@ -47,19 +115,114 @@ class ActivityNoun
const PERSON = 'http://activitystrea.ms/schema/1.0/person';
const GROUP = 'http://activitystrea.ms/schema/1.0/group';
const PLACE = 'http://activitystrea.ms/schema/1.0/place';
- const COMMENT = 'http://activitystrea.ms/schema/1.0/comment'; // tea
+ const COMMENT = 'http://activitystrea.ms/schema/1.0/comment';
+ // ^^^^^^^^^^ tea!
+
+ // Atom elements we snarf
+
+ const TITLE = 'title';
+ const SUMMARY = 'summary';
+ const CONTENT = 'content';
+ const ID = 'id';
+ const SOURCE = 'source';
+
+ const NAME = 'name';
+ const URI = 'uri';
+ const EMAIL = 'email';
public $type;
public $id;
public $title;
public $summary;
public $content;
+ public $link;
+ public $source;
+
+ /**
+ * Constructor
+ *
+ * This probably needs to be refactored
+ * to generate a local class (ActivityPerson, ActivityFile, ...)
+ * based on the object type.
+ *
+ * @param DOMElement $element DOM thing to turn into an Activity thing
+ */
+
+ function __construct($element)
+ {
+ $this->source = $element;
+
+ if ($element->tagName == 'author') {
+
+ $this->type = self::PERSON; // XXX: is this fair?
+ $this->title = $this->_childContent($element, self::NAME);
+ $this->id = $this->_childContent($element, self::URI);
+
+ if (empty($this->id)) {
+ $email = $this->_childContent($element, self::EMAIL);
+ if (!empty($email)) {
+ // XXX: acct: ?
+ $this->id = 'mailto:'.$email;
+ }
+ }
+
+ } else {
+
+ $this->type = $this->_childContent($element, Activity::OBJECTTYPE,
+ Activity::SPEC);
+
+ if (empty($this->type)) {
+ $this->type = ActivityObject::NOTE;
+ }
+
+ $this->id = $this->_childContent($element, self::ID);
+ $this->title = $this->_childContent($element, self::TITLE);
+ $this->summary = $this->_childContent($element, self::SUMMARY);
+ $this->content = $this->_childContent($element, self::CONTENT);
+ $this->source = $this->_childContent($element, self::SOURCE);
+
+ $this->link = ActivityUtils::getLink($element);
+
+ // XXX: grab PoCo stuff
+ }
+ }
+
+ /**
+ * Grab the text content of a DOM element child of the current element
+ *
+ * @param DOMElement $element Element whose children we examine
+ * @param string $tag Tag to look up
+ * @param string $namespace Namespace to use, defaults to Atom
+ *
+ * @return string content of the child
+ */
+
+ private function _childContent($element, $tag, $namespace=Activity::ATOM)
+ {
+ $els = $element->getElementsByTagnameNS($namespace, $tag);
+
+ if (empty($els) || $els->length == 0) {
+ return null;
+ } else {
+ $el = $els->item(0);
+ return $el->textContent;
+ }
+ }
}
-class Activity
-{
- const NAMESPACE = 'http://activitystrea.ms/schema/1.0/';
+/**
+ * Utility class to hold a bunch of constant defining default verb types
+ *
+ * @category OStatus
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+class ActivityVerb
+{
const POST = 'http://activitystrea.ms/schema/1.0/post';
const SHARE = 'http://activitystrea.ms/schema/1.0/share';
const SAVE = 'http://activitystrea.ms/schema/1.0/save';
@@ -69,17 +232,162 @@ class Activity
const FRIEND = 'http://activitystrea.ms/schema/1.0/make-friend';
const JOIN = 'http://activitystrea.ms/schema/1.0/join';
const TAG = 'http://activitystrea.ms/schema/1.0/tag';
+}
+
+/**
+ * An activity in the ActivityStrea.ms world
+ *
+ * An activity is kind of like a sentence: someone did something
+ * to something else.
+ *
+ * 'someone' is the 'actor'; 'did something' is the verb;
+ * 'something else' is the object.
+ *
+ * @category OStatus
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+class Activity
+{
+ const SPEC = 'http://activitystrea.ms/spec/1.0/';
+ const SCHEMA = 'http://activitystrea.ms/schema/1.0/';
+
+ const VERB = 'verb';
+ const OBJECT = 'object';
+ const ACTOR = 'actor';
+ const SUBJECT = 'subject';
+ const OBJECTTYPE = 'object-type';
+ const CONTEXT = 'context';
+ const TARGET = 'target';
+
+ const ATOM = 'http://www.w3.org/2005/Atom';
+
+ const AUTHOR = 'author';
+ const PUBLISHED = 'published';
+ const UPDATED = 'updated';
- public $actor; // an ActivityNoun
- public $verb; // a string (the URL)
- public $object; // an ActivityNoun
- public $target; // an ActivityNoun
+ public $actor; // an ActivityObject
+ public $verb; // a string (the URL)
+ public $object; // an ActivityObject
+ public $target; // an ActivityObject
+ public $context; // an ActivityObject
+ public $time; // Time of the activity
+ public $link; // an ActivityObject
+ public $entry; // the source entry
+ public $feed; // the source feed
- static function fromAtomEntry($domEntry)
+ /**
+ * Turns a regular old Atom <entry> into a magical activity
+ *
+ * @param DOMElement $entry Atom entry to poke at
+ * @param DOMElement $feed Atom feed, for context
+ */
+
+ function __construct($entry, $feed = null)
{
+ $this->entry = $entry;
+ $this->feed = $feed;
+
+ $pubEl = $this->_child($entry, self::PUBLISHED, self::ATOM);
+
+ if (!empty($pubEl)) {
+ $this->time = strtotime($pubEl->textContent);
+ } else {
+ // XXX technically an error; being liberal. Good idea...?
+ $updateEl = $this->_child($entry, self::UPDATED, self::ATOM);
+ if (!empty($updateEl)) {
+ $this->time = strtotime($updateEl->textContent);
+ } else {
+ $this->time = null;
+ }
+ }
+
+ $this->link = ActivityUtils::getLink($entry);
+
+ $verbEl = $this->_child($entry, self::VERB);
+
+ if (!empty($verbEl)) {
+ $this->verb = trim($verbEl->textContent);
+ } else {
+ $this->verb = ActivityVerb::POST;
+ // XXX: do other implied stuff here
+ }
+
+ $objectEl = $this->_child($entry, self::OBJECT);
+
+ if (!empty($objectEl)) {
+ $this->object = new ActivityObject($objectEl);
+ } else {
+ $this->object = new ActivityObject($entry);
+ }
+
+ $actorEl = $this->_child($entry, self::ACTOR);
+
+ if (!empty($actorEl)) {
+
+ $this->actor = new ActivityObject($actorEl);
+
+ } else if (!empty($feed) &&
+ $subjectEl = $this->_child($feed, self::SUBJECT)) {
+
+ $this->actor = new ActivityObject($subjectEl);
+
+ } else if ($authorEl = $this->_child($entry, self::AUTHOR, self::ATOM)) {
+
+ $this->actor = new ActivityObject($authorEl);
+
+ } else if (!empty($feed) && $authorEl = $this->_child($feed, self::AUTHOR,
+ self::ATOM)) {
+
+ $this->actor = new ActivityObject($authorEl);
+ }
+
+ $contextEl = $this->_child($entry, self::CONTEXT);
+
+ if (!empty($contextEl)) {
+ $this->context = new ActivityObject($contextEl);
+ }
+
+ $targetEl = $this->_child($entry, self::TARGET);
+
+ if (!empty($targetEl)) {
+ $this->target = new ActivityObject($targetEl);
+ }
}
+ /**
+ * Returns an Atom <entry> based on this activity
+ *
+ * @return DOMElement Atom entry
+ */
+
function toAtomEntry()
{
+ return null;
}
-}
+
+ /**
+ * Gets the first child element with the given tag
+ *
+ * @param DOMElement $element element to pick at
+ * @param string $tag tag to look for
+ * @param string $namespace Namespace to look under
+ *
+ * @return DOMElement found element or null
+ */
+
+ private function _child($element, $tag, $namespace=self::SPEC)
+ {
+ $els = $element->getElementsByTagnameNS($namespace, $tag);
+
+ if (empty($els) || $els->length == 0) {
+ return null;
+ } else {
+ return $els->item(0);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/OStatus/tests/ActivityParseTests.php b/plugins/OStatus/tests/ActivityParseTests.php
new file mode 100644
index 000000000..fa8bcdda2
--- /dev/null
+++ b/plugins/OStatus/tests/ActivityParseTests.php
@@ -0,0 +1,147 @@
+<?php
+
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+ print "This script must be run from the command line\n";
+ exit();
+}
+
+// XXX: we should probably have some common source for this stuff
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
+define('STATUSNET', true);
+
+require_once INSTALLDIR . '/lib/common.php';
+require_once INSTALLDIR . '/plugins/OStatus/lib/activity.php';
+
+class ActivityParseTests extends PHPUnit_Framework_TestCase
+{
+ public function testExample1()
+ {
+ global $_example1;
+ $dom = DOMDocument::loadXML($_example1);
+ $act = new Activity($dom->documentElement);
+
+ $this->assertFalse(empty($act));
+ $this->assertEquals($act->time, 1243860840);
+ $this->assertEquals($act->verb, ActivityVerb::POST);
+ }
+
+ public function testExample3()
+ {
+ global $_example3;
+ $dom = DOMDocument::loadXML($_example3);
+
+ $feed = $dom->documentElement;
+
+ $entries = $feed->getElementsByTagName('entry');
+
+ $entry = $entries->item(0);
+
+ $act = new Activity($entry, $feed);
+
+ $this->assertFalse(empty($act));
+ $this->assertEquals($act->time, 1071340202);
+ $this->assertEquals($act->link, 'http://example.org/2003/12/13/atom03.html');
+
+ $this->assertEquals($act->verb, ActivityVerb::POST);
+
+ $this->assertFalse(empty($act->actor));
+ $this->assertEquals($act->actor->type, ActivityObject::PERSON);
+ $this->assertEquals($act->actor->title, 'John Doe');
+ $this->assertEquals($act->actor->id, 'mailto:johndoe@example.com');
+
+ $this->assertFalse(empty($act->object));
+ $this->assertEquals($act->object->type, ActivityObject::NOTE);
+ $this->assertEquals($act->object->id, 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a');
+ $this->assertEquals($act->object->title, 'Atom-Powered Robots Run Amok');
+ $this->assertEquals($act->object->summary, 'Some text.');
+ $this->assertEquals($act->object->link, 'http://example.org/2003/12/13/atom03.html');
+
+ $this->assertTrue(empty($act->context));
+ $this->assertTrue(empty($act->target));
+
+ $this->assertEquals($act->entry, $entry);
+ $this->assertEquals($act->feed, $feed);
+ }
+}
+
+$_example1 = <<<EXAMPLE1
+<?xml version='1.0' encoding='UTF-8'?>
+<entry xmlns='http://www.w3.org/2005/Atom' xmlns:activity='http://activitystrea.ms/spec/1.0/'>
+ <id>tag:versioncentral.example.org,2009:/commit/1643245</id>
+ <published>2009-06-01T12:54:00Z</published>
+ <title>Geraldine committed a change to yate</title>
+ <content type="xhtml">Geraldine just committed a change to yate on VersionCentral</content>
+ <link rel="alternate" type="text/html"
+ href="http://versioncentral.example.org/geraldine/yate/commit/1643245" />
+ <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+ <activity:verb>http://versioncentral.example.org/activity/commit</activity:verb>
+ <activity:object>
+ <activity:object-type>http://versioncentral.example.org/activity/changeset</activity:object-type>
+ <id>tag:versioncentral.example.org,2009:/change/1643245</id>
+ <title>Punctuation Changeset</title>
+ <summary>Fixing punctuation because it makes it more readable.</summary>
+ <link rel="alternate" type="text/html" href="..." />
+ </activity:object>
+</entry>
+EXAMPLE1;
+
+$_example2 = <<<EXAMPLE2
+<?xml version='1.0' encoding='UTF-8'?>
+<entry xmlns='http://www.w3.org/2005/Atom' xmlns:activity='http://activitystrea.ms/spec/1.0/'>
+ <id>tag:photopanic.example.com,2008:activity01</id>
+ <title>Geraldine posted a Photo on PhotoPanic</title>
+ <published>2008-11-02T15:29:00Z</published>
+ <link rel="alternate" type="text/html" href="/geraldine/activities/1" />
+ <activity:verb>
+ http://activitystrea.ms/schema/1.0/post
+ </activity:verb>
+ <activity:object>
+ <id>tag:photopanic.example.com,2008:photo01</id>
+ <title>My Cat</title>
+ <published>2008-11-02T15:29:00Z</published>
+ <link rel="alternate" type="text/html" href="/geraldine/photos/1" />
+ <activity:object-type>
+ tag:atomactivity.example.com,2008:photo
+ </activity:object-type>
+ <source>
+ <title>Geraldine's Photos</title>
+ <link rel="self" type="application/atom+xml" href="/geraldine/photofeed.xml" />
+ <link rel="alternate" type="text/html" href="/geraldine/" />
+ </source>
+ </activity:object>
+ <content type="html">
+ &lt;p&gt;Geraldine posted a Photo on PhotoPanic&lt;/p&gt;
+ &lt;img src="/geraldine/photo1.jpg"&gt;
+ </content>
+</entry>
+EXAMPLE2;
+
+$_example3 = <<<EXAMPLE3
+<?xml version="1.0" encoding="utf-8"?>
+
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+ <title>Example Feed</title>
+ <subtitle>A subtitle.</subtitle>
+ <link href="http://example.org/feed/" rel="self" />
+ <link href="http://example.org/" />
+ <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
+ <updated>2003-12-13T18:30:02Z</updated>
+ <author>
+ <name>John Doe</name>
+ <email>johndoe@example.com</email>
+ </author>
+
+ <entry>
+ <title>Atom-Powered Robots Run Amok</title>
+ <link href="http://example.org/2003/12/13/atom03" />
+ <link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
+ <link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+ <updated>2003-12-13T18:30:02Z</updated>
+ <summary>Some text.</summary>
+ </entry>
+
+</feed>
+EXAMPLE3;
diff --git a/plugins/OStatus/theme/base/css/ostatus.css b/plugins/OStatus/theme/base/css/ostatus.css
new file mode 100644
index 000000000..9bc90a731
--- /dev/null
+++ b/plugins/OStatus/theme/base/css/ostatus.css
@@ -0,0 +1,30 @@
+/** theme: base for OStatus
+ *
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @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/
+ */
+
+#form_ostatus_connect.dialogbox {
+width:70%;
+background-image:none;
+}
+#form_ostatus_connect.dialogbox .form_data label {
+width:34%;
+}
+#form_ostatus_connect.dialogbox .form_data input {
+width:57%;
+}
+#form_ostatus_connect.dialogbox .form_data .form_guide {
+margin-left:36%;
+}
+
+#form_ostatus_connect.dialogbox #ostatus_nickname {
+display:none;
+}
+
+#form_ostatus_connect.dialogbox .submit_dialogbox {
+min-width:96px;
+}
diff --git a/plugins/OpenID/finishopenidlogin.php b/plugins/OpenID/finishopenidlogin.php
index d25ce696c..438a728d8 100644
--- a/plugins/OpenID/finishopenidlogin.php
+++ b/plugins/OpenID/finishopenidlogin.php
@@ -438,49 +438,7 @@ class FinishopenidloginAction extends Action
function urlToNickname($openid)
{
- static $bad = array('query', 'user', 'password', 'port', 'fragment');
-
- $parts = parse_url($openid);
-
- # If any of these parts exist, this won't work
-
- foreach ($bad as $badpart) {
- if (array_key_exists($badpart, $parts)) {
- return null;
- }
- }
-
- # We just have host and/or path
-
- # If it's just a host...
- if (array_key_exists('host', $parts) &&
- (!array_key_exists('path', $parts) || strcmp($parts['path'], '/') == 0))
- {
- $hostparts = explode('.', $parts['host']);
-
- # Try to catch common idiom of nickname.service.tld
-
- if ((count($hostparts) > 2) &&
- (strlen($hostparts[count($hostparts) - 2]) > 3) && # try to skip .co.uk, .com.au
- (strcmp($hostparts[0], 'www') != 0))
- {
- return $this->nicknamize($hostparts[0]);
- } else {
- # Do the whole hostname
- return $this->nicknamize($parts['host']);
- }
- } else {
- if (array_key_exists('path', $parts)) {
- # Strip starting, ending slashes
- $path = preg_replace('@/$@', '', $parts['path']);
- $path = preg_replace('@^/@', '', $path);
- if (strpos($path, '/') === false) {
- return $this->nicknamize($path);
- }
- }
- }
-
- return null;
+ return common_url_to_nickname($openid);
}
function xriToNickname($xri)
@@ -510,7 +468,6 @@ class FinishopenidloginAction extends Action
function nicknamize($str)
{
- $str = preg_replace('/\W/', '', $str);
- return strtolower($str);
+ return common_nicknamize($str);
}
}
diff --git a/plugins/PoweredByStatusNet/PoweredByStatusNetPlugin.php b/plugins/PoweredByStatusNet/PoweredByStatusNetPlugin.php
index 14d1608d3..fb4eff738 100644
--- a/plugins/PoweredByStatusNet/PoweredByStatusNetPlugin.php
+++ b/plugins/PoweredByStatusNet/PoweredByStatusNetPlugin.php
@@ -45,6 +45,7 @@ class PoweredByStatusNetPlugin extends Plugin
{
function onEndAddressData($action)
{
+ $action->text(' ');
$action->elementStart('span', 'poweredby');
$action->raw(sprintf(_m('powered by %s'),
sprintf('<a href="http://status.net/">%s</a>',