/** * 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 showItem($notice) { $profile = $notice->getProfile(); $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->getRendered()) { $this->element('content:encoded', null, common_xml_safe_str($notice->getRendered())); } $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')); try { $location = Notice_location::locFromStored($notice); if (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); } } catch (ServerException $e) { // No result, so no location data } $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) { try { $enclosure = $attachment->getEnclosure(); $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); } catch (ServerException $e) { // There was not enough metadata available } $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 twitterRssEntryArray($notice) { $entry = array(); if (Event::handle('StartRssEntryArray', array($notice, &$entry))) { $profile = $notice->getProfile(); // We trim() to avoid extraneous whitespace in the output $entry['content'] = common_xml_safe_str(trim($notice->getRendered())); $entry['title'] = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content)); $entry['link'] = common_local_url('shownotice', array('notice' => $notice->id)); $entry['published'] = common_date_iso8601($notice->created); $taguribase = TagURI::base(); $entry['id'] = "tag:{$taguribase}:{$entry['link']}"; $entry['updated'] = $entry['published']; $entry['author'] = $profile->getBestName(); // Enclosures $attachments = $notice->attachments(); $enclosures = array(); foreach ($attachments as $attachment) { try { $enclosure_o = $attachment->getEnclosure(); $enclosure = array(); $enclosure['url'] = $enclosure_o->url; $enclosure['mimetype'] = $enclosure_o->mimetype; $enclosure['size'] = $enclosure_o->size; $enclosures[] = $enclosure; } catch (ServerException $e) { // There was not enough metadata available } } if (!empty($enclosures)) { $entry['enclosures'] = $enclosures; } // Tags/Categories $tag = new Notice_tag(); $tag->notice_id = $notice->id; if ($tag->find()) { $entry['tags'] = array(); while ($tag->fetch()) { $entry['tags'][] = $tag->tag; } } $tag->free(); // RSS Item specific $entry['description'] = $entry['content']; $entry['pubDate'] = common_date_rfc2822($notice->created); $entry['guid'] = $entry['link']; try { $notloc = Notice_location::locFromStored($notice); // This is the format that GeoJSON expects stuff to be in. // showGeoRSS() below uses it for XML output, so we reuse it $entry['geo'] = array('type' => 'Point', 'coordinates' => array((double) $notloc->lat, (double) $notloc->lon)); } catch (ServerException $e) { $entry['geo'] = null; } Event::handle('EndRssEntryArray', array($notice, &$entry)); } return $entry; }
/** * Hook for adding extra JavaScript * * @param Action $action Action object for the page * * @return boolean event handler return */ function showScripts() { parent::showScripts(); $jsonArray = array(); while ($this->notice->fetch()) { try { $notloc = Notice_location::locFromStored($this->notice); $jsonArray[] = $this->noticeAsJson($this->notice); } catch (ServerException $e) { // no location data } } $this->inlineScript('$(document).ready(function() { ' . ' var _notices = ' . json_encode($jsonArray) . '; ' . 'showMapstraction($("#map_canvas"), _notices); });'); return true; }
/** * show the notice location * * shows the notice location in the correct language. * * If an URL is available, makes a link. Otherwise, just a span. * * @return void */ function showNoticeLocation() { return; try { $location = Notice_location::locFromStored($this->notice); } catch (NoResultException $e) { return; } catch (ServerException $e) { return; } $name = $location->getName(); $lat = $location->lat; $lon = $location->lon; $latlon = !empty($lat) && !empty($lon) ? $lat . ';' . $lon : ''; if (empty($name)) { $latdms = $this->decimalDegreesToDMS(abs($lat)); $londms = $this->decimalDegreesToDMS(abs($lon)); // TRANS: Used in coordinates as abbreviation of north. $north = _('N'); // TRANS: Used in coordinates as abbreviation of south. $south = _('S'); // TRANS: Used in coordinates as abbreviation of east. $east = _('E'); // TRANS: Used in coordinates as abbreviation of west. $west = _('W'); $name = sprintf(_('%1$u°%2$u\'%3$u"%4$s %5$u°%6$u\'%7$u"%8$s'), $latdms['deg'], $latdms['min'], $latdms['sec'], $lat > 0 ? $north : $south, $londms['deg'], $londms['min'], $londms['sec'], $lon > 0 ? $east : $west); } $url = $location->getUrl(); $this->out->text(' '); $this->out->elementStart('span', array('class' => 'location')); // TRANS: Followed by geo location. $this->out->text(_('at')); $this->out->text(' '); if (empty($url)) { $this->out->element('abbr', array('class' => 'geo', 'title' => $latlon), $name); } else { $xstr = new XMLStringer(false); $xstr->elementStart('a', array('href' => $url, 'rel' => 'external')); $xstr->element('abbr', array('class' => 'geo', 'title' => $latlon), $name); $xstr->elementEnd('a'); $this->out->raw($xstr->getString()); } $this->out->elementEnd('span'); }