]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Update activity streams JSON to match spec
authorZach Copley <zach@status.net>
Thu, 25 Aug 2011 17:00:20 +0000 (10:00 -0700)
committerZach Copley <zach@status.net>
Thu, 25 Aug 2011 17:01:20 +0000 (10:01 -0700)
Squashed commit of the following:

commit 0722450267a1d0f4bdc2853f52a85b850329db73
Author: Zach Copley <zach@status.net>
Date:   Thu Aug 25 09:58:29 2011 -0700

    Updgrade activity object json

commit 882ba1dceaba8a0b3ec3513760aa09f68e41f270
Author: Zach Copley <zach@status.net>
Date:   Wed Aug 24 16:30:07 2011 -0700

    Update to the JSON activity serialization document

commit 121e441b314b93e184711c3dcc79ada69d429eba
Author: Zach Copley <zach@status.net>
Date:   Wed Aug 24 15:08:06 2011 -0700

    Output application/json instead of application/stream+json (at least for now)

commit e045e214bffe5e0ddeb0a42555d440b75ae4edde
Author: Zach Copley <zach@status.net>
Date:   Wed Aug 24 15:06:40 2011 -0700

    Update to use latest property names from the JSON activity spec

actions/apitimelinefriends.php
lib/activity.php
lib/activityobject.php
lib/activitystreamjsondocument.php

index e27d05265258d3ad224f27440541164c6c070325..591baccfccfba26713cf40c018d10a7be0927cad 100644 (file)
@@ -267,15 +267,14 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
             break;
         case 'as':
             header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
-            $doc = new ActivityStreamJSONDocument($this->auth_user);
-            $doc->setTitle($title);
-            $doc->addLink($link,'alternate', 'text/html');
+            $doc = new ActivityStreamJSONDocument($this->auth_user, $title);
+            $doc->addLink($link, 'alternate', 'text/html');
             $doc->addItemsFromNotices($this->notices);
             $this->raw($doc->asString());
             break;
         default:
             // TRANS: Client error displayed when coming across a non-supported API method.
-            $this->clientError(_('API method not found.'), $code = 404);
+            $this->clientError(_('API method not found.'), 404);
             break;
         }
     }
index 1582a2019e45f0460df21eaa44d09e82e350806f..9dbb0e2ee0029b845f5ca6464e519812f30ac534 100644 (file)
@@ -362,15 +362,16 @@ class Activity
         // actor
         $activity['actor'] = $this->actor->asArray();
 
-        // body
-        $activity['body'] = $this->content;
+        // content
+        $activity['content'] = $this->content;
 
         // generator <-- We could use this when we know a notice is created
         //               locally. Or if we know the upstream Generator.
 
-        // icon <-- I've decided to use the posting user's stream avatar here
-        //          for now (also included in the avatarLinks extension)
+        // icon <-- possibly a mini object representing verb?
 
+        // id
+        $activity['id'] = $this->id;
 
         // object
         if ($this->verb == ActivityVerb::POST && count($this->objects) == 1) {
@@ -399,9 +400,9 @@ class Activity
 
             // Instead of adding enclosures as an extension to JSON
             // Activities, it seems like we should be using the
-            // attachedObjects property of ActivityObject
+            // attachements property of ActivityObject
 
-            $attachedObjects = array();
+            $attachments = array();
 
             // XXX: OK, this is kinda cheating. We should probably figure out
             // what kind of objects these are based on mime-type and then
@@ -413,11 +414,11 @@ class Activity
 
                 if (is_string($enclosure)) {
 
-                    $attachedObjects[]['id']  = $enclosure;
+                    $attachments[]['id']  = $enclosure;
 
                 } else {
 
-                    $attachedObjects[]['id']  = $enclosure->url;
+                    $attachments[]['id']  = $enclosure->url;
 
                     $mediaLink = new ActivityStreamsMediaLink(
                         $enclosure->url,
@@ -427,16 +428,16 @@ class Activity
                         // XXX: Add 'size' as an extension to MediaLink?
                     );
 
-                    $attachedObjects[]['mediaLink'] = $mediaLink->asArray(); // extension
+                    $attachments[]['mediaLink'] = $mediaLink->asArray(); // extension
 
                     if ($enclosure->title) {
-                        $attachedObjects[]['displayName'] = $enclosure->title;
+                        $attachments[]['displayName'] = $enclosure->title;
                     }
                }
             }
 
