]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
OStatus sub/unsub updates:
authorBrion Vibber <brion@pobox.com>
Thu, 18 Feb 2010 18:20:48 +0000 (18:20 +0000)
committerBrion Vibber <brion@pobox.com>
Thu, 18 Feb 2010 18:20:48 +0000 (18:20 +0000)
- fix for PuSH unsub verification
- send Salmon notification on unsub

lib/atom10entry.php
lib/atom10feed.php
lib/atomnoticefeed.php
plugins/OStatus/OStatusPlugin.php
plugins/OStatus/actions/pushcallback.php
plugins/OStatus/actions/pushhub.php
plugins/OStatus/actions/salmon.php
plugins/OStatus/classes/HubSub.php
plugins/OStatus/classes/Ostatus_profile.php
plugins/OStatus/lib/activity.php
plugins/OStatus/lib/hubverifyqueuehandler.php

index 5710c80fc59d24be39b933da47a1056211b4b262..f8f16d5946bc31bf784005e2526b06daa59bf282 100644 (file)
@@ -27,8 +27,7 @@
  * @link      http://status.net/
  */
 
-if (!defined('STATUSNET')
-{
+if (!defined('STATUSNET')) {
     exit(1);
 }
 
@@ -87,7 +86,7 @@ class Atom10Entry extends XMLStringer
      *
      * @return void
      */
-    function validate
+    function validate()
     {
 
     }
index 14a3beb83e3116dcd539fd6932a0cd16df6cf10c..5e17b20d3ab8816507ea4ebe96fb99786a97e6f3 100644 (file)
@@ -78,7 +78,7 @@ class Atom10Feed extends XMLStringer
         $this->authors    = array();
         $this->links      = array();
         $this->entries    = array();
-        $this->addNamespace('xmlns', 'http://www.w3.org/2005/Atom');
+        $this->addNamespace('', 'http://www.w3.org/2005/Atom');
     }
 
     /**
@@ -162,7 +162,14 @@ class Atom10Feed extends XMLStringer
     {
         $this->xw->startDocument('1.0', 'UTF-8');
         $commonAttrs = array('xml:lang' => 'en-US');
-        $commonAttrs = array_merge($commonAttrs, $this->namespaces);
+        foreach ($this->namespaces as $prefix => $uri) {
+            if ($prefix == '') {
+                $attr = 'xmlns';
+            } else {
+                $attr = 'xmlns:' . $prefix;
+            }
+            $commonAttrs[$attr] = $uri;
+        }
         $this->elementStart('feed', $commonAttrs);
 
         $this->element('id', null, $this->id);
index b7a60bde6ebae19b93b38eb97c34ea4a5c385242..7653f9154463d3eacc460a22b443ffd3262eb58a 100644 (file)
@@ -50,23 +50,23 @@ class AtomNoticeFeed extends Atom10Feed
         // Feeds containing notice info use these namespaces
 
         $this->addNamespace(
-            'xmlns:thr',
+            'thr',
             'http://purl.org/syndication/thread/1.0'
         );
 
         $this->addNamespace(
-            'xmlns:georss',
+            'georss',
             'http://www.georss.org/georss'
         );
 
         $this->addNamespace(
-            'xmlns:activity',
+            'activity',
             'http://activitystrea.ms/spec/1.0/'
         );
 
         // XXX: What should the uri be?
         $this->addNamespace(
-            'xmlns:ostatus',
+            'ostatus',
             'http://ostatus.org/schema/1.0'
         );
     }
index b6c9fa1d4c28b2439255f1af31d6f3f657eaf482..e548a151c7f69cc3bff4bd8262d8e7727939890c 100644 (file)
@@ -112,7 +112,7 @@ 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(AtomNoticeFeed $feed)
+    function onStartApiAtom($feed)
     {
         $id = null;
 
@@ -171,6 +171,12 @@ class OStatusPlugin extends Plugin
     {
         $base = dirname(__FILE__);
         $lower = strtolower($cls);
+        $map = array('activityverb' => 'activity',
+                     'activityobject' => 'activity',
+                     'activityutils' => 'activity');
+        if (isset($map[$lower])) {
+            $lower = $map[$lower];
+        }
         $files = array("$base/classes/$cls.php",
                        "$base/lib/$lower.php");
         if (substr($lower, -6) == 'action') {
@@ -253,18 +259,45 @@ class OStatusPlugin extends Plugin
     }
 
     /**
-     * Garbage collect unused feeds on unsubscribe
+     * Notify remote server when one of our users subscribes.
+     * @fixme Check and restart the PuSH subscription if needed
+     *
+     * @param User $user
+     * @param Profile $other
+     * @return hook return value
+     */
+    function onEndSubscribe($user, $other)
+    {
+        $oprofile = Ostatus_profile::staticGet('profile_id', $other->id);
+        if ($oprofile) {
+            // Notify the remote server of the unsub, if supported.
+            $oprofile->notify($user->getProfile(), ActivityVerb::FOLLOW, $oprofile);
+        }
+        return true;
+    }
+
+    /**
+     * Notify remote server and garbage collect unused feeds on unsubscribe.
+     * @fixme send these operations to background queues
+     *
+     * @param User $user
+     * @param Profile $other
+     * @return hook return value
      */
     function onEndUnsubscribe($user, $other)
     {
-        $profile = Ostatus_profile::staticGet('profile_id', $other->id);
-        if ($feed) {
+        $oprofile = Ostatus_profile::staticGet('profile_id', $other->id);
+        if ($oprofile) {
+            // Notify the remote server of the unsub, if supported.
+            $oprofile->notify($user->getProfile(), ActivityVerb::UNFOLLOW, $oprofile);
+
+            // Drop the PuSH subscription if there are no other subscribers.
             $sub = new Subscription();
             $sub->subscribed = $other->id;
             $sub->limit(1);
             if (!$sub->find(true)) {
-                common_log(LOG_INFO, "Unsubscribing from now-unused feed $feed->feeduri on hub $feed->huburi");
-                $profile->unsubscribe();
+                common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri on hub $oprofile->huburi");
+                $oprofile->unsubscribe();
             }
         }
         return true;
@@ -290,6 +323,16 @@ class OStatusPlugin extends Plugin
         return true;
     }
 
+    /**
+     * Override the "from ostatus" bit in notice lists to link to the
+     * original post and show the domain it came from.
+     *
+     * @param Notice in $notice
+     * @param string out &$name
+     * @param string out &$url
+     * @param string out &$title
+     * @return mixed hook return code
+     */
     function onStartNoticeSourceLink($notice, &$name, &$url, &$title)
     {
         if ($notice->source == 'ostatus') {
index 388c8f9c3dad2976f2232b8ef772f5dbc6d32e31..ed859a32f821bcc1cdeea5193b225ad0308a4020 100644 (file)
@@ -89,7 +89,7 @@ class PushCallbackAction extends Action
 
         if ($profile->verify_token !== $verify_token) {
             common_log(LOG_WARNING, __METHOD__ . ": bogus hub callback with bad token \"$verify_token\" for feed $topic");
-            throw new ServerError("Bogus hub callback: bad token", 404);
+            throw new ServerException("Bogus hub callback: bad token", 404);
         }
 
         if ($mode != $profile->sub_state) {
index 13ec09d52871634b3bb864742bc038994923b564..19599d815f51b2ab1344f6a965976e7f28574ec5 100644 (file)
@@ -83,6 +83,7 @@ class PushHubAction extends Action
     {
         $feed = $this->argUrl('hub.topic');
         $callback = $this->argUrl('hub.callback');
+        $token = $this->arg('hub.verify_token', null);
 
         common_log(LOG_DEBUG, __METHOD__ . ": checking sub'd to $feed $callback");
         if ($this->getSub($feed, $callback)) {
@@ -96,7 +97,6 @@ class PushHubAction extends Action
         $sub = new HubSub();
         $sub->topic = $feed;
         $sub->callback = $callback;
-        $sub->verify_token = $this->arg('hub.verify_token', null);
         $sub->secret = $this->arg('hub.secret', null);
         if (strlen($sub->secret) > 200) {
             throw new ClientException("hub.secret must be no longer than 200 chars", 400);
@@ -115,7 +115,7 @@ class PushHubAction extends Action
 
         // @fixme check errors ;)
 
-        $data = array('sub' => $sub, 'mode' => 'subscribe');
+        $data = array('sub' => $sub, 'mode' => 'subscribe', 'token' => $token);
         $qm = QueueManager::get();
         $qm->enqueue($data, 'hubverify');
         
@@ -130,6 +130,8 @@ class PushHubAction extends Action
      *   202 Accepted - request saved and awaiting verification
      *   204 No Content - already subscribed
      *   400 Bad Request - invalid params or rejected feed
+     *
+     * @fixme background this
      */
     function unsubscribe()
     {
@@ -138,7 +140,8 @@ class PushHubAction extends Action
         $sub = $this->getSub($feed, $callback);
         
         if ($sub) {
-            if ($sub->verify('unsubscribe')) {
+            $token = $this->arg('hub.verify_token', null);
+            if ($sub->verify('unsubscribe', $token)) {
                 $sub->delete();
                 common_log(LOG_INFO, "PuSH unsubscribed $feed for $callback");
             } else {
index 9ca01982663089a1eb7f97fb8806cd4371a552a0..224134cd7cbebea72354d22a8f0dec99d52ae4fa 100644 (file)
@@ -34,6 +34,8 @@ class SalmonAction extends Action
 
     function prepare($args)
     {
+        parent::prepare($args);
+
         if ($_SERVER['REQUEST_METHOD'] != 'POST') {
             $this->clientError(_('This method requires a POST.'));
         }
index 7071ee5b4f82e9933973b7a3afc705ef58934233..0cd4281f8f5208199fb7b28cb9f922916bb60aa2 100644 (file)
@@ -30,7 +30,6 @@ class HubSub extends Memcached_DataObject
     public $topic;
     public $callback;
     public $secret;
-    public $verify_token;
     public $challenge;
     public $lease;
     public $sub_start;
@@ -62,7 +61,6 @@ class HubSub extends Memcached_DataObject
                      'topic' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
                      'callback' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
                      'secret' => DB_DATAOBJECT_STR,
-                     'verify_token' => DB_DATAOBJECT_STR,
                      'challenge' => DB_DATAOBJECT_STR,
                      'lease' =>  DB_DATAOBJECT_INT,
                      'sub_start' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME,
@@ -84,8 +82,6 @@ class HubSub extends Memcached_DataObject
                                    255, false),
                      new ColumnDef('secret', 'text',
                                    null, true),
-                     new ColumnDef('verify_token', 'text',
-                                   null, true),
                      new ColumnDef('challenge', 'varchar',
                                    32, true),
                      new ColumnDef('lease', 'int',
@@ -154,8 +150,9 @@ class HubSub extends Memcached_DataObject
     /**
      * Send a verification ping to subscriber
      * @param string $mode 'subscribe' or 'unsubscribe'
+     * @param string $token hub.verify_token value, if provided by client
      */
-    function verify($mode)
+    function verify($mode, $token=null)
     {
         assert($mode == 'subscribe' || $mode == 'unsubscribe');
 
@@ -172,8 +169,8 @@ class HubSub extends Memcached_DataObject
         if ($mode == 'subscribe') {
             $params['hub.lease_seconds'] = $this->lease;
         }
-        if ($this->verify_token) {
-            $params['hub.verify_token'] = $this->verify_token;
+        if ($token !== null) {
+            $params['hub.verify_token'] = $token;
         }
         $url = $this->callback . '?' . http_build_query($params, '', '&'); // @fixme ugly urls
 
index be01cdfe196236fb859e6feabe5f21260dc049b6..486417617c365091f68cc43ca2e2b99abbe196ca 100644 (file)
@@ -484,7 +484,7 @@ class Ostatus_profile extends Memcached_DataObject
         } else {
             $this->sub_end = null;
         }
-        $this->lastupdate = common_sql_date();
+        $this->lastupdate = common_sql_now();
 
         return $this->update($original);
     }
@@ -497,12 +497,13 @@ class Ostatus_profile extends Memcached_DataObject
     {
         $original = clone($this);
 
-        $this->verify_token = null;
-        $this->secret = null;
-        $this->sub_state = null;
-        $this->sub_start = null;
-        $this->sub_end = null;
-        $this->lastupdate = common_sql_date();
+        // @fixme these should all be null, but DB_DataObject doesn't save null values...?????
+        $this->verify_token = '';
+        $this->secret = '';
+        $this->sub_state = '';
+        $this->sub_start = '';
+        $this->sub_end = '';
+        $this->lastupdate = common_sql_now();
 
         return $this->update($original);
     }
@@ -527,24 +528,25 @@ class Ostatus_profile extends Memcached_DataObject
                 ':' . $actor->id .
                 ':' . time(); // @fixme
 
-            $entry = new Atom10Entry();
+            //$entry = new Atom10Entry();
+            $entry = new XMLStringer();
             $entry->elementStart('entry');
             $entry->element('id', null, $id);
             $entry->element('title', null, $text);
             $entry->element('summary', null, $text);
-            $entry->element('published', null, common_date_w3dtf());
+            $entry->element('published', null, common_date_w3dtf(time()));
 
             $entry->element('activity:verb', null, $verb);
-            $entry->raw($profile->asAtomAuthor());
-            $entry->raw($profile->asActivityActor());
+            $entry->raw($actor->asAtomAuthor());
+            $entry->raw($actor->asActivityActor());
             $entry->raw($object->asActivityNoun('object'));
-            $entry->elmentEnd('entry');
+            $entry->elementEnd('entry');
 
             $feed = $this->atomFeed($actor);
-            $feed->initFeed();
+            #$feed->initFeed();
             $feed->addEntry($entry);
-            $feed->renderEntries();
-            $feed->endFeed();
+            #$feed->renderEntries();
+            #$feed->endFeed();
 
             $xml = $feed->getString();
             common_log(LOG_INFO, "Posting to Salmon endpoint $salmon: $xml");
@@ -568,7 +570,7 @@ class Ostatus_profile extends Memcached_DataObject
         $feed = new Atom10Feed();
         // @fixme should these be set up somewhere else?
         $feed->addNamespace('activity', 'http://activitystrea.ms/spec/1.0/');
-        $feed->addNamesapce('thr', 'http://purl.org/syndication/thread/1.0');
+        $feed->addNamespace('thr', 'http://purl.org/syndication/thread/1.0');
         $feed->addNamespace('georss', 'http://www.georss.org/georss');
         $feed->addNamespace('ostatus', 'http://ostatus.org/schema/1.0');
 
@@ -579,14 +581,14 @@ class Ostatus_profile extends Memcached_DataObject
         $feed->setUpdated(time());
         $feed->setPublished(time());
 
-        $feed->addLink(common_url('ApiTimelineUser',
-                                  array('id' => $actor->id,
-                                        'type' => 'atom')),
+        $feed->addLink(common_local_url('ApiTimelineUser',
+                                        array('id' => $actor->id,
+                                              'type' => 'atom')),
                        array('rel' => 'self',
                              'type' => 'application/atom+xml'));
 
-        $feed->addLink(common_url('userbyid',
-                                  array('id' => $actor->id)),
+        $feed->addLink(common_local_url('userbyid',
+                                        array('id' => $actor->id)),
                        array('rel' => 'alternate',
                              'type' => 'text/html'));
 
index f137946ab4e1058c722170c11f6c99c38061b789..3ed613dc7f3f167efa161f268b52df84e17abfbd 100644 (file)
@@ -303,6 +303,12 @@ class ActivityVerb
     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';
+
+    // Custom OStatus verbs for the flipside until they're standardized
+    const DELETE     = 'http://ostatus.org/schema/1.0/unfollow';
+    const UNFAVORITE = 'http://ostatus.org/schema/1.0/unfavorite';
+    const UNFOLLOW   = 'http://ostatus.org/schema/1.0/unfollow';
+    const LEAVE      = 'http://ostatus.org/schema/1.0/leave';
 }
 
 /**
index 125d13a777fcac5848ae3a1322487f97bf78ad11..7ce9e14312e7684745e47448cf1e3eb5f3cb036e 100644 (file)
@@ -33,13 +33,14 @@ class HubVerifyQueueHandler extends QueueHandler
     {
         $sub = $data['sub'];
         $mode = $data['mode'];
+        $token = $data['token'];
 
         assert($sub instanceof HubSub);
         assert($mode === 'subscribe' || $mode === 'unsubscribe');
 
         common_log(LOG_INFO, __METHOD__ . ": $mode $sub->callback $sub->topic");
         try {
-            $sub->verify($mode);
+            $sub->verify($mode, $token);
         } catch (Exception $e) {
             common_log(LOG_ERR, "Failed PuSH $mode verify to $sub->callback for $sub->topic: " .
                                 $e->getMessage());