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;
}
}
// 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) {
// 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
if (is_string($enclosure)) {
- $attachedObjects[]['id'] = $enclosure;
+ $attachments[]['id'] = $enclosure;
} else {
- $attachedObjects[]['id'] = $enclosure->url;
+ $attachments[]['id'] = $enclosure->url;
$mediaLink = new ActivityStreamsMediaLink(
$enclosure->url,
// 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 {
}
}
- $activity['postedTime'] = self::iso8601Date($this->time); // Change to exactly be RFC3339?
+ // published
+ $activity['published'] = self::iso8601Date($this->time);
// provider
$provider = array(
// 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
//
// 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();
$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;
// @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...)
$object[$objectName] = $props;
}
- // GeoJSON
-
if (!empty($this->geopoint)) {
list($lat, $long) = explode(' ', $this->geopoint);
}
if (!empty($this->poco)) {
- $object['contact'] = $this->poco->asArray();
+ $object['contact'] = array_filter($this->poco->asArray());
}
Event::handle('EndActivityObjectOutputJson', array($this, &$object));
}
* @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
* @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;
+ }
}
/**
function setTitle($title)
{
- $this->doc['title'] = $title;
+ $this->title = $title;
+ }
+
+ function setUrl($url)
+ {
+ $this->url = $url;
}
+
/**
* Add more than one Item to the document
*
$act = $notice->asActivity($cur);
$act->extra[] = $notice->noticeInfo($cur);
- array_push($this->doc['items'], $act->asArray());
+ array_push($this->items, $act->asArray());
+ $this->count++;
}
/**
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());
}
/*
*/
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
}
}
$url = null,
$width = null,
$height = null,
- $mediaType = null,
- $rel = null,
+ $mediaType = null, // extension
+ $rel = null, // extension
$duration = null
)
{
}
}
+/*
+ * 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
*
return array_filter($this->linkDict);
}
}
+