-            if (!empty($attachedObjects)) {
-                $activity['object']['attachedObjects'] = $attachedObjects;
+            if (!empty($attachments)) {
+                $activity['object']['attachments'] = $attachments;
             }
 
         } else {
@@ -452,7 +453,8 @@ class Activity
             }
         }
 
-        $activity['postedTime'] = self::iso8601Date($this->time); // Change to exactly be RFC3339?
+        // published
+        $activity['published'] = self::iso8601Date($this->time);
 
         // provider
         $provider = array(
@@ -471,8 +473,8 @@ class Activity
         // title
         $activity['title'] = $this->title;
 
-        // updatedTime <-- Should we use this to indicate the time we received
-        //                 a remote notice? Probably not.
+        // updated <-- Optional. Should we use this to indicate the time we r
+        //             eceived a remote notice? Probably not.
 
         // verb
         //
@@ -480,6 +482,9 @@ class Activity
         // relative simple name is easier to parse
         $activity['verb'] = substr($this->verb, strrpos($this->verb, '/') + 1);
 
+        // url
+        $activity['url'] = $this->id;
+
         /* Purely extensions hereafter */
 
         $tags = array();
index 0343fa664ed374315cf9b3bea12b21e0a7132ce8..7204980d40b8b505554935a2730370179eefec34 100644 (file)
@@ -679,16 +679,19 @@ class ActivityObject
         $object = array();
 
         if (Event::handle('StartActivityObjectOutputJson', array($this, &$object))) {
-            // XXX: attachedObjects are added by Activity
+            // XXX: attachments are added by Activity
+
+            // author (Add object for author? Could be useful for repeats.)
+
+            // content (Add rendered version of the notice?)
 
             // displayName
             $object['displayName'] = $this->title;
 
-            // TODO: downstreamDuplicates
-
-            // embedCode (used for video)
+            // downstreamDuplicates
 
             // id
+            $object['id'] = $this->id;
             //
             // XXX: Should we use URL here? or a crazy tag URI?
             $object['id'] = $this->id;
@@ -736,9 +739,13 @@ class ActivityObject
             // @fixme this breaks extension URIs
             $object['type'] = substr($this->type, strrpos($this->type, '/') + 1);
 
+            // published (probably don't need. Might be useful for repeats.)
+
             // summary
             $object['summary'] = $this->summary;
 
+            // udpated (probably don't need this)
+
             // TODO: upstreamDuplicates
 
             // url (XXX: need to put the right thing here...)
@@ -753,8 +760,6 @@ class ActivityObject
                 $object[$objectName] = $props;
             }
 
-            // GeoJSON
-
             if (!empty($this->geopoint)) {
 
                 list($lat, $long) = explode(' ', $this->geopoint);
@@ -766,7 +771,7 @@ class ActivityObject
             }
 
             if (!empty($this->poco)) {
-                $object['contact'] = $this->poco->asArray();
+                $object['contact'] = array_filter($this->poco->asArray());
             }
             Event::handle('EndActivityObjectOutputJson', array($this, &$object));
         }
index 097267f504e18ceca3be22213388eeb24ddb076a..6d17075931768e062172820d8f383d0efee9abf7 100644 (file)
@@ -41,15 +41,29 @@ if (!defined('STATUSNET'))
  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  * @link     http://status.net/
  */
