forked from GNUsocial/gnu-social
Add event hooks for customizing ActivityObject output to Atom and JSON, and helpers for MicroAppPlugin.
New hooks: * StartActivityObjectOutputAtom * EndActivityObjectOutputAtom $obj ActivityObject $out XMLOutputter * StartActivityObjectOutputJson * EndActivityObjectOutputJson $obj ActivityObject &$out array
This commit is contained in:
parent
843ace580d
commit
3146c9fae8
16
EVENTS.txt
16
EVENTS.txt
@ -1115,3 +1115,19 @@ StartGroupProfileElements: Start showing stuff about the group on its profile pa
|
|||||||
EndGroupProfileElements: Start showing stuff about the group on its profile page
|
EndGroupProfileElements: Start showing stuff about the group on its profile page
|
||||||
- $action: action being executed (for output and params)
|
- $action: action being executed (for output and params)
|
||||||
- $group: group for the page
|
- $group: group for the page
|
||||||
|
|
||||||
|
StartActivityObjectOutputAtom: Called at start of Atom XML output generation for ActivityObject chunks, just inside the <activity:object>. Cancel the event to take over its output completely (you're responsible for calling the matching End event if so)
|
||||||
|
- $obj: ActivityObject
|
||||||
|
- $out: XMLOutputter to append custom output
|
||||||
|
|
||||||
|
EndActivityObjectOutputAtom: Called at end of Atom XML output generation for ActivityObject chunks, just inside the </activity:object>
|
||||||
|
- $obj: ActivityObject
|
||||||
|
- $out: XMLOutputter to append custom output
|
||||||
|
|
||||||
|
StartActivityObjectOutputJson: Called at start of JSON output generation for ActivityObject chunks: the array has not yet been filled out. Cancel the event to take over its output completely (you're responsible for calling the matching End event if so)
|
||||||
|
- $obj ActivityObject
|
||||||
|
- &$out: array to be serialized; you're free to modify it
|
||||||
|
|
||||||
|
EndActivityObjectOutputJson: Called at end of JSON output generation for ActivityObject chunks: the array has not yet been filled out.
|
||||||
|
- $obj ActivityObject
|
||||||
|
- &$out: array to be serialized; you're free to modify it
|
||||||
|
@ -533,91 +533,95 @@ class ActivityObject
|
|||||||
$xo->elementStart($tag);
|
$xo->elementStart($tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
$xo->element('activity:object-type', null, $this->type);
|
if (Event::handle('StartActivityObjectOutputAtom', array($this, $xo))) {
|
||||||
|
$xo->element('activity:object-type', null, $this->type);
|
||||||
|
|
||||||
// <author> uses URI
|
// <author> uses URI
|
||||||
|
|
||||||
if ($tag == 'author') {
|
|
||||||
$xo->element(self::URI, null, $this->id);
|
|
||||||
} else {
|
|
||||||
$xo->element(self::ID, null, $this->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->title)) {
|
|
||||||
$name = common_xml_safe_str($this->title);
|
|
||||||
if ($tag == 'author') {
|
if ($tag == 'author') {
|
||||||
// XXX: Backward compatibility hack -- atom:name should contain
|
$xo->element(self::URI, null, $this->id);
|
||||||
// full name here, instead of nickname, i.e.: $name. Change
|
|
||||||
// this in the next version.
|
|
||||||
$xo->element(self::NAME, null, $this->poco->preferredUsername);
|
|
||||||
} else {
|
} else {
|
||||||
$xo->element(self::TITLE, null, $name);
|
$xo->element(self::ID, null, $this->id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->summary)) {
|
if (!empty($this->title)) {
|
||||||
$xo->element(
|
$name = common_xml_safe_str($this->title);
|
||||||
self::SUMMARY,
|
if ($tag == 'author') {
|
||||||
null,
|
// XXX: Backward compatibility hack -- atom:name should contain
|
||||||
common_xml_safe_str($this->summary)
|
// full name here, instead of nickname, i.e.: $name. Change
|
||||||
);
|
// this in the next version.
|
||||||
}
|
$xo->element(self::NAME, null, $this->poco->preferredUsername);
|
||||||
|
} else {
|
||||||
|
$xo->element(self::TITLE, null, $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($this->content)) {
|
if (!empty($this->summary)) {
|
||||||
// XXX: assuming HTML content here
|
|
||||||
$xo->element(
|
|
||||||
ActivityUtils::CONTENT,
|
|
||||||
array('type' => 'html'),
|
|
||||||
common_xml_safe_str($this->content)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->link)) {
|
|
||||||
$xo->element(
|
|
||||||
'link',
|
|
||||||
array(
|
|
||||||
'rel' => 'alternate',
|
|
||||||
'type' => 'text/html',
|
|
||||||
'href' => $this->link
|
|
||||||
),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->type == ActivityObject::PERSON
|
|
||||||
|| $this->type == ActivityObject::GROUP) {
|
|
||||||
|
|
||||||
foreach ($this->avatarLinks as $avatar) {
|
|
||||||
$xo->element(
|
$xo->element(
|
||||||
'link', array(
|
self::SUMMARY,
|
||||||
'rel' => 'avatar',
|
null,
|
||||||
'type' => $avatar->type,
|
common_xml_safe_str($this->summary)
|
||||||
'media:width' => $avatar->width,
|
);
|
||||||
'media:height' => $avatar->height,
|
}
|
||||||
'href' => $avatar->url
|
|
||||||
|
if (!empty($this->content)) {
|
||||||
|
// XXX: assuming HTML content here
|
||||||
|
$xo->element(
|
||||||
|
ActivityUtils::CONTENT,
|
||||||
|
array('type' => 'html'),
|
||||||
|
common_xml_safe_str($this->content)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->link)) {
|
||||||
|
$xo->element(
|
||||||
|
'link',
|
||||||
|
array(
|
||||||
|
'rel' => 'alternate',
|
||||||
|
'type' => 'text/html',
|
||||||
|
'href' => $this->link
|
||||||
),
|
),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->geopoint)) {
|
if ($this->type == ActivityObject::PERSON
|
||||||
$xo->element(
|
|| $this->type == ActivityObject::GROUP) {
|
||||||
'georss:point',
|
|
||||||
null,
|
|
||||||
$this->geopoint
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->poco)) {
|
foreach ($this->avatarLinks as $avatar) {
|
||||||
$this->poco->outputTo($xo);
|
$xo->element(
|
||||||
}
|
'link', array(
|
||||||
|
'rel' => 'avatar',
|
||||||
|
'type' => $avatar->type,
|
||||||
|
'media:width' => $avatar->width,
|
||||||
|
'media:height' => $avatar->height,
|
||||||
|
'href' => $avatar->url
|
||||||
|
),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @fixme there's no way here to make a tree; elements can only contain plaintext
|
if (!empty($this->geopoint)) {
|
||||||
// @fixme these may collide with JSON extensions
|
$xo->element(
|
||||||
foreach ($this->extra as $el) {
|
'georss:point',
|
||||||
list($extraTag, $attrs, $content) = $el;
|
null,
|
||||||
$xo->element($extraTag, $attrs, $content);
|
$this->geopoint
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->poco)) {
|
||||||
|
$this->poco->outputTo($xo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @fixme there's no way here to make a tree; elements can only contain plaintext
|
||||||
|
// @fixme these may collide with JSON extensions
|
||||||
|
foreach ($this->extra as $el) {
|
||||||
|
list($extraTag, $attrs, $content) = $el;
|
||||||
|
$xo->element($extraTag, $attrs, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::handle('EndActivityObjectOutputAtom', array($this, $xo));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($tag)) {
|
if (!empty($tag)) {
|
||||||
@ -647,94 +651,96 @@ class ActivityObject
|
|||||||
{
|
{
|
||||||
$object = array();
|
$object = array();
|
||||||
|
|
||||||
// XXX: attachedObjects are added by Activity
|
if (Event::handle('StartActivityObjectOutputJson', array($this, &$object))) {
|
||||||
|
// XXX: attachedObjects are added by Activity
|
||||||
|
|
||||||
// displayName
|
// displayName
|
||||||
$object['displayName'] = $this->title;
|
$object['displayName'] = $this->title;
|
||||||
|
|
||||||
// TODO: downstreamDuplicates
|
// TODO: downstreamDuplicates
|
||||||
|
|
||||||
// embedCode (used for video)
|
// embedCode (used for video)
|
||||||
|
|
||||||
// id
|
// id
|
||||||
//
|
//
|
||||||
// XXX: Should we use URL here? or a crazy tag URI?
|
// XXX: Should we use URL here? or a crazy tag URI?
|
||||||
$object['id'] = $this->id;
|
$object['id'] = $this->id;
|
||||||
|
|
||||||
if ($this->type == ActivityObject::PERSON
|
if ($this->type == ActivityObject::PERSON
|
||||||
|| $this->type == ActivityObject::GROUP) {
|
|| $this->type == ActivityObject::GROUP) {
|
||||||
|
|
||||||
// XXX: Not sure what the best avatar is to use for the
|
// XXX: Not sure what the best avatar is to use for the
|
||||||
// author's "image". For now, I'm using the large size.
|
// author's "image". For now, I'm using the large size.
|
||||||
|
|
||||||
$avatarLarge = null;
|
$avatarLarge = null;
|
||||||
$avatarMediaLinks = array();
|
$avatarMediaLinks = array();
|
||||||
|
|
||||||
foreach ($this->avatarLinks as $a) {
|
foreach ($this->avatarLinks as $a) {
|
||||||
|
|
||||||
// Make a MediaLink for every other Avatar
|
// Make a MediaLink for every other Avatar
|
||||||
$avatar = new ActivityStreamsMediaLink(
|
$avatar = new ActivityStreamsMediaLink(
|
||||||
$a->url,
|
$a->url,
|
||||||
$a->width,
|
$a->width,
|
||||||
$a->height,
|
$a->height,
|
||||||
$a->type,
|
$a->type,
|
||||||
'avatar'
|
'avatar'
|
||||||
);
|
);
|
||||||
|
|
||||||
// Find the big avatar to use as the "image"
|
// Find the big avatar to use as the "image"
|
||||||
if ($a->height == AVATAR_PROFILE_SIZE) {
|
if ($a->height == AVATAR_PROFILE_SIZE) {
|
||||||
$imgLink = $avatar;
|
$imgLink = $avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
$avatarMediaLinks[] = $avatar->asArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
$avatarMediaLinks[] = $avatar->asArray();
|
$object['avatarLinks'] = $avatarMediaLinks; // extension
|
||||||
|
|
||||||
|
// image
|
||||||
|
$object['image'] = $imgLink->asArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
$object['avatarLinks'] = $avatarMediaLinks; // extension
|
// objectType
|
||||||
|
//
|
||||||
|
// We can probably use the whole schema URL here but probably the
|
||||||
|
// relative simple name is easier to parse
|
||||||
|
// @fixme this breaks extension URIs
|
||||||
|
$object['type'] = substr($this->type, strrpos($this->type, '/') + 1);
|
||||||
|
|
||||||
// image
|
// summary
|
||||||
$object['image'] = $imgLink->asArray();
|
$object['summary'] = $this->summary;
|
||||||
|
|
||||||
|
// TODO: upstreamDuplicates
|
||||||
|
|
||||||
|
// url (XXX: need to put the right thing here...)
|
||||||
|
$object['url'] = $this->id;
|
||||||
|
|
||||||
|
/* Extensions */
|
||||||
|
// @fixme these may collide with XML extensions
|
||||||
|
// @fixme multiple tags of same name will overwrite each other
|
||||||
|
// @fixme text content from XML extensions will be lost
|
||||||
|
foreach ($this->extra as $e) {
|
||||||
|
list($objectName, $props, $txt) = $e;
|
||||||
|
$object[$objectName] = $props;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeoJSON
|
||||||
|
|
||||||
|
if (!empty($this->geopoint)) {
|
||||||
|
|
||||||
|
list($lat, $long) = explode(' ', $this->geopoint);
|
||||||
|
|
||||||
|
$object['geopoint'] = array(
|
||||||
|
'type' => 'Point',
|
||||||
|
'coordinates' => array($lat, $long)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->poco)) {
|
||||||
|
$object['contact'] = $this->poco->asArray();
|
||||||
|
}
|
||||||
|
Event::handle('EndActivityObjectOutputJson', array($this, &$object));
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectType
|
|
||||||
//
|
|
||||||
// We can probably use the whole schema URL here but probably the
|
|
||||||
// relative simple name is easier to parse
|
|
||||||
// @fixme this breaks extension URIs
|
|
||||||
$object['type'] = substr($this->type, strrpos($this->type, '/') + 1);
|
|
||||||
|
|
||||||
// summary
|
|
||||||
$object['summary'] = $this->summary;
|
|
||||||
|
|
||||||
// TODO: upstreamDuplicates
|
|
||||||
|
|
||||||
// url (XXX: need to put the right thing here...)
|
|
||||||
$object['url'] = $this->id;
|
|
||||||
|
|
||||||
/* Extensions */
|
|
||||||
// @fixme these may collide with XML extensions
|
|
||||||
// @fixme multiple tags of same name will overwrite each other
|
|
||||||
// @fixme text content from XML extensions will be lost
|
|
||||||
foreach ($this->extra as $e) {
|
|
||||||
list($objectName, $props, $txt) = $e;
|
|
||||||
$object[$objectName] = $props;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GeoJSON
|
|
||||||
|
|
||||||
if (!empty($this->geopoint)) {
|
|
||||||
|
|
||||||
list($lat, $long) = explode(' ', $this->geopoint);
|
|
||||||
|
|
||||||
$object['geopoint'] = array(
|
|
||||||
'type' => 'Point',
|
|
||||||
'coordinates' => array($lat, $long)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->poco)) {
|
|
||||||
$object['contact'] = $this->poco->asArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_filter($object);
|
return array_filter($object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,44 @@ abstract class MicroAppPlugin extends Plugin
|
|||||||
in_array($activity->objects[0]->type, $types));
|
in_array($activity->objects[0]->type, $types));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when generating Atom XML ActivityStreams output from an
|
||||||
|
* ActivityObject belonging to this plugin. Gives the plugin
|
||||||
|
* a chance to add custom output.
|
||||||
|
*
|
||||||
|
* Note that you can only add output of additional XML elements,
|
||||||
|
* not change existing stuff here.
|
||||||
|
*
|
||||||
|
* If output is already handled by the base Activity classes,
|
||||||
|
* you can leave this base implementation as a no-op.
|
||||||
|
*
|
||||||
|
* @param ActivityObject $obj
|
||||||
|
* @param XMLOutputter $out to add elements at end of object
|
||||||
|
*/
|
||||||
|
function activityObjectOutputAtom(ActivityObject $obj, XMLOutputter $out)
|
||||||
|
{
|
||||||
|
// default is a no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when generating JSON ActivityStreams output from an
|
||||||
|
* ActivityObject belonging to this plugin. Gives the plugin
|
||||||
|
* a chance to add custom output.
|
||||||
|
*
|
||||||
|
* Modify the array contents to your heart's content, and it'll
|
||||||
|
* all get serialized out as JSON.
|
||||||
|
*
|
||||||
|
* If output is already handled by the base Activity classes,
|
||||||
|
* you can leave this base implementation as a no-op.
|
||||||
|
*
|
||||||
|
* @param ActivityObject $obj
|
||||||
|
* @param array &$out JSON-targeted array which can be modified
|
||||||
|
*/
|
||||||
|
public function activityObjectOutputJson(ActivityObject $obj, array &$out)
|
||||||
|
{
|
||||||
|
// default is a no-op
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a notice is deleted, delete the related objects
|
* When a notice is deleted, delete the related objects
|
||||||
* by calling the overridable $this->deleteRelated().
|
* by calling the overridable $this->deleteRelated().
|
||||||
@ -439,6 +477,46 @@ abstract class MicroAppPlugin extends Plugin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler gives the plugin a chance to add custom
|
||||||
|
* Atom XML ActivityStreams output from a previously filled-out
|
||||||
|
* ActivityObject.
|
||||||
|
*
|
||||||
|
* The atomOutput method is called if it's one of
|
||||||
|
* our matching types.
|
||||||
|
*
|
||||||
|
* @param ActivityObject $obj
|
||||||
|
* @param XMLOutputter $out to add elements at end of object
|
||||||
|
* @return boolean hook return value
|
||||||
|
*/
|
||||||
|
function onEndActivityObjectOutputAtom(ActivityObject $obj, XMLOutputter $out)
|
||||||
|
{
|
||||||
|
if (in_array($obj->type, $this->types())) {
|
||||||
|
$this->activityObjectOutputAtom($obj, $out);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler gives the plugin a chance to add custom
|
||||||
|
* JSON ActivityStreams output from a previously filled-out
|
||||||
|
* ActivityObject.
|
||||||
|
*
|
||||||
|
* The activityObjectOutputJson method is called if it's one of
|
||||||
|
* our matching types.
|
||||||
|
*
|
||||||
|
* @param ActivityObject $obj
|
||||||
|
* @param array &$out JSON-targeted array which can be modified
|
||||||
|
* @return boolean hook return value
|
||||||
|
*/
|
||||||
|
function onEndActivityObjectOutputJson(ActivityObject $obj, array &$out)
|
||||||
|
{
|
||||||
|
if (in_array($obj->type, $this->types())) {
|
||||||
|
$this->activityObjectOutputJson($obj, &$out);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function onStartShowEntryForms(&$tabs)
|
function onStartShowEntryForms(&$tabs)
|
||||||
{
|
{
|
||||||
$tabs[$this->tag()] = $this->appTitle();
|
$tabs[$this->tag()] = $this->appTitle();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user