if (!empty($this->formatted)) {
$xs = new XMLStringer(true);
$xs->elementStart('poco:address');
- $xs->element('poco:formatted', null, $this->formatted);
+ $xs->element('poco:formatted', null, common_xml_safe_str($this->formatted));
$xs->elementEnd('poco:address');
return $xs->getString();
}
return $poco;
}
+ function fromGroup($group)
+ {
+ if (empty($group)) {
+ return null;
+ }
+
+ $poco = new PoCo();
+
+ $poco->preferredUsername = $group->nickname;
+ $poco->displayName = $group->getBestName();
+
+ $poco->note = $group->description;
+
+ $paddy = new PoCoAddress();
+ $paddy->formatted = $group->location;
+ $poco->address = $paddy;
+
+ if (!empty($group->homepage)) {
+ array_push(
+ $poco->urls,
+ new PoCoURL(
+ 'homepage',
+ $group->homepage,
+ true
+ )
+ );
+ }
+
+ return $poco;
+ }
+
function getPrimaryURL()
{
foreach ($this->urls as $url) {
);
if (!empty($this->note)) {
- $xs->element('poco:note', null, $this->note);
+ $xs->element('poco:note', null, common_xml_safe_str($this->note));
}
if (!empty($this->address)) {
static function getLink(DOMNode $element, $rel, $type=null)
{
- $links = $element->getElementsByTagnameNS(self::ATOM, self::LINK);
+ $els = $element->childNodes;
- foreach ($links as $link) {
+ foreach ($els as $link) {
+ if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) {
- $linkRel = $link->getAttribute(self::REL);
- $linkType = $link->getAttribute(self::TYPE);
+ $linkRel = $link->getAttribute(self::REL);
+ $linkType = $link->getAttribute(self::TYPE);
- if ($linkRel == $rel &&
- (is_null($type) || $linkType == $type)) {
- return $link->getAttribute(self::HREF);
+ if ($linkRel == $rel &&
+ (is_null($type) || $linkType == $type)) {
+ return $link->getAttribute(self::HREF);
+ }
}
}
return null;
}
+ static function getLinks(DOMNode $element, $rel, $type=null)
+ {
+ $els = $element->childNodes;
+ $out = array();
+
+ foreach ($els as $link) {
+ if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) {
+
+ $linkRel = $link->getAttribute(self::REL);
+ $linkType = $link->getAttribute(self::TYPE);
+
+ if ($linkRel == $rel &&
+ (is_null($type) || $linkType == $type)) {
+ $out[] = $link;
+ }
+ }
+ }
+
+ return $out;
+ }
+
/**
* Gets the first child element with the given tag
*
// slavishly following http://atompub.org/rfc4287.html#rfc.section.4.1.3.3
- if ($type == 'text') {
+ if (empty($type) || $type == 'text') {
return $contentEl->textContent;
} else if ($type == 'html') {
$text = $contentEl->textContent;
return htmlspecialchars_decode($text, ENT_QUOTES);
} else if ($type == 'xhtml') {
- $divEl = ActivityUtils::child($contentEl, 'div');
+ $divEl = ActivityUtils::child($contentEl, 'div', 'http://www.w3.org/1999/xhtml');
if (empty($divEl)) {
return null;
}
$text .= $doc->saveXML($child);
}
return trim($text);
- } else if (in_array(array('text/xml', 'application/xml'), $type) ||
+ } else if (in_array($type, array('text/xml', 'application/xml')) ||
preg_match('#(+|/)xml$#', $type)) {
throw new ClientException(_("Can't handle embedded XML content yet."));
} else if (strncasecmp($type, 'text/', 5)) {
}
}
+// XXX: Arg! This wouldn't be necessary if we used Avatars conistently
+class AvatarLink
+{
+ public $url;
+ public $type;
+ public $size;
+ public $width;
+ public $height;
+
+ function __construct($element=null)
+ {
+ if ($element) {
+ // @fixme use correct namespaces
+ $this->url = $element->getAttribute('href');
+ $this->type = $element->getAttribute('type');
+ $width = $element->getAttribute('media:width');
+ if ($width != null) {
+ $this->width = intval($width);
+ }
+ $height = $element->getAttribute('media:height');
+ if ($height != null) {
+ $this->height = intval($height);
+ }
+ }
+ }
+
+ static function fromAvatar($avatar)
+ {
+ if (empty($avatar)) {
+ return null;
+ }
+ $alink = new AvatarLink();
+ $alink->type = $avatar->mediatype;
+ $alink->height = $avatar->height;
+ $alink->width = $avatar->width;
+ $alink->url = $avatar->displayUrl();
+ return $alink;
+ }
+
+ static function fromFilename($filename, $size)
+ {
+ $alink = new AvatarLink();
+ $alink->url = $filename;
+ $alink->height = $size;
+ if (!empty($filename)) {
+ $alink->width = $size;
+ $alink->type = self::mediatype($filename);
+ } else {
+ $alink->url = User_group::defaultLogo($size);
+ $alink->type = 'image/png';
+ }
+ return $alink;
+ }
+
+ // yuck!
+ static function mediatype($filename) {
+ $ext = strtolower(end(explode('.', $filename)));
+ if ($ext == 'jpeg') {
+ $ext = 'jpg';
+ }
+ // hope we don't support any others
+ $types = array('png', 'gif', 'jpg', 'jpeg');
+ if (in_array($ext, $types)) {
+ return 'image/' . $ext;
+ }
+ return null;
+ }
+}
+
/**
* A noun-ish thing in the activity universe
*
public $content;
public $link;
public $source;
- public $avatar;
+ public $avatarLinks = array();
public $geopoint;
public $poco;
public $displayName;
if ($this->type == self::PERSON || $this->type == self::GROUP) {
$this->displayName = $this->title;
- // @fixme we may have multiple avatars with different resolutions specified
- $this->avatar = ActivityUtils::getLink($element, 'avatar');
+ $photos = ActivityUtils::getLinks($element, 'photo');
+ if (count($photos)) {
+ foreach ($photos as $link) {
+ $this->avatarLinks[] = new AvatarLink($link);
+ }
+ } else {
+ $avatars = ActivityUtils::getLinks($element, 'avatar');
+ foreach ($avatars as $link) {
+ $this->avatarLinks[] = new AvatarLink($link);
+ }
+ }
$this->poco = new PoCo($element);
}
$object->id = $profile->getUri();
$object->title = $profile->getBestName();
$object->link = $profile->profileurl;
- $object->avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
+
+ $orig = $profile->getOriginalAvatar();
+
+ if (!empty($orig)) {
+ $object->avatarLinks[] = AvatarLink::fromAvatar($orig);
+ }
+
+ $sizes = array(
+ AVATAR_PROFILE_SIZE,
+ AVATAR_STREAM_SIZE,
+ AVATAR_MINI_SIZE
+ );
+
+ foreach ($sizes as $size) {
+
+ $alink = null;
+ $avatar = $profile->getAvatar($size);
+
+ if (!empty($avatar)) {
+ $alink = AvatarLink::fromAvatar($avatar);
+ } else {
+ $alink = new AvatarLink();
+ $alink->type = 'image/png';
+ $alink->height = $size;
+ $alink->width = $size;
+ $alink->url = Avatar::defaultImage($size);
+ }
+
+ $object->avatarLinks[] = $alink;
+ }
if (isset($profile->lat) && isset($profile->lon)) {
- $object->geopoint = (float)$profile->lat . ' ' . (float)$profile->lon;
+ $object->geopoint = (float)$profile->lat
+ . ' ' . (float)$profile->lon;
}
$object->poco = PoCo::fromProfile($profile);
return $object;
}
+ static function fromGroup($group)
+ {
+ $object = new ActivityObject();
+
+ $object->type = ActivityObject::GROUP;
+ $object->id = $group->getUri();
+ $object->title = $group->getBestName();
+ $object->link = $group->getUri();
+
+ $object->avatarLinks[] = AvatarLink::fromFilename(
+ $group->homepage_logo,
+ AVATAR_PROFILE_SIZE
+ );
+
+ $object->avatarLinks[] = AvatarLink::fromFilename(
+ $group->stream_logo,
+ AVATAR_STREAM_SIZE
+ );
+
+ $object->avatarLinks[] = AvatarLink::fromFilename(
+ $group->mini_logo,
+ AVATAR_MINI_SIZE
+ );
+
+ $object->poco = PoCo::fromGroup($group);
+
+ return $object;
+ }
+
function asString($tag='activity:object')
{
$xs = new XMLStringer(true);
$xs->element(self::ID, null, $this->id);
if (!empty($this->title)) {
- $xs->element(self::TITLE, null, $this->title);
+ $xs->element(
+ self::TITLE,
+ null,
+ common_xml_safe_str($this->title)
+ );
}
if (!empty($this->summary)) {
- $xs->element(self::SUMMARY, null, $this->summary);
+ $xs->element(
+ self::SUMMARY,
+ null,
+ common_xml_safe_str($this->summary)
+ );
}
if (!empty($this->content)) {
// XXX: assuming HTML content here
- $xs->element(ActivityUtils::CONTENT, array('type' => 'html'), $this->content);
+ $xs->element(
+ ActivityUtils::CONTENT,
+ array('type' => 'html'),
+ common_xml_safe_str($this->content)
+ );
}
if (!empty($this->link)) {
if ($this->type == ActivityObject::PERSON
|| $this->type == ActivityObject::GROUP) {
- $xs->element(
- 'link', array(
- 'type' => empty($this->avatar) ? 'image/png' : $this->avatar->mediatype,
- 'rel' => 'avatar',
- 'href' => empty($this->avatar)
- ? Avatar::defaultImage(AVATAR_PROFILE_SIZE)
- : $this->avatar->displayUrl()
- ),
- null
- );
+
+ foreach ($this->avatarLinks as $avatar) {
+ $xs->element(
+ 'link', array(
+ 'rel' => 'avatar',
+ 'type' => $avatar->type,
+ 'media:width' => $avatar->width,
+ 'media:height' => $avatar->height,
+ 'href' => $avatar->url
+ ),
+ null
+ );
+ }
}
if (!empty($this->geopoint)) {
public $content; // HTML content of activity
public $id; // ID of the activity
public $title; // title of the activity
+ public $categories = array(); // list of AtomCategory objects
+ public $enclosures = array(); // list of enclosure URL references
/**
* Turns a regular old Atom <entry> into a magical activity
}
$this->entry = $entry;
+
+ // Insist on a feed's root DOMElement; don't allow a DOMDocument
+ if ($feed instanceof DOMDocument) {
+ throw new ClientException(
+ _("Expecting a root feed element but got a whole XML document.")
+ );
+ }
+
$this->feed = $feed;
$pubEl = $this->_child($entry, self::PUBLISHED, self::ATOM);
$this->summary = ActivityUtils::childContent($entry, 'summary');
$this->id = ActivityUtils::childContent($entry, 'id');
$this->content = ActivityUtils::getContent($entry);
+
+ $catEls = $entry->getElementsByTagNameNS(self::ATOM, 'category');
+ if ($catEls) {
+ for ($i = 0; $i < $catEls->length; $i++) {
+ $catEl = $catEls->item($i);
+ $this->categories[] = new AtomCategory($catEl);
+ }
+ }
+
+ foreach (ActivityUtils::getLinks($entry, 'enclosure') as $link) {
+ $this->enclosures[] = $link->getAttribute('href');
+ }
}
/**
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/',
'xmlns:georss' => 'http://www.georss.org/georss',
'xmlns:ostatus' => 'http://ostatus.org/schema/1.0',
- 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0');
+ 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0',
+ 'xmlns:media' => 'http://purl.org/syndication/atommedia');
} else {
$attrs = array();
}
$xs->raw($this->target->asString('activity:target'));
}
+ foreach ($this->categories as $cat) {
+ $xs->raw($cat->asString());
+ }
+
$xs->elementEnd('entry');
return $xs->getString();
{
return ActivityUtils::child($element, $tag, $namespace);
}
-}
\ No newline at end of file
+}
+
+class AtomCategory
+{
+ public $term;
+ public $scheme;
+ public $label;
+
+ function __construct($element=null)
+ {
+ if ($element && $element->attributes) {
+ $this->term = $this->extract($element, 'term');
+ $this->scheme = $this->extract($element, 'scheme');
+ $this->label = $this->extract($element, 'label');
+ }
+ }
+
+ protected function extract($element, $attrib)
+ {
+ $node = $element->attributes->getNamedItemNS(Activity::ATOM, $attrib);
+ if ($node) {
+ return trim($node->textContent);
+ }
+ $node = $element->attributes->getNamedItem($attrib);
+ if ($node) {
+ return trim($node->textContent);
+ }
+ return null;
+ }
+
+ function asString()
+ {
+ $attribs = array();
+ if ($this->term !== null) {
+ $attribs['term'] = $this->term;
+ }
+ if ($this->scheme !== null) {
+ $attribs['scheme'] = $this->scheme;
+ }
+ if ($this->label !== null) {
+ $attribs['label'] = $this->label;
+ }
+ $xs = new XMLStringer();
+ $xs->element('category', $attribs);
+ return $xs->asString();
+ }
+}