-class ActivityStreamJSONDocument
+class ActivityStreamJSONDocument extends JSONActivityCollection
 {
-    const CONTENT_TYPE = 'application/stream+json; charset=utf-8';
+    // Note: Lot of AS folks think the content type should be:
+    // 'application/stream+json; charset=utf-8', but this is more
+    // useful at the moment, because some programs actually understand
+    // it.
+    const CONTENT_TYPE = 'application/json; charset=utf-8';
 
     /* Top level array representing the document */
     protected $doc = array();
 
     /* The current authenticated user */
-    protected $cur = null;
+    protected $cur;
+
+    /* Title of the document */
+    protected $title;
+
+    /* Links associated with this document */
+    protected $links;
+
+    /* Count of items in this document */
+    // XXX This is cryptically referred to in the spec: "The Stream serialization MAY contain a count property."
+    protected $count;
 
     /**
      * Constructor
@@ -57,20 +71,26 @@ class ActivityStreamJSONDocument
      * @param User $cur the current authenticated user
      */
 
-    function __construct($cur = null)
+    function __construct($cur = null, $title = null, $items = null, $links = null, $url = null)
     {
+        parent::__construct($items, $url);
 
         $this->cur = $cur;
 
         /* Title of the JSON document */
-        $this->doc['title'] = null;
+        $this->title = $title;
 
-        /* Array of activity items */
-        $this->doc['items'] = array();
+        if (!empty($items)) {
+            $this->count = count($this->items);
+        }
 
         /* Array of links associated with the document */
-        $this->doc['links'] = array();
+        $this->links = empty($links) ? array() : $items;
 
+        /* URL of a document, this document? containing a list of all the items in the stream */
+        if (!empty($this->url)) {
+            $this->url = $this->url;
+        }
     }
 
     /**
@@ -81,9 +101,15 @@ class ActivityStreamJSONDocument
 
     function setTitle($title)
     {
-        $this->doc['title'] = $title;
+        $this->title = $title;
+    }
+
+    function setUrl($url)
+    {
+        $this->url = $url;
     }
 
+
     /**
      * Add more than one Item to the document
      *
@@ -116,7 +142,8 @@ class ActivityStreamJSONDocument
 
         $act          = $notice->asActivity($cur);
         $act->extra[] = $notice->noticeInfo($cur);
-        array_push($this->doc['items'], $act->asArray());
+        array_push($this->items, $act->asArray());
+        $this->count++;
     }
 
     /**
@@ -128,7 +155,7 @@ class ActivityStreamJSONDocument
     function addLink($url = null, $rel = null, $mediaType = null)
     {
         $link = new ActivityStreamsLink($url, $rel, $mediaType);
-        $this->doc['links'][] = $link->asArray();
+        array_push($this->links, $link->asArray());
     }
 
     /*
@@ -138,7 +165,13 @@ class ActivityStreamJSONDocument
      */
     function asString()
     {
-        return json_encode(array_filter($this->doc));
+        $this->doc['generator'] = 'StatusNet ' . STATUSNET_VERSION; // extension
+        $this->doc['title'] = $this->title;
+        $this->doc['url']   = $this->url;
+        $this->doc['count'] = $this->count;
+        $this->doc['items'] = $this->items;
+        $this->doc['links'] = $this->links; // extension
+        return json_encode(array_filter($this->doc)); // filter out empty elements
     }
 
 }
@@ -161,8 +194,8 @@ class ActivityStreamsMediaLink extends ActivityStreamsLink
         $url       = null,
         $width     = null,
         $height    = null,
-        $mediaType = null,
-        $rel       = null,
+        $mediaType = null, // extension
+        $rel       = null, // extension
         $duration  = null
     )
     {
@@ -183,6 +216,49 @@ class ActivityStreamsMediaLink extends ActivityStreamsLink
     }
 }
 
+/*
+ * Collection primarily as the root of an Activity Streams doc but can be used as the value
+ * of extension properties in a variety of situations.
+ *
+ * A valid Collection object serialization MUST contain at least the url or items properties.
+ */
+class JSONActivityCollection {
+
+    /* Non-negative integer specifying the total number of activities within the stream */
+    protected $totalItems;
+
+    /* An array containing a listing of Objects of any object type */
+    protected $items;
+
+    /* IRI referencing a JSON document containing the full listing of objects in the collection */
+    protected $url;
+
+    /**
+     * Constructor
+     *
+     * @param array  $items       array of activity items
+     * @param string $url         url of a doc list all the objs in the collection
+     * @param int    $totalItems  total number of items in the collection
+     */
+    function __construct($items = null, $url = null)
+    {
+        $this->items      = empty($items) ? array() : $items;
+        $this->totalItems = count($items);
+        $this->url        = $url;
+    }
+
+    /**
+     * Get the total number of items in the collection
+     *
+     * @return int total the total
+     */
+    public function getTotalItems()
+    {
+        $this->totalItems = count($items);
+        return $this->totalItems;
+    }
+}
+
 /**
  * A class for representing links in JSON Activities
  *
@@ -216,3 +292,4 @@ class ActivityStreamsLink
         return array_filter($this->linkDict);
     }
 }
+