OStatus: prep work for sending notifications on sub/unsub/join/leave/favorite/unfavorite via Salmon; needs to be completed and hooked up once feed gen is fixed.
This commit is contained in:
parent
b57e3dfae2
commit
b39047d95b
@ -755,6 +755,14 @@ class Profile extends Memcached_DataObject
|
||||
return !empty($notice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML string fragment with limited profile information
|
||||
* as an Atom <author> element.
|
||||
*
|
||||
* Assumes that Atom has been previously set up as the base namespace.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function asAtomAuthor()
|
||||
{
|
||||
$xs = new XMLStringer(true);
|
||||
@ -767,11 +775,33 @@ class Profile extends Memcached_DataObject
|
||||
return $xs->getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML string fragment with profile information as an
|
||||
* Activity Streams <activity:actor> element.
|
||||
*
|
||||
* Assumes that 'activity' namespace has been previously defined.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function asActivityActor()
|
||||
{
|
||||
return $this->asActivityNoun('actor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML string fragment with profile information as an
|
||||
* Activity Streams noun object with the given element type.
|
||||
*
|
||||
* Assumes that 'activity' namespace has been previously defined.
|
||||
*
|
||||
* @param string $element one of 'actor', 'subject', 'object', 'target'
|
||||
* @return string
|
||||
*/
|
||||
function asActivityNoun($element)
|
||||
{
|
||||
$xs = new XMLStringer(true);
|
||||
|
||||
$xs->elementStart('activity:actor');
|
||||
$xs->elementStart('activity:' . $element);
|
||||
$xs->element(
|
||||
'activity:object-type',
|
||||
null,
|
||||
@ -799,7 +829,7 @@ class Profile extends Memcached_DataObject
|
||||
''
|
||||
);
|
||||
|
||||
$xs->elementEnd('activity:actor');
|
||||
$xs->elementEnd('activity:' . $element);
|
||||
|
||||
return $xs->getString();
|
||||
}
|
||||
|
@ -299,6 +299,71 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an XML string fragment with profile information as an
|
||||
* Activity Streams noun object with the given element type.
|
||||
*
|
||||
* Assumes that 'activity' namespace has been previously defined.
|
||||
*
|
||||
* @param string $element one of 'actor', 'subject', 'object', 'target'
|
||||
* @return string
|
||||
*/
|
||||
function asActivityNoun($element)
|
||||
{
|
||||
$xs = new XMLStringer(true);
|
||||
|
||||
$avatarHref = Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||
$avatarType = 'image/png';
|
||||
if ($this->isGroup()) {
|
||||
$type = 'http://activitystrea.ms/schema/1.0/group';
|
||||
$self = $this->localGroup();
|
||||
|
||||
// @fixme put a standard getAvatar() interface on groups too
|
||||
if ($self->homepage_logo) {
|
||||
$avatarHref = $self->homepage_logo;
|
||||
$map = array('png' => 'image/png',
|
||||
'jpg' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif');
|
||||
$extension = pathinfo(parse_url($avatarHref, PHP_URL_PATH), PATHINFO_EXTENSION);
|
||||
if (isset($map[$extension])) {
|
||||
$avatarType = $map[$extension];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$type = 'http://activitystrea.ms/schema/1.0/person';
|
||||
$self = $this->localProfile();
|
||||
$avatar = $self->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
if ($avatar) {
|
||||
$avatarHref = $avatar->
|
||||
$avatarType = $avatar->mediatype;
|
||||
}
|
||||
}
|
||||
$xs->elementStart('activity:' . $element);
|
||||
$xs->element(
|
||||
'activity:object-type',
|
||||
null,
|
||||
$type
|
||||
);
|
||||
$xs->element(
|
||||
'id',
|
||||
null,
|
||||
$this->homeuri); // ?
|
||||
$xs->element('title', null, $self->getBestName());
|
||||
|
||||
$xs->element(
|
||||
'link', array(
|
||||
'type' => $avatarType,
|
||||
'href' => $avatarHref
|
||||
),
|
||||
''
|
||||
);
|
||||
|
||||
$xs->elementEnd('activity:' . $element);
|
||||
|
||||
return $xs->getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Damn dirty hack!
|
||||
*/
|
||||
@ -397,7 +462,7 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an unsubscription request to the hub for this feed.
|
||||
* Send a PuSH unsubscription request to the hub for this feed.
|
||||
* The hub will later send us a confirmation POST to /main/push/callback.
|
||||
*
|
||||
* @return bool true on success, false on failure
|
||||
@ -406,6 +471,92 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
return $this->subscribe('unsubscribe');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an Activity Streams notification to the remote Salmon endpoint,
|
||||
* if so configured.
|
||||
*
|
||||
* @param Profile $actor
|
||||
* @param $verb eg Activity::SUBSCRIBE or Activity::JOIN
|
||||
* @param $object object of the action; if null, the remote entity itself is assumed
|
||||
*/
|
||||
public function notify(Profile $actor, $verb, $object=null)
|
||||
{
|
||||
if ($object == null) {
|
||||
$object = $this;
|
||||
}
|
||||
if ($this->salmonuri) {
|
||||
$text = 'update'; // @fixme
|
||||
$id = 'tag:' . common_config('site', 'server') .
|
||||
':' . $verb .
|
||||
':' . $actor->id .
|
||||
':' . time(); // @fixme
|
||||
|
||||
$entry = new Atom10Entry();
|
||||
$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('activity:verb', null, $verb);
|
||||
$entry->raw($profile->asAtomAuthor());
|
||||
$entry->raw($profile->asActivityActor());
|
||||
$entry->raw($object->asActivityNoun('object'));
|
||||
$entry->elmentEnd('entry');
|
||||
|
||||
$feed = $this->atomFeed($actor);
|
||||
$feed->initFeed();
|
||||
$feed->addEntry($entry);
|
||||
$feed->renderEntries();
|
||||
$feed->endFeed();
|
||||
|
||||
$xml = $feed->getString();
|
||||
common_log(LOG_INFO, "Posting to Salmon endpoint $salmon: $xml");
|
||||
|
||||
$salmon = new Salmon(); // ?
|
||||
$salmon->post($this->salmonuri, $xml);
|
||||
}
|
||||
}
|
||||
|
||||
function getBestName()
|
||||
{
|
||||
if ($this->isGroup()) {
|
||||
return $this->localGroup()->getBestName();
|
||||
} else {
|
||||
return $this->localProfile()->getBestName();
|
||||
}
|
||||
}
|
||||
|
||||
function atomFeed($actor)
|
||||
{
|
||||
$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('georss', 'http://www.georss.org/georss');
|
||||
$feed->addNamespace('ostatus', 'http://ostatus.org/schema/1.0');
|
||||
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$feed->setId("tag:{$taguribase}:UserTimeline:{$actor->id}"); // ???
|
||||
|
||||
$feed->setTitle($actor->getBestName() . ' timeline'); // @fixme
|
||||
$feed->setUpdated(time());
|
||||
$feed->setPublished(time());
|
||||
|
||||
$feed->addLink(common_url('ApiTimelineUser',
|
||||
array('id' => $actor->id,
|
||||
'type' => 'atom')),
|
||||
array('rel' => 'self',
|
||||
'type' => 'application/atom+xml'));
|
||||
|
||||
$feed->addLink(common_url('userbyid',
|
||||
array('id' => $actor->id)),
|
||||
array('rel' => 'alternate',
|
||||
'type' => 'text/html'));
|
||||
|
||||
return $feed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and post notices for updates from the feed.
|
||||
* Currently assumes that all items in the feed are new,
|
||||
|
Loading…
Reference in New Issue
Block a user