function outputTo($xo) { if (!empty($this->formatted)) { $xo->elementStart('poco:address'); $xo->element('poco:formatted', null, common_xml_safe_str($this->formatted)); $xo->elementEnd('poco:address'); } }
function asString() { if (!empty($this->formatted)) { $xs = new XMLStringer(true); $xs->elementStart('poco:address'); $xs->element('poco:formatted', null, common_xml_safe_str($this->formatted)); $xs->elementEnd('poco:address'); return $xs->getString(); } return null; }
/** * Convert a notice into an activity for export. * * @param Profile $scoped The currently logged in/scoped profile * * @return Activity activity object representing this Notice. */ function asActivity(Profile $scoped = null) { $act = self::cacheGet(Cache::codeKey('notice:as-activity:' . $this->id)); if ($act instanceof Activity) { return $act; } $act = new Activity(); if (Event::handle('StartNoticeAsActivity', array($this, $act, $scoped))) { $act->id = $this->uri; $act->time = strtotime($this->created); try { $act->link = $this->getUrl(); } catch (InvalidUrlException $e) { // The notice is probably a share or similar, which don't // have a representational URL of their own. } $act->content = common_xml_safe_str($this->getRendered()); $profile = $this->getProfile(); $act->actor = $profile->asActivityObject(); $act->actor->extra[] = $profile->profileInfo($scoped); $act->verb = $this->verb; if (!$this->repeat_of) { $act->objects[] = $this->asActivityObject(); } // XXX: should this be handled by default processing for object entry? // Categories $tags = $this->getTags(); foreach ($tags as $tag) { $cat = new AtomCategory(); $cat->term = $tag; $act->categories[] = $cat; } // Enclosures // XXX: use Atom Media and/or File activity objects instead $attachments = $this->attachments(); foreach ($attachments as $attachment) { // Include local attachments in Activity if (!empty($attachment->filename)) { $act->enclosures[] = $attachment->getEnclosure(); } } $ctx = new ActivityContext(); try { $reply = $this->getParent(); $ctx->replyToID = $reply->getUri(); $ctx->replyToUrl = $reply->getUrl(true); // true for fallback to local URL, less messy } catch (NoParentNoticeException $e) { // This is not a reply to something } catch (NoResultException $e) { // Parent notice was probably deleted } try { $ctx->location = Notice_location::locFromStored($this); } catch (ServerException $e) { $ctx->location = null; } $conv = null; if (!empty($this->conversation)) { $conv = Conversation::getKV('id', $this->conversation); if ($conv instanceof Conversation) { $ctx->conversation = $conv->uri; } } // This covers the legacy getReplies and getGroups too which get their data // from entries stored via Notice::saveNew (which we want to move away from)... foreach ($this->getAttentionProfiles() as $target) { // User and group profiles which get the attention of this notice $ctx->attention[$target->getUri()] = $target->getObjectType(); } switch ($this->scope) { case Notice::PUBLIC_SCOPE: $ctx->attention[ActivityContext::ATTN_PUBLIC] = ActivityObject::COLLECTION; break; case Notice::FOLLOWER_SCOPE: $surl = common_local_url("subscribers", array('nickname' => $profile->nickname)); $ctx->attention[$surl] = ActivityObject::COLLECTION; break; } $act->context = $ctx; $source = $this->getSource(); if ($source instanceof Notice_source) { $act->generator = ActivityObject::fromNoticeSource($source); } // Source $atom_feed = $profile->getAtomFeed(); if (!empty($atom_feed)) { $act->source = new ActivitySource(); // XXX: we should store the actual feed ID $act->source->id = $atom_feed; // XXX: we should store the actual feed title $act->source->title = $profile->getBestName(); $act->source->links['alternate'] = $profile->profileurl; $act->source->links['self'] = $atom_feed; $act->source->icon = $profile->avatarUrl(AVATAR_PROFILE_SIZE); $notice = $profile->getCurrentNotice(); if ($notice instanceof Notice) { $act->source->updated = self::utcDate($notice->created); } $user = User::getKV('id', $profile->id); if ($user instanceof User) { $act->source->links['license'] = common_config('license', 'url'); } } if ($this->isLocal()) { $act->selfLink = common_local_url('ApiStatusesShow', array('id' => $this->id, 'format' => 'atom')); $act->editLink = $act->selfLink; } Event::handle('EndNoticeAsActivity', array($this, $act, $scoped)); } self::cacheSet(Cache::codeKey('notice:as-activity:' . $this->id), $act); return $act; }
function rssDirectMessageArray($message) { $entry = array(); $from = $message->getFrom(); $entry['title'] = sprintf('Message from %1$s to %2$s', $from->nickname, $message->getTo()->nickname); $entry['content'] = common_xml_safe_str($message->rendered); $entry['link'] = common_local_url('showmessage', array('message' => $message->id)); $entry['published'] = common_date_iso8601($message->created); $taguribase = TagURI::base(); $entry['id'] = "tag:{$taguribase}:{$entry['link']}"; $entry['updated'] = $entry['published']; $entry['author-name'] = $from->getBestName(); $entry['author-uri'] = $from->homepage; $entry['avatar'] = $from->avatarUrl(AVATAR_STREAM_SIZE); try { $avatar = $from->getAvatar(AVATAR_STREAM_SIZE); $entry['avatar-type'] = $avatar->mediatype; } catch (Exception $e) { $entry['avatar-type'] = 'image/png'; } // RSS item specific $entry['description'] = $entry['content']; $entry['pubDate'] = common_date_rfc2822($message->created); $entry['guid'] = $entry['link']; return $entry; }
function outputTo($xo, $tag = 'activity:object') { if (!empty($tag)) { $xo->elementStart($tag); } if (Event::handle('StartActivityObjectOutputAtom', array($this, $xo))) { $xo->element('activity:object-type', null, $this->type); // <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') { // XXX: Backward compatibility hack -- atom:name should contain // 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->summary)) { $xo->element(self::SUMMARY, null, common_xml_safe_str($this->summary)); } 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); } if (!empty($this->owner)) { $owner = $this->owner->asActivityNoun(self::AUTHOR); $xo->raw($owner); } if ($this->type == ActivityObject::PERSON || $this->type == ActivityObject::GROUP) { foreach ($this->avatarLinks as $alink) { $xo->element('link', array('rel' => 'avatar', 'type' => $alink->type, 'media:width' => $alink->width, 'media:height' => $alink->height, 'href' => $alink->url), null); } } if (!empty($this->geopoint)) { $xo->element('georss:point', null, $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) = array_pad($el, 3, null); $xo->element($extraTag, $attrs, $content); } Event::handle('EndActivityObjectOutputAtom', array($this, $xo)); } if (!empty($tag)) { $xo->elementEnd($tag); } return; }
/** * Build an Atom entry similar to search.twitter.com's based on * a given notice * * @param Notice $notice the notice to use * * @return void */ function showEntry($notice) { $server = common_config('site', 'server'); $profile = $notice->getProfile(); $nurl = common_local_url('shownotice', array('notice' => $notice->id)); $this->elementStart('entry'); $taguribase = TagURI::base(); $this->element('id', null, "tag:{$taguribase}:{$notice->id}"); $this->element('published', null, common_date_w3dtf($notice->created)); $this->element('link', array('type' => 'text/html', 'rel' => 'alternate', 'href' => $nurl)); $this->element('title', null, common_xml_safe_str(trim($notice->content))); $this->element('content', array('type' => 'html'), $notice->rendered); $this->element('updated', null, common_date_w3dtf($notice->created)); $this->element('link', array('type' => 'image/png', 'rel' => 'related', 'href' => $profile->avatarUrl())); // TODO: Here is where we'd put in a link to an atom feed for threads $this->element("twitter:source", null, htmlentities($this->sourceLink($notice->source))); $this->elementStart('author'); $name = $profile->nickname; if ($profile->fullname) { $name .= ' (' . $profile->fullname . ')'; } $this->element('name', null, $name); $this->element('uri', null, common_profile_uri($profile)); $this->elementEnd('author'); $this->elementEnd('entry'); }
function asString() { $xs = new XMLStringer(true); $xs->element('poco:preferredUsername', null, $this->preferredUsername); $xs->element('poco:displayName', null, $this->displayName); if (!empty($this->note)) { $xs->element('poco:note', null, common_xml_safe_str($this->note)); } if (!empty($this->address)) { $xs->raw($this->address->asString()); } foreach ($this->urls as $url) { $xs->raw($url->asString()); } return $xs->getString(); }
/** * Convert a notice into an activity for export. * * @param User $cur Current user * * @return Activity activity object representing this Notice. */ function asActivity($cur) { $act = self::cacheGet(Cache::codeKey('notice:as-activity:' . $this->id)); if (!empty($act)) { return $act; } $act = new Activity(); if (Event::handle('StartNoticeAsActivity', array($this, &$act))) { $profile = $this->getProfile(); $act->actor = ActivityObject::fromProfile($profile); $act->actor->extra[] = $profile->profileInfo($cur); $act->verb = ActivityVerb::POST; $act->objects[] = ActivityObject::fromNotice($this); // XXX: should this be handled by default processing for object entry? $act->time = strtotime($this->created); $act->link = $this->bestUrl(); $act->content = common_xml_safe_str($this->rendered); $act->id = $this->uri; $act->title = common_xml_safe_str($this->content); // Categories $tags = $this->getTags(); foreach ($tags as $tag) { $cat = new AtomCategory(); $cat->term = $tag; $act->categories[] = $cat; } // Enclosures // XXX: use Atom Media and/or File activity objects instead $attachments = $this->attachments(); foreach ($attachments as $attachment) { $enclosure = $attachment->getEnclosure(); if ($enclosure) { $act->enclosures[] = $enclosure; } } $ctx = new ActivityContext(); if (!empty($this->reply_to)) { $reply = Notice::staticGet('id', $this->reply_to); if (!empty($reply)) { $ctx->replyToID = $reply->uri; $ctx->replyToUrl = $reply->bestUrl(); } } $ctx->location = $this->getLocation(); $conv = null; if (!empty($this->conversation)) { $conv = Conversation::staticGet('id', $this->conversation); if (!empty($conv)) { $ctx->conversation = $conv->uri; } } $reply_ids = $this->getReplies(); foreach ($reply_ids as $id) { $profile = Profile::staticGet('id', $id); if (!empty($profile)) { $ctx->attention[] = $profile->getUri(); } } $groups = $this->getGroups(); foreach ($groups as $group) { $ctx->attention[] = $group->getUri(); } // XXX: deprecated; use ActivityVerb::SHARE instead $repeat = null; if (!empty($this->repeat_of)) { $repeat = Notice::staticGet('id', $this->repeat_of); $ctx->forwardID = $repeat->uri; $ctx->forwardUrl = $repeat->bestUrl(); } $act->context = $ctx; // Source $atom_feed = $profile->getAtomFeed(); if (!empty($atom_feed)) { $act->source = new ActivitySource(); // XXX: we should store the actual feed ID $act->source->id = $atom_feed; // XXX: we should store the actual feed title $act->source->title = $profile->getBestName(); $act->source->links['alternate'] = $profile->profileurl; $act->source->links['self'] = $atom_feed; $act->source->icon = $profile->avatarUrl(AVATAR_PROFILE_SIZE); $notice = $profile->getCurrentNotice(); if (!empty($notice)) { $act->source->updated = self::utcDate($notice->created); } $user = User::staticGet('id', $profile->id); if (!empty($user)) { $act->source->links['license'] = common_config('license', 'url'); } } if ($this->isLocal()) { $act->selfLink = common_local_url('ApiStatusesShow', array('id' => $this->id, 'format' => 'atom')); $act->editLink = $act->selfLink; } Event::handle('EndNoticeAsActivity', array($this, &$act)); } self::cacheSet(Cache::codeKey('notice:as-activity:' . $this->id), $act); return $act; }
function showItem($notice) { $profile = Profile::staticGet($notice->profile_id); $nurl = common_local_url('shownotice', array('notice' => $notice->id)); $creator_uri = common_profile_uri($profile); $this->elementStart('item', array('rdf:about' => $notice->uri, 'rdf:type' => 'http://rdfs.org/sioc/types#MicroblogPost')); $title = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content)); $this->element('title', null, $title); $this->element('link', null, $nurl); $this->element('description', null, $profile->nickname . "'s status on " . common_exact_date($notice->created)); if ($notice->rendered) { $this->element('content:encoded', null, common_xml_safe_str($notice->rendered)); } $this->element('dc:date', null, common_date_w3dtf($notice->created)); $this->element('dc:creator', null, $profile->fullname ? $profile->fullname : $profile->nickname); $this->element('foaf:maker', array('rdf:resource' => $creator_uri)); $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri . '#acct')); $location = $notice->getLocation(); if ($location && isset($location->lat) && isset($location->lon)) { $location_uri = $location->getRdfURL(); $attrs = array('geo:lat' => $location->lat, 'geo:long' => $location->lon); if (strlen($location_uri)) { $attrs['rdf:resource'] = $location_uri; } $this->element('statusnet:origin', $attrs); } $this->element('statusnet:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); if ($notice->reply_to) { $replyurl = common_local_url('shownotice', array('notice' => $notice->reply_to)); $this->element('sioc:reply_of', array('rdf:resource' => $replyurl)); } if (!empty($notice->conversation)) { $conversationurl = common_local_url('conversation', array('id' => $notice->conversation)); $this->element('sioc:has_discussion', array('rdf:resource' => $conversationurl)); } $attachments = $notice->attachments(); if ($attachments) { foreach ($attachments as $attachment) { $enclosure = $attachment->getEnclosure(); if ($enclosure) { $attribs = array('rdf:resource' => $enclosure->url); if ($enclosure->title) { $attribs['dc:title'] = $enclosure->title; } if ($enclosure->modified) { $attribs['dc:date'] = common_date_w3dtf($enclosure->modified); } if ($enclosure->size) { $attribs['enc:length'] = $enclosure->size; } if ($enclosure->mimetype) { $attribs['enc:type'] = $enclosure->mimetype; } $this->element('enc:enclosure', $attribs); } $this->element('sioc:links_to', array('rdf:resource' => $attachment->url)); } } $tag = new Notice_tag(); $tag->notice_id = $notice->id; if ($tag->find()) { $entry['tags'] = array(); while ($tag->fetch()) { $tagpage = common_local_url('tag', array('tag' => $tag->tag)); if (in_array($tag, $this->tags_already_output)) { $this->element('ctag:tagged', array('rdf:resource' => $tagpage . '#concept')); continue; } $tagrss = common_local_url('tagrss', array('tag' => $tag->tag)); $this->elementStart('ctag:tagged'); $this->elementStart('ctag:Tag', array('rdf:about' => $tagpage . '#concept', 'ctag:label' => $tag->tag)); $this->element('foaf:page', array('rdf:resource' => $tagpage)); $this->element('rdfs:seeAlso', array('rdf:resource' => $tagrss)); $this->elementEnd('ctag:Tag'); $this->elementEnd('ctag:tagged'); $this->tags_already_output[] = $tag->tag; } } $this->elementEnd('item'); $this->creators[$creator_uri] = $profile; }
function showItem($notice) { $profile = Profile::staticGet($notice->profile_id); $nurl = common_local_url('shownotice', array('notice' => $notice->id)); $creator_uri = common_profile_uri($profile); $this->elementStart('item', array('rdf:about' => $notice->uri)); $title = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content)); $this->element('title', null, $title); $this->element('link', null, $nurl); $this->element('description', null, $profile->nickname . "'s status on " . common_exact_date($notice->created)); $this->element('dc:date', null, common_date_w3dtf($notice->created)); $this->element('dc:creator', null, $profile->fullname ? $profile->fullname : $profile->nickname); $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri)); $this->element('laconica:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); $this->elementEnd('item'); $this->creators[$creator_uri] = $profile; }
/** * Convert a notice into an activity for export. * * @param User $cur Current user * * @return Activity activity object representing this Notice. */ function asActivity($cur) { $act = self::cacheGet(Cache::codeKey('notice:as-activity:' . $this->id)); if (!empty($act)) { return $act; } $act = new Activity(); if (Event::handle('StartNoticeAsActivity', array($this, &$act))) { $act->id = TagURI::mint("post:" . $this->id); $act->time = strtotime($this->created); $act->content = common_xml_safe_str($this->rendered); $profile = $this->getProfile(); $act->actor = ActivityObject::fromProfile($profile); $act->actor->extra[] = $profile->profileInfo($cur); $act->verb = $this->verb; if ($this->repeat_of) { $repeated = Notice::staticGet('id', $this->repeat_of); if (!empty($repeated)) { $act->objects[] = $repeated->asActivity($cur); } } else { $act->objects[] = ActivityObject::fromNotice($this); } // XXX: should this be handled by default processing for object entry? // Categories $tags = $this->getTags(); foreach ($tags as $tag) { $cat = new AtomCategory(); $cat->term = $tag; $act->categories[] = $cat; } // Enclosures // XXX: use Atom Media and/or File activity objects instead $attachments = $this->attachments(); foreach ($attachments as $attachment) { // Save local attachments if (!empty($attachment->filename)) { $act->attachments[] = ActivityObject::fromFile($attachment); } } $ctx = new ActivityContext(); if (!empty($this->reply_to)) { $reply = Notice::staticGet('id', $this->reply_to); if (!empty($reply)) { $ctx->replyToID = $reply->uri; $ctx->replyToUrl = $reply->bestUrl(); } } $ctx->location = $this->getLocation(); $conv = null; if (!empty($this->conversation)) { $conv = Conversation::staticGet('id', $this->conversation); if (!empty($conv)) { $ctx->conversation = $conv->uri; } } $reply_ids = $this->getReplies(); foreach ($reply_ids as $id) { $rprofile = Profile::staticGet('id', $id); if (!empty($rprofile)) { $ctx->attention[] = $rprofile->getUri(); $ctx->attentionType[$rprofile->getUri()] = ActivityObject::PERSON; } } $groups = $this->getGroups(); foreach ($groups as $group) { $ctx->attention[] = $group->getUri(); $ctx->attentionType[$group->getUri()] = ActivityObject::GROUP; } switch ($this->scope) { case Notice::PUBLIC_SCOPE: $ctx->attention[] = "http://activityschema.org/collection/public"; $ctx->attentionType["http://activityschema.org/collection/public"] = ActivityObject::COLLECTION; break; case Notice::FOLLOWER_SCOPE: $surl = common_local_url("subscribers", array('nickname' => $profile->nickname)); $ctx->attention[] = $surl; $ctx->attentionType[$surl] = ActivityObject::COLLECTION; break; } // XXX: deprecated; use ActivityVerb::SHARE instead $repeat = null; if (!empty($this->repeat_of)) { $repeat = Notice::staticGet('id', $this->repeat_of); if (!empty($repeat)) { $ctx->forwardID = $repeat->uri; $ctx->forwardUrl = $repeat->bestUrl(); } } $act->context = $ctx; $source = $this->getSource(); if ($source) { $act->generator = ActivityObject::fromNoticeSource($source); } // Source $atom_feed = $profile->getAtomFeed(); if (!empty($atom_feed)) { $act->source = new ActivitySource(); // XXX: we should store the actual feed ID $act->source->id = $atom_feed; // XXX: we should store the actual feed title $act->source->title = $profile->getBestName(); $act->source->links['alternate'] = $profile->profileurl; $act->source->links['self'] = $atom_feed; $act->source->icon = $profile->avatarUrl(AVATAR_PROFILE_SIZE); $notice = $profile->getCurrentNotice(); if (!empty($notice)) { $act->source->updated = self::utcDate($notice->created); } $user = User::staticGet('id', $profile->id); if (!empty($user)) { $act->source->links['license'] = common_config('license', 'url'); } } if ($this->isLocal()) { $act->selfLink = common_local_url('ApiStatusesShow', array('id' => $this->id, 'format' => 'atom')); $act->editLink = $act->selfLink; } Event::handle('EndNoticeAsActivity', array($this, &$act)); } self::cacheSet(Cache::codeKey('notice:as-activity:' . $this->id), $act); return $act; }
function asString($tag = 'activity:object') { $xs = new XMLStringer(true); $xs->elementStart($tag); $xs->element('activity:object-type', null, $this->type); $xs->element(self::ID, null, $this->id); if (!empty($this->title)) { $xs->element(self::TITLE, null, common_xml_safe_str($this->title)); } if (!empty($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'), common_xml_safe_str($this->content)); } if (!empty($this->link)) { $xs->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) { $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)) { $xs->element('georss:point', null, $this->geopoint); } if (!empty($this->poco)) { $xs->raw($this->poco->asString()); } $xs->elementEnd($tag); return $xs->getString(); }
function outputTo($xo) { $xo->element('poco:preferredUsername', null, $this->preferredUsername); $xo->element('poco:displayName', null, $this->displayName); if (!empty($this->note)) { $xo->element('poco:note', null, common_xml_safe_str($this->note)); } if (!empty($this->address)) { $this->address->outputTo($xo); } foreach ($this->urls as $url) { $url->outputTo($xo); } }
function show_twitter_xml_dmsg($twitter_dm) { $this->elementStart('direct_message'); foreach ($twitter_dm as $element => $value) { switch ($element) { case 'sender': case 'recipient': $this->show_twitter_xml_user($value, $element); break; case 'text': $this->element($element, null, common_xml_safe_str($value)); break; default: $this->element($element, null, $value); } } $this->elementEnd('direct_message'); }
function showAtomGroups($group, $title, $id, $link, $subtitle = null, $selfuri = null) { $this->initDocument('atom'); $this->element('title', null, common_xml_safe_str($title)); $this->element('id', null, $id); $this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null); if (!is_null($selfuri)) { $this->element('link', array('href' => $selfuri, 'rel' => 'self', 'type' => 'application/atom+xml'), null); } $this->element('updated', null, common_date_iso8601('now')); $this->element('subtitle', null, common_xml_safe_str($subtitle)); if (is_array($group)) { foreach ($group as $g) { $this->raw($g->asAtomEntry()); } } else { while ($group->fetch()) { $this->raw($group->asAtomEntry()); } } $this->endDocument('atom'); }
function asAtomEntry($namespace = false, $source = false, $author = true) { $profile = $this->getProfile(); $xs = new XMLStringer(true); if ($namespace) { $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0'); } else { $attrs = array(); } $xs->elementStart('entry', $attrs); if ($source) { $xs->elementStart('source'); $xs->element('id', null, $profile->profileurl); $xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name')); $xs->element('link', array('href' => $profile->profileurl)); $user = User::staticGet('id', $profile->id); if (!empty($user)) { $atom_feed = common_local_url('ApiTimelineUser', array('format' => 'atom', 'id' => $profile->nickname)); $xs->element('link', array('rel' => 'self', 'type' => 'application/atom+xml', 'href' => $profile->profileurl)); $xs->element('link', array('rel' => 'license', 'href' => common_config('license', 'url'))); } $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE)); $xs->element('updated', null, common_date_w3dtf($this->created)); } if ($source) { $xs->elementEnd('source'); } $xs->element('title', null, common_xml_safe_str($this->content)); if ($author) { $xs->raw($profile->asAtomAuthor()); $xs->raw($profile->asActivityActor()); } $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', 'href' => $this->bestUrl())); $xs->element('id', null, $this->uri); $xs->element('published', null, common_date_w3dtf($this->created)); $xs->element('updated', null, common_date_w3dtf($this->created)); if ($this->reply_to) { $reply_notice = Notice::staticGet('id', $this->reply_to); if (!empty($reply_notice)) { $xs->element('link', array('rel' => 'related', 'href' => $reply_notice->bestUrl())); $xs->element('thr:in-reply-to', array('ref' => $reply_notice->uri, 'href' => $reply_notice->bestUrl())); } } if (!empty($this->conversation)) { $conv = Conversation::staticGet('id', $this->conversation); if (!empty($conv)) { $xs->element('link', array('rel' => 'ostatus:conversation', 'href' => $conv->uri)); } } $reply_ids = $this->getReplies(); foreach ($reply_ids as $id) { $profile = Profile::staticGet('id', $id); if (!empty($profile)) { $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $profile->getUri())); } } $groups = $this->getGroups(); foreach ($groups as $group) { $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $group->permalink())); } if (!empty($this->repeat_of)) { $repeat = Notice::staticGet('id', $this->repeat_of); if (!empty($repeat)) { $xs->element('ostatus:forward', array('ref' => $repeat->uri, 'href' => $repeat->bestUrl())); } } $xs->element('content', array('type' => 'html'), common_xml_safe_str($this->rendered)); $tag = new Notice_tag(); $tag->notice_id = $this->id; if ($tag->find()) { while ($tag->fetch()) { $xs->element('category', array('term' => $tag->tag)); } } $tag->free(); # Enclosures $attachments = $this->attachments(); if ($attachments) { foreach ($attachments as $attachment) { $enclosure = $attachment->getEnclosure(); if ($enclosure) { $attributes = array('rel' => 'enclosure', 'href' => $enclosure->url, 'type' => $enclosure->mimetype, 'length' => $enclosure->size); if ($enclosure->title) { $attributes['title'] = $enclosure->title; } $xs->element('link', $attributes, null); } } } if (!empty($this->lat) && !empty($this->lon)) { $xs->element('georss:point', null, $this->lat . ' ' . $this->lon); } $xs->elementEnd('entry'); return $xs->getString(); }
function asAtomEntry($namespace = false, $source = false) { $xs = new XMLStringer(true); if ($namespace) { $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0'); } else { $attrs = array(); } $xs->elementStart('entry', $attrs); if ($source) { $xs->elementStart('source'); $xs->element('id', null, $this->permalink()); $xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name')); $xs->element('link', array('href' => $this->permalink())); $xs->element('updated', null, $this->modified); $xs->elementEnd('source'); } $xs->element('title', null, $this->nickname); $xs->element('summary', null, common_xml_safe_str($this->description)); $xs->element('link', array('rel' => 'alternate', 'href' => $this->permalink())); $xs->element('id', null, $this->permalink()); $xs->element('published', null, common_date_w3dtf($this->created)); $xs->element('updated', null, common_date_w3dtf($this->modified)); $xs->element('content', array('type' => 'html'), common_xml_safe_str($this->description)); $xs->elementEnd('entry'); return $xs->getString(); }
function asAtomEntry($namespace = false, $source = false, $author = true, $cur = null) { $profile = $this->getProfile(); $xs = new XMLStringer(true); if ($namespace) { $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:georss' => 'http://www.georss.org/georss', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:media' => 'http://purl.org/syndication/atommedia', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:ostatus' => 'http://ostatus.org/schema/1.0', 'xmlns:statusnet' => 'http://status.net/schema/api/1/'); } else { $attrs = array(); } if (Event::handle('StartActivityStart', array(&$this, &$xs, &$attrs))) { $xs->elementStart('entry', $attrs); Event::handle('EndActivityStart', array(&$this, &$xs, &$attrs)); } if (Event::handle('StartActivitySource', array(&$this, &$xs))) { if ($source) { $atom_feed = $profile->getAtomFeed(); if (!empty($atom_feed)) { $xs->elementStart('source'); // XXX: we should store the actual feed ID $xs->element('id', null, $atom_feed); // XXX: we should store the actual feed title $xs->element('title', null, $profile->getBestName()); $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', 'href' => $profile->profileurl)); $xs->element('link', array('rel' => 'self', 'type' => 'application/atom+xml', 'href' => $atom_feed)); $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE)); $notice = $profile->getCurrentNotice(); if (!empty($notice)) { $xs->element('updated', null, self::utcDate($notice->created)); } $user = User::staticGet('id', $profile->id); if (!empty($user)) { $xs->element('link', array('rel' => 'license', 'href' => common_config('license', 'url'))); } $xs->elementEnd('source'); } } Event::handle('EndActivitySource', array(&$this, &$xs)); } $title = common_xml_safe_str($this->content); if (Event::handle('StartActivityTitle', array(&$this, &$xs, &$title))) { $xs->element('title', null, $title); Event::handle('EndActivityTitle', array($this, &$xs, $title)); } $atomAuthor = ''; if ($author) { $atomAuthor = $profile->asAtomAuthor($cur); } if (Event::handle('StartActivityAuthor', array(&$this, &$xs, &$atomAuthor))) { if (!empty($atomAuthor)) { $xs->raw($atomAuthor); Event::handle('EndActivityAuthor', array(&$this, &$xs, &$atomAuthor)); } } $actor = ''; if ($author) { $actor = $profile->asActivityActor(); } if (Event::handle('StartActivityActor', array(&$this, &$xs, &$actor))) { if (!empty($actor)) { $xs->raw($actor); Event::handle('EndActivityActor', array(&$this, &$xs, &$actor)); } } $url = $this->bestUrl(); if (Event::handle('StartActivityLink', array(&$this, &$xs, &$url))) { $xs->element('link', array('rel' => 'alternate', 'type' => 'text/html', 'href' => $url)); Event::handle('EndActivityLink', array(&$this, &$xs, $url)); } $id = $this->uri; if (Event::handle('StartActivityId', array(&$this, &$xs, &$id))) { $xs->element('id', null, $id); Event::handle('EndActivityId', array(&$this, &$xs, $id)); } $published = self::utcDate($this->created); if (Event::handle('StartActivityPublished', array(&$this, &$xs, &$published))) { $xs->element('published', null, $published); Event::handle('EndActivityPublished', array(&$this, &$xs, $published)); } $updated = $published; // XXX: notices are usually immutable if (Event::handle('StartActivityUpdated', array(&$this, &$xs, &$updated))) { $xs->element('updated', null, $updated); Event::handle('EndActivityUpdated', array(&$this, &$xs, $updated)); } $content = common_xml_safe_str($this->rendered); if (Event::handle('StartActivityContent', array(&$this, &$xs, &$content))) { $xs->element('content', array('type' => 'html'), $content); Event::handle('EndActivityContent', array(&$this, &$xs, $content)); } // Most of our notices represent POSTing a NOTE. This is the default verb // for activity streams, so we normally just leave it out. $verb = ActivityVerb::POST; if (Event::handle('StartActivityVerb', array(&$this, &$xs, &$verb))) { $xs->element('activity:verb', null, $verb); Event::handle('EndActivityVerb', array(&$this, &$xs, $verb)); } // We use the default behavior for activity streams: if there's no activity:object, // then treat the entry itself as the object. Here, you can set the type of that object, // which is normally a NOTE. $type = ActivityObject::NOTE; if (Event::handle('StartActivityDefaultObjectType', array(&$this, &$xs, &$type))) { $xs->element('activity:object-type', null, $type); Event::handle('EndActivityDefaultObjectType', array(&$this, &$xs, $type)); } // Since we usually use the entry itself as an object, we don't have an explicit // object. Some extensions may want to add them (for photo, event, music, etc.). $objects = array(); if (Event::handle('StartActivityObjects', array(&$this, &$xs, &$objects))) { foreach ($objects as $object) { $xs->raw($object->asString()); } Event::handle('EndActivityObjects', array(&$this, &$xs, $objects)); } $noticeInfoAttr = array('local_id' => $this->id); // local notice ID (useful to clients for ordering) $ns = $this->getSource(); if (!empty($ns)) { $noticeInfoAttr['source'] = $ns->code; if (!empty($ns->url)) { $noticeInfoAttr['source_link'] = $ns->url; if (!empty($ns->name)) { $noticeInfoAttr['source'] = '<a href="' . htmlspecialchars($ns->url) . '" rel="nofollow">' . htmlspecialchars($ns->name) . '</a>'; } } } if (!empty($cur)) { $noticeInfoAttr['favorite'] = $cur->hasFave($this) ? "true" : "false"; $profile = $cur->getProfile(); $noticeInfoAttr['repeated'] = $profile->hasRepeated($this->id) ? "true" : "false"; } if (!empty($this->repeat_of)) { $noticeInfoAttr['repeat_of'] = $this->repeat_of; } if (Event::handle('StartActivityNoticeInfo', array(&$this, &$xs, &$noticeInfoAttr))) { $xs->element('statusnet:notice_info', $noticeInfoAttr, null); Event::handle('EndActivityNoticeInfo', array(&$this, &$xs, $noticeInfoAttr)); } $replyNotice = null; if ($this->reply_to) { $replyNotice = Notice::staticGet('id', $this->reply_to); } if (Event::handle('StartActivityInReplyTo', array(&$this, &$xs, &$replyNotice))) { if (!empty($replyNotice)) { $xs->element('link', array('rel' => 'related', 'href' => $replyNotice->bestUrl())); $xs->element('thr:in-reply-to', array('ref' => $replyNotice->uri, 'href' => $replyNotice->bestUrl())); Event::handle('EndActivityInReplyTo', array(&$this, &$xs, $replyNotice)); } } $conv = null; if (!empty($this->conversation)) { $conv = Conversation::staticGet('id', $this->conversation); } if (Event::handle('StartActivityConversation', array(&$this, &$xs, &$conv))) { if (!empty($conv)) { $xs->element('link', array('rel' => 'ostatus:conversation', 'href' => $conv->uri)); } Event::handle('EndActivityConversation', array(&$this, &$xs, $conv)); } $replyProfiles = array(); $reply_ids = $this->getReplies(); foreach ($reply_ids as $id) { $profile = Profile::staticGet('id', $id); if (!empty($profile)) { $replyProfiles[] = $profile; } } if (Event::handle('StartActivityAttentionProfiles', array(&$this, &$xs, &$replyProfiles))) { foreach ($replyProfiles as $profile) { $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $profile->getUri())); $xs->element('link', array('rel' => 'mentioned', 'href' => $profile->getUri())); } Event::handle('EndActivityAttentionProfiles', array(&$this, &$xs, $replyProfiles)); } $groups = $this->getGroups(); if (Event::handle('StartActivityAttentionGroups', array(&$this, &$xs, &$groups))) { foreach ($groups as $group) { $xs->element('link', array('rel' => 'ostatus:attention', 'href' => $group->permalink())); $xs->element('link', array('rel' => 'mentioned', 'href' => $group->permalink())); } Event::handle('EndActivityAttentionGroups', array(&$this, &$xs, $groups)); } $repeat = null; if (!empty($this->repeat_of)) { $repeat = Notice::staticGet('id', $this->repeat_of); } if (Event::handle('StartActivityForward', array(&$this, &$xs, &$repeat))) { if (!empty($repeat)) { $xs->element('ostatus:forward', array('ref' => $repeat->uri, 'href' => $repeat->bestUrl())); } Event::handle('EndActivityForward', array(&$this, &$xs, $repeat)); } $tags = $this->getTags(); if (Event::handle('StartActivityCategories', array(&$this, &$xs, &$tags))) { foreach ($tags as $tag) { $xs->element('category', array('term' => $tag)); } Event::handle('EndActivityCategories', array(&$this, &$xs, $tags)); } // Enclosures $enclosures = array(); $attachments = $this->attachments(); foreach ($attachments as $attachment) { $enclosure = $attachment->getEnclosure(); if ($enclosure) { $enclosures[] = $enclosure; } } if (Event::handle('StartActivityEnclosures', array(&$this, &$xs, &$enclosures))) { foreach ($enclosures as $enclosure) { $attributes = array('rel' => 'enclosure', 'href' => $enclosure->url, 'type' => $enclosure->mimetype, 'length' => $enclosure->size); if ($enclosure->title) { $attributes['title'] = $enclosure->title; } $xs->element('link', $attributes, null); } Event::handle('EndActivityEnclosures', array(&$this, &$xs, $enclosures)); } $lat = $this->lat; $lon = $this->lon; if (Event::handle('StartActivityGeo', array(&$this, &$xs, &$lat, &$lon))) { if (!empty($lat) && !empty($lon)) { $xs->element('georss:point', null, $lat . ' ' . $lon); } Event::handle('EndActivityGeo', array(&$this, &$xs, $lat, $lon)); } if (Event::handle('StartActivityEnd', array(&$this, &$xs))) { $xs->elementEnd('entry'); Event::handle('EndActivityEnd', array(&$this, &$xs)); } return $xs->getString(); }
/** * Build an Atom entry similar to search.twitter.com's based on * a given notice * * @param Notice $notice the notice to use * * @return void */ function showEntry($notice) { $server = common_config('site', 'server'); $profile = $notice->getProfile(); $nurl = common_local_url('shownotice', array('notice' => $notice->id)); $this->elementStart('entry'); $taguribase = TagURI::base(); $this->element('id', null, "tag:{$taguribase}:{$notice->id}"); $this->element('published', null, common_date_w3dtf($notice->created)); $this->element('link', array('type' => 'text/html', 'rel' => 'alternate', 'href' => $nurl)); $this->element('title', null, common_xml_safe_str(trim($notice->content))); $this->element('content', array('type' => 'html'), $notice->getRendered()); $this->element('updated', null, common_date_w3dtf($notice->created)); $this->element('link', array('type' => 'image/png', 'rel' => 'related', 'href' => $profile->avatarUrl())); // @todo: Here is where we'd put in a link to an atom feed for threads $source = null; $ns = $notice->getSource(); if ($ns instanceof Notice_source) { if (!empty($ns->name) && !empty($ns->url)) { $source = '<a href="' . htmlspecialchars($ns->url) . '" rel="nofollow">' . htmlspecialchars($ns->name) . '</a>'; } else { $source = $ns->code; } } $this->element("twitter:source", null, $source); $this->elementStart('author'); $name = $profile->nickname; if ($profile->fullname) { // @todo Needs proper i18n? $name .= ' (' . $profile->fullname . ')'; } $this->element('name', null, $name); $this->element('uri', null, common_profile_uri($profile)); $this->elementEnd('author'); $this->elementEnd('entry'); }
function outputTo($xo, $tag = 'activity:object') { if (!empty($tag)) { $xo->elementStart($tag); } $xo->element('activity:object-type', null, $this->type); // <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') { // XXX: Backward compatibility hack -- atom:name should contain // 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->summary)) { $xo->element(self::SUMMARY, null, common_xml_safe_str($this->summary)); } 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); } if ($this->type == ActivityObject::PERSON || $this->type == ActivityObject::GROUP) { foreach ($this->avatarLinks as $avatar) { $xo->element('link', array('rel' => 'avatar', 'type' => $avatar->type, 'media:width' => $avatar->width, 'media:height' => $avatar->height, 'href' => $avatar->url), null); } } if (!empty($this->geopoint)) { $xo->element('georss:point', null, $this->geopoint); } if (!empty($this->poco)) { $this->poco->outputTo($xo); } foreach ($this->extra as $el) { list($extraTag, $attrs, $content) = $el; $xo->element($extraTag, $attrs, $content); } if (!empty($tag)) { $xo->elementEnd($tag); } return; }