From d6869cde7ba7e577d54f0c6ecab3599dc85f0f67 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 11 Feb 2010 16:51:15 -0500 Subject: let avatars be served over SSL --- classes/Avatar.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Avatar.php b/classes/Avatar.php index 91bde0f04..dbe2cd813 100644 --- a/classes/Avatar.php +++ b/classes/Avatar.php @@ -82,9 +82,20 @@ class Avatar extends Memcached_DataObject $server = common_config('site', 'server'); } - // XXX: protocol + $ssl = common_config('avatar', 'ssl'); + + if (is_null($ssl)) { // null -> guess + if (common_config('site', 'ssl') == 'always' && + !common_config('avatar', 'server')) { + $ssl = true; + } else { + $ssl = false; + } + } + + $protocol = ($ssl) ? 'https' : 'http'; - return 'http://'.$server.$path.$filename; + return $protocol.'://'.$server.$path.$filename; } function displayUrl() -- cgit v1.2.3-54-g00ecf From e2c0f59414dd7e9a33ffbae7307b81a85c2c168b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 10 Feb 2010 18:55:14 -0800 Subject: Some upgrades to Atom output for OStatus --- actions/apitimelineuser.php | 2 +- classes/Notice.php | 38 +++++++++++++++++++++++++++-------- classes/Profile.php | 49 +++++++++++++++++++++++++++++++++++++++++++++ lib/atom10feed.php | 2 +- lib/atomnoticefeed.php | 18 ++++++++++++++++- 5 files changed, 98 insertions(+), 11 deletions(-) (limited to 'classes') diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index bcc48f59c..cb8213619 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -189,7 +189,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction $atom->addEntryFromNotices($this->notices); - print $atom->getString(); + $this->raw($atom->getString()); break; case 'json': diff --git a/classes/Notice.php b/classes/Notice.php index 247440f29..091f2dc7b 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -957,7 +957,10 @@ class Notice extends Memcached_DataObject if ($namespace) { $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', - 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0'); + '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:ostatus' => 'http://ostatus.org/schema/1.0'); } else { $attrs = array(); } @@ -983,11 +986,6 @@ class Notice extends Memcached_DataObject $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE)); } - $xs->elementStart('author'); - $xs->element('name', null, $profile->nickname); - $xs->element('uri', null, $profile->profileurl); - $xs->elementEnd('author'); - if ($source) { $xs->elementEnd('source'); } @@ -995,6 +993,9 @@ class Notice extends Memcached_DataObject $xs->element('title', null, $this->content); $xs->element('summary', null, $this->content); + $xs->raw($profile->asAtomAuthor()); + $xs->raw($profile->asActivityActor($namespace)); + $xs->element('link', array('rel' => 'alternate', 'href' => $this->bestUrl())); @@ -1014,6 +1015,29 @@ class Notice extends Memcached_DataObject } } + if (!empty($this->conversation) + && $this->conversation != $this->notice->id) { + $xs->element( + 'link', array( + 'rel' => 'osatus:conversation', + 'href' => common_local_url( + 'conversation', + array('id' => $this->conversation) + ) + ) + ); + } + + 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'), $this->rendered); $tag = new Notice_tag(); @@ -1041,9 +1065,7 @@ class Notice extends Memcached_DataObject } if (!empty($this->lat) && !empty($this->lon)) { - $xs->elementStart('geo', array('xmlns:georss' => 'http://www.georss.org/georss')); $xs->element('georss:point', null, $this->lat . ' ' . $this->lon); - $xs->elementEnd('geo'); } $xs->elementEnd('entry'); diff --git a/classes/Profile.php b/classes/Profile.php index feabc2508..664c45f64 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -754,4 +754,53 @@ class Profile extends Memcached_DataObject return !empty($notice); } + + function asAtomAuthor() + { + $xs = new XMLStringer(true); + + $xs->elementStart('author'); + $xs->element('name', null, $this->nickname); + $xs->element('uri', null, $this->profileurl); + $xs->elementEnd('author'); + + return $xs->getString(); + } + + function asActivityActor() + { + $xs = new XMLStringer(true); + + $xs->elementStart('activity:actor'); + $xs->element( + 'activity:object-type', + null, + 'http://activitystrea.ms/schema/1.0/person' + ); + $xs->element( + 'id', + null, + common_local_url( + 'userbyid', + array('id' => $this->id) + ) + ); + $xs->element('title', null, $this->getBestName()); + + $avatar = $this->getAvatar(AVATAR_PROFILE_SIZE); + + $xs->element( + 'link', array( + 'type' => empty($avatar) ? 'image/png' : $avatar->mediatype, + 'href' => empty($avatar) + ? Avatar::defaultImage(AVATAR_PROFILE_SIZE) + : $avatar->displayUrl() + ), + '' + ); + + $xs->elementEnd('activity:actor'); + + return $xs->getString(); + } } diff --git a/lib/atom10feed.php b/lib/atom10feed.php index 9dd8ebc9b..01fc69072 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -153,7 +153,7 @@ class Atom10Feed extends XMLStringer * Assumes you want rel="alternate" and type="text/html" unless * you send in $otherAttrs. * - * @param string $uri the uri the href need to point to + * @param string $uri the uri the href needs to point to * @param array $otherAttrs other attributes to stick in * * @return void diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index a28c9cda7..ce87ec9e6 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -5,12 +5,28 @@ class AtomNoticeFeed extends Atom10Feed function __construct($indent = true) { parent::__construct($indent); - // Feeds containing notice info use the Atom Threading Extensions + // Feeds containing notice info use these namespaces $this->addNamespace( 'xmlns:thr', 'http://purl.org/syndication/thread/1.0' ); + + $this->addNamespace( + 'xmlns:georss', + 'http://www.georss.org/georss' + ); + + $this->addNamespace( + 'xmlns:activity', + 'http://activitystrea.ms/spec/1.0/' + ); + + // XXX: What should the uri be? + $this->addNamespace( + 'xmlns:ostatus', + 'http://ostatus.org/schema/1.0' + ); } function addEntryFromNotices($notices) -- cgit v1.2.3-54-g00ecf From 3018683718bd73bf00472622f9e81914703d50a7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 11 Feb 2010 17:03:31 -0500 Subject: let backgrounds be put under SSL --- README | 2 ++ classes/Design.php | 15 +++++++++++++-- lib/default.php | 3 ++- 3 files changed, 17 insertions(+), 3 deletions(-) (limited to 'classes') diff --git a/README b/README index 7531df997..3b2baaeeb 100644 --- a/README +++ b/README @@ -1521,6 +1521,8 @@ dir: directory to write backgrounds too. Default is '/background/' subdir of install dir. path: path to backgrounds. Default is sub-path of install path; note that you may need to change this if you change site-path too. +ssl: Whether or not to use HTTPS for background files. Defaults to + null, meaning to guess from site-wide SSL settings. ping ---- diff --git a/classes/Design.php b/classes/Design.php index 4e7d7dfb2..ff44e0109 100644 --- a/classes/Design.php +++ b/classes/Design.php @@ -155,9 +155,20 @@ class Design extends Memcached_DataObject $server = common_config('site', 'server'); } - // XXX: protocol + $ssl = common_config('background', 'ssl'); + + if (is_null($ssl)) { // null -> guess + if (common_config('site', 'ssl') == 'always' && + !common_config('background', 'server')) { + $ssl = true; + } else { + $ssl = false; + } + } + + $protocol = ($ssl) ? 'https' : 'http'; - return 'http://'.$server.$path.$filename; + return $protocol.'://'.$server.$path.$filename; } function setDisposition($on, $off, $tile) diff --git a/lib/default.php b/lib/default.php index 8a21271b8..0822654f6 100644 --- a/lib/default.php +++ b/lib/default.php @@ -116,7 +116,8 @@ $default = 'background' => array('server' => null, 'dir' => INSTALLDIR . '/background/', - 'path' => $_path . '/background/'), + 'path' => $_path . '/background/', + 'ssl' => null), 'public' => array('localonly' => true, 'blacklist' => array(), -- cgit v1.2.3-54-g00ecf From 31461e120f23416c8c4979805900e3018fb2a6fd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 11 Feb 2010 17:06:57 -0500 Subject: let files go to SSL dir too --- README | 2 ++ classes/File.php | 15 +++++++++++++-- lib/default.php | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/README b/README index 3b2baaeeb..75336eb83 100644 --- a/README +++ b/README @@ -1462,6 +1462,8 @@ server: server name to use when creating URLs for uploaded files. a virtual server here can speed up Web performance. path: URL path, relative to the server, to find files. Defaults to main path + '/file/'. +ssl: whether to use HTTPS for file URLs. Defaults to null, meaning to + guess based on other SSL settings. filecommand: command to use for determining the type of a file. May be skipped if fileinfo extension is installed. Defaults to '/usr/bin/file'. diff --git a/classes/File.php b/classes/File.php index ee418a802..91b12d2e2 100644 --- a/classes/File.php +++ b/classes/File.php @@ -228,9 +228,20 @@ class File extends Memcached_DataObject $server = common_config('site', 'server'); } - // XXX: protocol + $ssl = common_config('attachments', 'ssl'); - return 'http://'.$server.$path.$filename; + if (is_null($ssl)) { // null -> guess + if (common_config('site', 'ssl') == 'always' && + !common_config('attachments', 'server')) { + $ssl = true; + } else { + $ssl = false; + } + } + + $protocol = ($ssl) ? 'https' : 'http'; + + return $protocol.'://'.$server.$path.$filename; } } diff --git a/lib/default.php b/lib/default.php index 0822654f6..8b1fe2769 100644 --- a/lib/default.php +++ b/lib/default.php @@ -188,6 +188,7 @@ $default = array('server' => null, 'dir' => INSTALLDIR . '/file/', 'path' => $_path . '/file/', + 'ssl' => null, 'supported' => array('image/png', 'image/jpeg', 'image/gif', -- cgit v1.2.3-54-g00ecf From 3beddffc39e9a0bc5d32f50f4c8f93771060a032 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 11 Feb 2010 15:24:18 -0800 Subject: ostatus:attention links in Notice Atom output --- classes/Notice.php | 16 +++++++++++++++- classes/Profile.php | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index 091f2dc7b..a39388cdb 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -994,7 +994,7 @@ class Notice extends Memcached_DataObject $xs->element('summary', null, $this->content); $xs->raw($profile->asAtomAuthor()); - $xs->raw($profile->asActivityActor($namespace)); + $xs->raw($profile->asActivityActor()); $xs->element('link', array('rel' => 'alternate', 'href' => $this->bestUrl())); @@ -1028,6 +1028,20 @@ class Notice extends Memcached_DataObject ); } + $reply_ids = $this->getReplies(); + + foreach ($reply_ids as $id) { + $profile = Profile::staticGet('id', $id); + if (!empty($profile)) { + $xs->element( + 'link', array( + 'rel' => 'osatus:attention', + 'href' => $profile->getAcctUri() + ) + ); + } + } + if (!empty($this->repeat_of)) { $repeat = Notice::staticGet('id', $this->repeat_of); if (!empty($repeat)) { diff --git a/classes/Profile.php b/classes/Profile.php index 664c45f64..3e5150c18 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -803,4 +803,10 @@ class Profile extends Memcached_DataObject return $xs->getString(); } + + function getAcctUri() + { + return $this->nickname . '@' . common_config('site', 'server'); + } + } -- cgit v1.2.3-54-g00ecf From 525358fa101784fa5bbbac8b214091de89ec0634 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 11 Feb 2010 17:08:50 -0800 Subject: Fix retarded spelling mistake --- classes/Notice.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index a39388cdb..924931e42 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1019,7 +1019,7 @@ class Notice extends Memcached_DataObject && $this->conversation != $this->notice->id) { $xs->element( 'link', array( - 'rel' => 'osatus:conversation', + 'rel' => 'ostatus:conversation', 'href' => common_local_url( 'conversation', array('id' => $this->conversation) @@ -1035,7 +1035,7 @@ class Notice extends Memcached_DataObject if (!empty($profile)) { $xs->element( 'link', array( - 'rel' => 'osatus:attention', + 'rel' => 'ostatus:attention', 'href' => $profile->getAcctUri() ) ); -- cgit v1.2.3-54-g00ecf From b39047d95b447251de75d15b986017286aca05e0 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 12 Feb 2010 18:54:48 +0000 Subject: 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. --- classes/Profile.php | 34 ++++++- plugins/OStatus/classes/Ostatus_profile.php | 153 +++++++++++++++++++++++++++- 2 files changed, 184 insertions(+), 3 deletions(-) (limited to 'classes') diff --git a/classes/Profile.php b/classes/Profile.php index 3e5150c18..ab05bb854 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -755,6 +755,14 @@ class Profile extends Memcached_DataObject return !empty($notice); } + /** + * Returns an XML string fragment with limited profile information + * as an Atom 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 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(); } diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index f7bbcd028..733d8843b 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -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, -- cgit v1.2.3-54-g00ecf From fd3c9334bfcfe627446feb86ac3054b24ed05449 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 12 Feb 2010 11:15:12 -0800 Subject: PHP 5.3 compatibility hack for DB_DataObject statusnet.links.ini file could not be read anymore due to the entry for nonce containing a comma in its key value. PHP's parse_ini_file() function no longer allows commas in keys, and rejects the *ENTIRE FILE* if it's present, breaking various automatic joins. --- classes/Nonce.php | 15 +++++++++++++++ classes/statusnet.links.ini | 7 +++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'classes') diff --git a/classes/Nonce.php b/classes/Nonce.php index 486a65a3c..2f8ab00b5 100644 --- a/classes/Nonce.php +++ b/classes/Nonce.php @@ -22,4 +22,19 @@ class Nonce extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + /** + * Compatibility hack for PHP 5.3 + * + * The statusnet.links.ini entry cannot be read because "," is no longer + * allowed in key names when read by parse_ini_file(). + * + * @return array + * @access public + */ + function links() + { + return array('consumer_key,token' => 'token:consumer_key,token'); + } + } diff --git a/classes/statusnet.links.ini b/classes/statusnet.links.ini index 7f233e676..b9dd5af0c 100644 --- a/classes/statusnet.links.ini +++ b/classes/statusnet.links.ini @@ -19,8 +19,11 @@ profile_id = profile:id [token] consumer_key = consumer:consumer_key -[nonce] -consumer_key,token = token:consumer_key,token +; Compatibility hack for PHP 5.3 +; This entry has been moved to the class definition, as commas are no longer +; considered valid in keys, causing parse_ini_file() to reject the whole file. +;[nonce] +;consumer_key,token = token:consumer_key,token [confirm_address] user_id = user:id -- cgit v1.2.3-54-g00ecf From 506c2d7491f7f229a1469ef176fee6c21d61a6c6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 12 Feb 2010 12:22:12 -0800 Subject: Initial upgraded Atom output for group timelines --- actions/apitimelinegroup.php | 62 +++++++++++++++++++++++++++++---------- classes/User_group.php | 33 +++++++++++++++++++++ lib/api.php | 2 +- lib/atom10feed.php | 70 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 149 insertions(+), 18 deletions(-) (limited to 'classes') diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index fd2ed9ff9..45962fa76 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -109,38 +109,70 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction $title = sprintf(_("%s timeline"), $this->group->nickname); $taguribase = common_config('integration', 'taguri'); $id = "tag:$taguribase:GroupTimeline:" . $this->group->id; - $link = common_local_url( - 'showgroup', - array('nickname' => $this->group->nickname) - ); + $subtitle = sprintf( _('Updates from %1$s on %2$s!'), $this->group->nickname, $sitename ); - $logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE); + + $logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE); switch($this->format) { case 'xml': $this->showXmlTimeline($this->notices); break; case 'rss': - $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo); - break; - case 'atom': - $selfuri = common_root_url() . - 'api/statusnet/groups/timeline/' . - $this->group->id . '.atom'; - $this->showAtomTimeline( + $this->showRssTimeline( $this->notices, $title, - $id, - $link, + $this->group->homeUrl(), $subtitle, null, - $selfuri, $logo ); + break; + case 'atom': + + header('Content-Type: application/atom+xml; charset=utf-8'); + + try { + + $atom = new AtomNoticeFeed(); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); + + $atom->addAuthorRaw($this->group->asAtomAuthor()); + $atom->setActivitySubject($this->group->asActivitySubject()); + + $atom->addLink($this->group->homeUrl()); + + $id = $this->arg('id'); + $aargs = array('format' => 'atom'); + if (!empty($id)) { + $aargs['id'] = $id; + } + + $atom->addLink( + $this->getSelfUri('ApiTimelineGroup', $aargs), + array('rel' => 'self', 'type' => 'application/atom+xml') + ); + + $atom->addEntryFromNotices($this->notices); + + $this->raw($atom->getString()); + + } catch (Atom10FeedException $e) { + $this->serverError( + 'Could not generate feed for group - ' . $e->getMessage() + ); + return; + } + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/classes/User_group.php b/classes/User_group.php index 1fbb50a6e..379e6b721 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -355,6 +355,39 @@ class User_group extends Memcached_DataObject return $xs->getString(); } + function asAtomAuthor() + { + $xs = new XMLStringer(true); + + $xs->elementStart('author'); + $xs->element('name', null, $this->nickname); + $xs->element('uri', null, $this->permalink()); + $xs->elementEnd('author'); + + return $xs->getString(); + } + + function asActivitySubject() + { + $xs = new XMLStringer(true); + + $xs->elementStart('activity:subject'); + $xs->element('activity:object', null, 'http://activitystrea.ms/schema/1.0/group'); + $xs->element('id', null, $this->permalink()); + $xs->element('title', null, $this->getBestName()); + $xs->element( + 'link', array( + 'rel' => 'avatar', + 'href' => empty($this->homepage_logo) + ? User_group::defaultLogo(AVATAR_PROFILE_SIZE) + : $this->homepage_logo + ) + ); + $xs->elementEnd('activity:subject'); + + return $xs->getString(); + } + static function register($fields) { // MAGICALLY put fields into current scope diff --git a/lib/api.php b/lib/api.php index 8f1fe1ef7..494b595d1 100644 --- a/lib/api.php +++ b/lib/api.php @@ -1103,7 +1103,7 @@ class ApiAction extends Action } } - function serverError($msg, $code = 500, $content_type = 'json') + function serverError($msg, $code = 500, $content_type = 'xml') { $action = $this->trimmed('action'); diff --git a/lib/atom10feed.php b/lib/atom10feed.php index ccca76a09..806a9684b 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -51,6 +51,7 @@ class Atom10Feed extends XMLStringer public $xw; private $namespaces; private $authors; + private $subject; private $categories; private $contributors; private $generator; @@ -74,6 +75,7 @@ class Atom10Feed extends XMLStringer function __construct($indent = true) { parent::__construct($indent); $this->namespaces = array(); + $this->authors = array(); $this->links = array(); $this->entries = array(); $this->addNamespace('xmlns', 'http://www.w3.org/2005/Atom'); @@ -93,6 +95,64 @@ class Atom10Feed extends XMLStringer $this->namespaces = array_merge($this->namespaces, $ns); } + function addAuthor($name, $uri = null, $email = null) + { + $xs = new XMLStringer(true); + + $xs->elementStart('author'); + + if (!empty($name)) { + $xs->element('name', null, $name); + } else { + throw new Atom10FeedException( + 'author element must contain a name element.' + ); + } + + if (!is_null($uri)) { + $xs->element('uri', null, $uri); + } + + if (!is_null(email)) { + $xs->element('email', null, $email); + } + + $xs->elementEnd('author'); + + array_push($this->authors, $xs->getString()); + } + + /** + * Add an Author to the feed via raw XML string + * + * @param string $xmlAuthor An XML string representation author + * + * @return void + */ + function addAuthorRaw($xmlAuthor) + { + array_push($this->authors, $xmlAuthor); + } + + function renderAuthors() + { + foreach ($this->authors as $author) { + $this->raw($author); + } + } + + /** + * Add a activity feed subject via raw XML string + * + * @param string $xmlSubject An XML string representation of the subject + * + * @return void + */ + function setActivitySubject($xmlSubject) + { + $this->subject = $xmlSubject; + } + function getNamespaces() { return $this->namespaces; @@ -136,9 +196,9 @@ class Atom10Feed extends XMLStringer } } - function addEntryRaw($entry) + function addEntryRaw($xmlEntry) { - array_push($this->entries, $entry); + array_push($this->entries, $xmlEntry); } function addEntry($entry) @@ -164,6 +224,12 @@ class Atom10Feed extends XMLStringer $this->validate(); $this->initFeed(); + $this->renderAuthors(); + + if (!empty($this->subject)) { + $this->raw($this->subject); + } + $this->renderEntries(); $this->endFeed(); -- cgit v1.2.3-54-g00ecf From d6f1df8b76259acfc0d0566e8bf3610172b27884 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 12 Feb 2010 15:30:23 -0800 Subject: fix for Atom notice output: correct check against conversation & current id --- classes/Notice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'classes') diff --git a/classes/Notice.php b/classes/Notice.php index 924931e42..73b22d58a 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -1016,7 +1016,7 @@ class Notice extends Memcached_DataObject } if (!empty($this->conversation) - && $this->conversation != $this->notice->id) { + && $this->conversation != $this->id) { $xs->element( 'link', array( 'rel' => 'ostatus:conversation', -- cgit v1.2.3-54-g00ecf