From bc4e843f396dc450b04b612e7de14246084469d1 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 8 Feb 2010 19:22:55 -0800 Subject: Disable deprecated 'since' parameter on public_timeline API; causes performance problems. (since_id will work cleanly) --- actions/apitimelinepublic.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'actions') diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php index 3f4a46c0f..0fb0788e9 100644 --- a/actions/apitimelinepublic.php +++ b/actions/apitimelinepublic.php @@ -74,6 +74,10 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction parent::prepare($args); $this->notices = $this->getNotices(); + + if ($this->since) { + throw new ServerException("since parameter is disabled for performance; use since_id", 403); + } return true; } @@ -145,7 +149,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction $notice = Notice::publicStream( ($this->page - 1) * $this->count, $this->count, $this->since_id, - $this->max_id, $this->since + $this->max_id ); while ($notice->fetch()) { -- cgit v1.2.3-54-g00ecf From b56b154b51ede363ee8e49ec5b9b9332b8df923c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 8 Feb 2010 21:52:05 -0800 Subject: Better checking for duplicate app names --- actions/editapplication.php | 2 +- actions/newapplication.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'actions') diff --git a/actions/editapplication.php b/actions/editapplication.php index ca5dba1e4..64cf0a574 100644 --- a/actions/editapplication.php +++ b/actions/editapplication.php @@ -277,7 +277,7 @@ class EditApplicationAction extends OwnerDesignAction function nameExists($name) { $newapp = Oauth_application::staticGet('name', $name); - if (!$newapp) { + if (empty($newapp)) { return false; } else { return $newapp->id != $this->app->id; diff --git a/actions/newapplication.php b/actions/newapplication.php index c0c520797..0f819b349 100644 --- a/actions/newapplication.php +++ b/actions/newapplication.php @@ -290,7 +290,7 @@ class NewApplicationAction extends OwnerDesignAction function nameExists($name) { $app = Oauth_application::staticGet('name', $name); - return ($app !== false); + return !empty($app); } } -- cgit v1.2.3-54-g00ecf From 70d5f39ed66cb277e925ea71dcc24ca580110b3d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 8 Feb 2010 21:52:05 -0800 Subject: Better checking for duplicate app names --- actions/editapplication.php | 2 +- actions/newapplication.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'actions') diff --git a/actions/editapplication.php b/actions/editapplication.php index ca5dba1e4..64cf0a574 100644 --- a/actions/editapplication.php +++ b/actions/editapplication.php @@ -277,7 +277,7 @@ class EditApplicationAction extends OwnerDesignAction function nameExists($name) { $newapp = Oauth_application::staticGet('name', $name); - if (!$newapp) { + if (empty($newapp)) { return false; } else { return $newapp->id != $this->app->id; diff --git a/actions/newapplication.php b/actions/newapplication.php index c0c520797..0f819b349 100644 --- a/actions/newapplication.php +++ b/actions/newapplication.php @@ -290,7 +290,7 @@ class NewApplicationAction extends OwnerDesignAction function nameExists($name) { $app = Oauth_application::staticGet('name', $name); - return ($app !== false); + return !empty($app); } } -- cgit v1.2.3-54-g00ecf From 8449256817f5a2bd7a7cac6bc04e4cb477d7dc49 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 9 Feb 2010 18:32:52 -0800 Subject: OStatus partial support for group subscriptions: * detection of group feeds is currently a nasty hack based on presence of '/groups/' in URL -- should use some property on the feed? * listing for the remote group is kinda cruddy; needs to be named more cleanly * still need to establish per-author profiles (easier once we have the updated Atom code in) * group delivery probably not right yet * saving of group messages still triggering some weird behavior Added support for since_id and max_id on group timeline feeds as a free extra. Enjoy! --- actions/apitimelinegroup.php | 2 +- actions/showgroup.php | 4 +- classes/Notice.php | 4 +- classes/User_group.php | 4 +- lib/util.php | 2 +- plugins/OStatus/OStatusPlugin.php | 4 +- plugins/OStatus/actions/feedsubsettings.php | 22 +++++--- plugins/OStatus/classes/Feedinfo.php | 55 ++++++++++++++++++-- plugins/OStatus/lib/feedmunger.php | 4 +- plugins/OStatus/lib/hubdistribqueuehandler.php | 70 +++++++++++++++++++++++--- 10 files changed, 140 insertions(+), 31 deletions(-) (limited to 'actions') diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index af414c680..fd2ed9ff9 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -130,7 +130,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction case 'atom': $selfuri = common_root_url() . 'api/statusnet/groups/timeline/' . - $this->group->nickname . '.atom'; + $this->group->id . '.atom'; $this->showAtomTimeline( $this->notices, $title, diff --git a/actions/showgroup.php b/actions/showgroup.php index 8042a4951..eb1238902 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -330,13 +330,13 @@ class ShowgroupAction extends GroupDesignAction new Feed(Feed::RSS2, common_local_url('ApiTimelineGroup', array('format' => 'rss', - 'id' => $this->group->nickname)), + 'id' => $this->group->id)), sprintf(_('Notice feed for %s group (RSS 2.0)'), $this->group->nickname)), new Feed(Feed::ATOM, common_local_url('ApiTimelineGroup', array('format' => 'atom', - 'id' => $this->group->nickname)), + 'id' => $this->group->id)), sprintf(_('Notice feed for %s group (Atom)'), $this->group->nickname)), new Feed(Feed::FOAF, diff --git a/classes/Notice.php b/classes/Notice.php index fca1c599c..247440f29 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -783,7 +783,7 @@ class Notice extends Memcached_DataObject $result = $gi->insert(); - if (!result) { + if (!$result) { common_log_db_error($gi, 'INSERT', __FILE__); throw new ServerException(_('Problem saving group inbox.')); } @@ -917,7 +917,7 @@ class Notice extends Memcached_DataObject /** * Same calculation as saveGroups but without the saving * @fixme merge the functions - * @return array of Group objects + * @return array of Group_inbox objects */ function getGroups() { diff --git a/classes/User_group.php b/classes/User_group.php index c86eadf8f..1fbb50a6e 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -49,12 +49,12 @@ class User_group extends Memcached_DataObject array('id' => $this->id)); } - function getNotices($offset, $limit) + function getNotices($offset, $limit, $since_id=null, $max_id=null) { $ids = Notice::stream(array($this, '_streamDirect'), array(), 'user_group:notice_ids:' . $this->id, - $offset, $limit); + $offset, $limit, $since_id, $max_id); return Notice::getStreamByIds($ids); } diff --git a/lib/util.php b/lib/util.php index 00c21aeb2..a07fe49e3 100644 --- a/lib/util.php +++ b/lib/util.php @@ -697,7 +697,7 @@ function common_group_link($sender_id, $nickname) { $sender = Profile::staticGet($sender_id); $group = User_group::getForNickname($nickname); - if ($group && $sender->isMember($group)) { + if ($sender && $group && $sender->isMember($group)) { $attrs = array('href' => $group->permalink(), 'class' => 'url'); if (!empty($group->fullname)) { diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 60a4e3827..89b5c4caa 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -107,11 +107,11 @@ class OStatusPlugin extends Plugin /** * Set up a PuSH hub link to our internal link for canonical timeline - * Atom feeds for users. + * Atom feeds for users and groups. */ function onStartApiAtom(Action $action) { - if ($action instanceof ApiTimelineUserAction) { + if ($action instanceof ApiTimelineUserAction || $action instanceof ApiTimelineGroupAction) { $id = $action->arg('id'); if (strval(intval($id)) === strval($id)) { // Canonical form of id in URL? diff --git a/plugins/OStatus/actions/feedsubsettings.php b/plugins/OStatus/actions/feedsubsettings.php index 4d5b7b60f..6f592bf5b 100644 --- a/plugins/OStatus/actions/feedsubsettings.php +++ b/plugins/OStatus/actions/feedsubsettings.php @@ -209,7 +209,7 @@ class FeedSubSettingsAction extends ConnectSettingsAction return; } } - + // And subscribe the current user to the local profile $user = common_current_user(); $profile = $this->feedinfo->getProfile(); @@ -217,12 +217,22 @@ class FeedSubSettingsAction extends ConnectSettingsAction throw new ServerException("Feed profile was not saved properly."); } - if ($user->isSubscribed($profile)) { - $this->showForm(_m('Already subscribed!')); - } elseif ($user->subscribeTo($profile)) { - $this->showForm(_m('Feed subscribed!')); + if ($this->feedinfo->isGroup()) { + if ($user->isMember($profile)) { + $this->showForm(_m('Already a member!')); + } elseif (Group_member::join($this->feedinfo->group_id, $user->id)) { + $this->showForm(_m('Joined remote group!')); + } else { + $this->showForm(_m('Remote group join failed!')); + } } else { - $this->showForm(_m('Feed subscription failed!')); + if ($user->isSubscribed($profile)) { + $this->showForm(_m('Already subscribed!')); + } elseif ($user->subscribeTo($profile)) { + $this->showForm(_m('Feed subscribed!')); + } else { + $this->showForm(_m('Feed subscription failed!')); + } } } } diff --git a/plugins/OStatus/classes/Feedinfo.php b/plugins/OStatus/classes/Feedinfo.php index 107faf012..792ea6034 100644 --- a/plugins/OStatus/classes/Feedinfo.php +++ b/plugins/OStatus/classes/Feedinfo.php @@ -89,7 +89,8 @@ class Feedinfo extends Memcached_DataObject function table() { return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, - 'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'profile_id' => DB_DATAOBJECT_INT, + 'group_id' => DB_DATAOBJECT_INT, 'feeduri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'homeuri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'huburi' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, @@ -111,7 +112,9 @@ class Feedinfo extends Memcached_DataObject /*extra*/ null, /*auto_increment*/ true), new ColumnDef('profile_id', 'integer', - null, false), + null, true), + new ColumnDef('group_id', 'integer', + null, true), new ColumnDef('feeduri', 'varchar', 255, false, 'UNI'), new ColumnDef('homeuri', 'varchar', @@ -176,6 +179,7 @@ class Feedinfo extends Memcached_DataObject /** * @param FeedMunger $munger + * @param boolean $isGroup is this a group record? * @return Feedinfo */ public static function ensureProfile($munger) @@ -217,6 +221,22 @@ class Feedinfo extends Memcached_DataObject } $feedinfo->profile_id = $profile->id; + if ($feedinfo->isGroup()) { + $group = new User_group(); + $group->nickname = $profile->nickname . '@remote'; // @fixme + $group->fullname = $profile->fullname; + $group->homepage = $profile->homepage; + $group->location = $profile->location; + $group->created = $profile->created; + $group->insert(); + + if ($avatar) { + $group->setOriginal($filename); + } + + $feedinfo->group_id = $group->id; + } + $result = $feedinfo->insert(); if (empty($result)) { throw new FeedDBException($feedinfo); @@ -231,6 +251,14 @@ class Feedinfo extends Memcached_DataObject return $feedinfo; } + /** + * Damn dirty hack! + */ + function isGroup() + { + return (strpos($this->feeduri, '/groups/') !== false); + } + /** * Send a subscription request to the hub for this feed. * The hub will later send us a confirmation POST to /feedsub/callback. @@ -325,17 +353,34 @@ class Feedinfo extends Memcached_DataObject $dupe = new Notice(); $dupe->uri = $notice->uri; if ($dupe->find(true)) { + // @fixme we might have to do individual and group delivery separately! common_log(LOG_WARNING, __METHOD__ . ": tried to save dupe notice for entry {$notice->uri} of feed {$this->feeduri}"); continue; } - + if (Event::handle('StartNoticeSave', array(&$notice))) { $id = $notice->insert(); Event::handle('EndNoticeSave', array($notice)); } - $notice->addToInboxes(); - common_log(LOG_INFO, __METHOD__ . ": saved notice {$notice->id} for entry $index of update to \"{$this->feeduri}\""); + + common_log(LOG_DEBUG, "going to check group delivery..."); + if ($this->group_id) { + $group = User_group::staticGet($this->group_id); + if ($group) { + common_log(LOG_INFO, __METHOD__ . ": saving to local shadow group $group->id $group->nickname"); + $groups = array($group); + } else { + common_log(LOG_INFO, __METHOD__ . ": lost the local shadow group?"); + } + } else { + common_log(LOG_INFO, __METHOD__ . ": no local shadow groups"); + $groups = array(); + } + common_log(LOG_DEBUG, "going to add to inboxes..."); + $notice->addToInboxes($groups, array()); + common_log(LOG_DEBUG, "added to inboxes."); + $hits++; } if ($hits == 0) { diff --git a/plugins/OStatus/lib/feedmunger.php b/plugins/OStatus/lib/feedmunger.php index cbaec6775..5dce95342 100644 --- a/plugins/OStatus/lib/feedmunger.php +++ b/plugins/OStatus/lib/feedmunger.php @@ -203,7 +203,7 @@ class FeedMunger if (!$entry) { return null; } - + if ($preview) { $notice = new FeedSubPreviewNotice($this->profile(true)); $notice->id = -1; @@ -221,7 +221,7 @@ class FeedMunger $notice->uri = $link; $notice->url = $link; $notice->content = $this->noticeFromEntry($entry); - $notice->rendered = common_render_content($notice->content, $notice); + $notice->rendered = common_render_content($notice->content, $notice); // @fixme this is failing on group posts $notice->created = common_sql_date($entry->updated); // @fixme $notice->is_local = Notice::GATEWAY; $notice->source = 'feed'; diff --git a/plugins/OStatus/lib/hubdistribqueuehandler.php b/plugins/OStatus/lib/hubdistribqueuehandler.php index 126f1355f..189ccbedf 100644 --- a/plugins/OStatus/lib/hubdistribqueuehandler.php +++ b/plugins/OStatus/lib/hubdistribqueuehandler.php @@ -34,6 +34,14 @@ class HubDistribQueueHandler extends QueueHandler { assert($notice instanceof Notice); + $this->pushUser($notice); + foreach ($notice->getGroups() as $group) { + $this->pushGroup($notice, $group->group_id); + } + } + + function pushUser($notice) + { // See if there's any PuSH subscriptions, including OStatus clients. // @fixme handle group subscriptions as well // http://identi.ca/api/statuses/user_timeline/1.atom @@ -43,20 +51,42 @@ class HubDistribQueueHandler extends QueueHandler $sub = new HubSub(); $sub->topic = $feed; if ($sub->find()) { - common_log(LOG_INFO, "Preparing $sub->N PuSH distribution(s) for $feed"); - $qm = QueueManager::get(); $atom = $this->userFeedForNotice($notice); - while ($sub->fetch()) { - common_log(LOG_INFO, "Prepping PuSH distribution to $sub->callback for $feed"); - $data = array('sub' => clone($sub), - 'atom' => $atom); - $qm->enqueue($data, 'hubout'); - } + $this->pushFeeds($atom, $sub); } else { common_log(LOG_INFO, "No PuSH subscribers for $feed"); } } + function pushGroup($notice, $group_id) + { + $feed = common_local_url('ApiTimelineGroup', + array('id' => $group_id, + 'format' => 'atom')); + $sub = new HubSub(); + $sub->topic = $feed; + if ($sub->find()) { + common_log(LOG_INFO, "Building PuSH feed for $feed"); + $atom = $this->groupFeedForNotice($group_id, $notice); + $this->pushFeeds($atom, $sub); + } else { + common_log(LOG_INFO, "No PuSH subscribers for $feed"); + } + } + + + function pushFeeds($atom, $sub) + { + common_log(LOG_INFO, "Preparing $sub->N PuSH distribution(s) for $sub->topic"); + $qm = QueueManager::get(); + while ($sub->fetch()) { + common_log(LOG_INFO, "Prepping PuSH distribution to $sub->callback for $sub->topic"); + $data = array('sub' => clone($sub), + 'atom' => $atom); + $qm->enqueue($data, 'hubout'); + } + } + /** * Build a single-item version of the sending user's Atom feed. * @param Notice $notice @@ -83,5 +113,29 @@ class HubDistribQueueHandler extends QueueHandler common_log(LOG_DEBUG, $feed); return $feed; } + + function groupFeedForNotice($group_id, $notice) + { + // @fixme this feels VERY hacky... + // should probably be a cleaner way to do it + + ob_start(); + $api = new ApiTimelineGroupAction(); + $args = array('id' => $group_id, + 'format' => 'atom', + 'max_id' => $notice->id, + 'since_id' => $notice->id - 1); + $api->prepare($args); + $api->handle($args); + $feed = ob_get_clean(); + + // ...and override the content-type back to something normal... eww! + // hope there's no other headers that got set while we weren't looking. + header('Content-Type: text/html; charset=utf-8'); + + common_log(LOG_DEBUG, $feed); + return $feed; + } + } -- cgit v1.2.3-54-g00ecf From ce3c3be1bf971329f82bedbf3aae636e3c8ecbf9 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 10 Feb 2010 14:24:16 -0800 Subject: Utility classes for atom feeds --- actions/apitimelineuser.php | 39 +++++++++- lib/atom10entry.php | 58 +++++++++++++++ lib/atom10feed.php | 177 ++++++++++++++++++++++++++++++++++++++++++++ lib/atomnoticefeed.php | 34 +++++++++ 4 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 lib/atom10entry.php create mode 100644 lib/atom10feed.php create mode 100644 lib/atomnoticefeed.php (limited to 'actions') diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index ed9104905..bcc48f59c 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -145,7 +145,26 @@ class ApiTimelineUserAction extends ApiBareAuthAction ); break; case 'atom': + + header('Content-Type: application/atom+xml; charset=utf-8'); + + $atom = new AtomNoticeFeed(); + + $atom->addLink( + common_local_url( + 'showstream', + array('nickname' => $this->user->nickname) + ) + ); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); + $id = $this->arg('id'); + if ($id) { $selfuri = common_root_url() . 'api/statuses/user_timeline/' . @@ -154,10 +173,24 @@ class ApiTimelineUserAction extends ApiBareAuthAction $selfuri = common_root_url() . 'api/statuses/user_timeline.atom'; } - $this->showAtomTimeline( - $this->notices, $title, $id, $link, - $subtitle, $suplink, $selfuri, $logo + + $atom->addLink( + $selfuri, + array('rel' => 'self', 'type' => 'application/atom+xml') + ); + + $atom->addLink( + $suplink, + array( + 'rel' => 'http://api.friendfeed.com/2008/03#sup', + 'type' => 'application/json' + ) ); + + $atom->addEntryFromNotices($this->notices); + + print $atom->getString(); + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/lib/atom10entry.php b/lib/atom10entry.php new file mode 100644 index 000000000..1b79ce7ad --- /dev/null +++ b/lib/atom10entry.php @@ -0,0 +1,58 @@ +namespaces = array(); + } + + function addNamespace($namespace, $uri) + { + $ns = array($namespace => $uri); + $this->namespaces = array_merge($this->namespaces, $ns); + } + + function initEntry() + { + + } + + function endEntry() + { + + } + + function validate + { + + } + + function getString() + { + $this->validate(); + + $this->initEntry(); + $this->renderEntries(); + $this->endEntry(); + + return $this->xw->outputMemory(); + } + +} \ No newline at end of file diff --git a/lib/atom10feed.php b/lib/atom10feed.php new file mode 100644 index 000000000..9dd8ebc9b --- /dev/null +++ b/lib/atom10feed.php @@ -0,0 +1,177 @@ +namespaces = array(); + $this->links = array(); + $this->entries = array(); + $this->addNamespace('xmlns', 'http://www.w3.org/2005/Atom'); + } + + function addNamespace($namespace, $uri) + { + $ns = array($namespace => $uri); + $this->namespaces = array_merge($this->namespaces, $ns); + } + + function getNamespaces() + { + return $this->namespaces; + } + + function initFeed() + { + $this->xw->startDocument('1.0', 'UTF-8'); + $commonAttrs = array('xml:lang' => 'en-US'); + $commonAttrs = array_merge($commonAttrs, $this->namespaces); + $this->elementStart('feed', $commonAttrs); + + $this->element('id', null, $this->id); + $this->element('title', null, $this->title); + $this->element('subtitle', null, $this->subtitle); + $this->element('logo', null, $this->logo); + $this->element('updated', null, $this->updated); + + $this->renderLinks(); + } + + /** + * Check that all required elements have been set, etc. + * Throws an Atom10FeedException if something's missing. + * + * @return void + */ + function validate() + { + } + + function renderLinks() + { + foreach ($this->links as $attrs) + { + $this->element('link', $attrs, null); + } + } + + function addEntryRaw($entry) + { + array_push($this->entries, $entry); + } + + function addEntry($entry) + { + array_push($this->entries, $entry->getString()); + } + + function renderEntries() + { + foreach ($this->entries as $entry) { + $this->raw($entry); + } + } + + function endFeed() + { + $this->elementEnd('feed'); + $this->xw->endDocument(); + } + + function getString() + { + $this->validate(); + + $this->initFeed(); + $this->renderEntries(); + $this->endFeed(); + + return $this->xw->outputMemory(); + } + + function setId($id) + { + $this->id = $id; + } + + function setTitle($title) + { + $this->title = $title; + } + + function setSubtitle($subtitle) + { + $this->subtitle = $subtitle; + } + + function setLogo($logo) + { + $this->logo = $logo; + } + + function setUpdated($dt) + { + $this->updated = common_date_iso8601($dt); + } + + function setPublished($dt) + { + $this->published = common_date_iso8601($dt); + } + + /** + * Adds a link element into the Atom document + * + * 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 array $otherAttrs other attributes to stick in + * + * @return void + */ + function addLink($uri, $otherAttrs = null) { + $attrs = array('href' => $uri); + + if (is_null($otherAttrs)) { + $attrs['rel'] = 'alternate'; + $attrs['type'] = 'text/html'; + } else { + $attrs = array_merge($attrs, $otherAttrs); + } + + array_push($this->links, $attrs); + } + +} + + + diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php new file mode 100644 index 000000000..a28c9cda7 --- /dev/null +++ b/lib/atomnoticefeed.php @@ -0,0 +1,34 @@ +addNamespace( + 'xmlns:thr', + 'http://purl.org/syndication/thread/1.0' + ); + } + + function addEntryFromNotices($notices) + { + if (is_array($notices)) { + foreach ($notices as $notice) { + $this->addEntryFromNotice($notice); + } + } else { + while ($notices->fetch()) { + $this->addEntryFromNotice($notice); + } + } + } + + function addEntryFromNotice($notice) + { + $this->addEntryRaw($notice->asAtomEntry()); + } + +} \ No newline at end of file -- 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 'actions') 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 c465f675d9dbcf9f808bc31a1d01e753df4ddf58 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 11 Feb 2010 13:54:40 -0800 Subject: Make Atom timelines in the API use Atom10feed --- actions/apitimelinefavorites.php | 69 ++++++++++++++++++++++++++-------- actions/apitimelinefriends.php | 74 ++++++++++++++++++++++++++----------- actions/apitimelinehome.php | 60 ++++++++++++++++++++++-------- actions/apitimelinementions.php | 34 ++++++++++++++--- actions/apitimelinepublic.php | 27 +++++++++++--- actions/apitimelineretweetsofme.php | 36 ++++++++++++++++-- actions/apitimelinetag.php | 51 ++++++++++++++++++------- actions/apitimelineuser.php | 25 +++++-------- lib/api.php | 18 +++++++++ lib/atom10feed.php | 8 +++- lib/atomnoticefeed.php | 4 +- 11 files changed, 308 insertions(+), 98 deletions(-) (limited to 'actions') diff --git a/actions/apitimelinefavorites.php b/actions/apitimelinefavorites.php index 1027d97d4..f7f900ddf 100644 --- a/actions/apitimelinefavorites.php +++ b/actions/apitimelinefavorites.php @@ -100,11 +100,11 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction function showTimeline() { - $profile = $this->user->getProfile(); - $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); + $profile = $this->user->getProfile(); + $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); - $sitename = common_config('site', 'name'); - $title = sprintf( + $sitename = common_config('site', 'name'); + $title = sprintf( _('%1$s / Favorites from %2$s'), $sitename, $this->user->nickname @@ -112,32 +112,69 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction $taguribase = common_config('integration', 'taguri'); $id = "tag:$taguribase:Favorites:" . $this->user->id; - $link = common_local_url( - 'favorites', - array('nickname' => $this->user->nickname) - ); - $subtitle = sprintf( + + $subtitle = sprintf( _('%1$s updates favorited by %2$s / %2$s.'), $sitename, $profile->getBestName(), $this->user->nickname ); - $logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE); + $logo = !empty($avatar) + ? $avatar->displayUrl() + : Avatar::defaultImage(AVATAR_PROFILE_SIZE); switch($this->format) { case 'xml': $this->showXmlTimeline($this->notices); break; case 'rss': - $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo); + $link = common_local_url( + 'showfavorites', + array('nickname' => $this->user->nickname) + ); + $this->showRssTimeline( + $this->notices, + $title, + $link, + $subtitle, + null, + $logo + ); break; case 'atom': - $selfuri = common_root_url() . - ltrim($_SERVER['QUERY_STRING'], 'p='); - $this->showAtomTimeline( - $this->notices, $title, $id, $link, $subtitle, - null, $selfuri, $logo + + header('Content-Type: application/atom+xml; charset=utf-8'); + + $atom = new AtomNoticeFeed(); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); + + $atom->addLink( + common_local_url( + 'showfavorites', + array('nickname' => $this->user->nickname) + ) + ); + + $id = $this->arg('id'); + $aargs = array('format' => 'atom'); + if (!empty($id)) { + $aargs['id'] = $id; + } + + $atom->addLink( + $this->getSelfUri('ApiTimelineFavorites', $aargs), + array('rel' => 'self', 'type' => 'application/atom+xml') ); + + $atom->addEntryFromNotices($this->notices); + + $this->raw($atom->getString()); + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php index 4e3827bae..0af04fe4f 100644 --- a/actions/apitimelinefriends.php +++ b/actions/apitimelinefriends.php @@ -114,39 +114,71 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction $title = sprintf(_("%s and friends"), $this->user->nickname); $taguribase = common_config('integration', 'taguri'); $id = "tag:$taguribase:FriendsTimeline:" . $this->user->id; - $link = common_local_url( - 'all', array('nickname' => $this->user->nickname) - ); - $subtitle = sprintf( - _('Updates from %1$s and friends on %2$s!'), - $this->user->nickname, $sitename - ); - $logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE); + + $subtitle = sprintf( + _('Updates from %1$s and friends on %2$s!'), + $this->user->nickname, $sitename + ); + + $logo = (!empty($avatar)) + ? $avatar->displayUrl() + : Avatar::defaultImage(AVATAR_PROFILE_SIZE); switch($this->format) { case 'xml': $this->showXmlTimeline($this->notices); break; case 'rss': - $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo); + + $link = common_local_url( + 'all', array( + 'nickname' => $this->user->nickname + ) + ); + + $this->showRssTimeline( + $this->notices, + $title, + $link, + $subtitle, + null, + $logo + ); break; case 'atom': - $target_id = $this->arg('id'); + header('Content-Type: application/atom+xml; charset=utf-8'); + + $atom = new AtomNoticeFeed(); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); - if (isset($target_id)) { - $selfuri = common_root_url() . - 'api/statuses/friends_timeline/' . - $target_id . '.atom'; - } else { - $selfuri = common_root_url() . - 'api/statuses/friends_timeline.atom'; + $atom->addLink( + common_local_url( + 'all', + array('nickname' => $this->user->nickname) + ) + ); + + $id = $this->arg('id'); + $aargs = array('format' => 'atom'); + if (!empty($id)) { + $aargs['id'] = $id; } - $this->showAtomTimeline( - $this->notices, $title, $id, $link, - $subtitle, null, $selfuri, $logo - ); + $atom->addLink( + $this->getSelfUri('ApiTimelineFriends', $aargs), + array('rel' => 'self', 'type' => 'application/atom+xml') + ); + + $atom->addEntryFromNotices($this->notices); + + $this->raw($atom->getString()); + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/actions/apitimelinehome.php b/actions/apitimelinehome.php index 828eae6cf..ae4168070 100644 --- a/actions/apitimelinehome.php +++ b/actions/apitimelinehome.php @@ -115,39 +115,67 @@ class ApiTimelineHomeAction extends ApiBareAuthAction $title = sprintf(_("%s and friends"), $this->user->nickname); $taguribase = common_config('integration', 'taguri'); $id = "tag:$taguribase:HomeTimeline:" . $this->user->id; - $link = common_local_url( - 'all', array('nickname' => $this->user->nickname) - ); + $subtitle = sprintf( _('Updates from %1$s and friends on %2$s!'), $this->user->nickname, $sitename ); - $logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE); + + $logo = (!empty($avatar)) + ? $avatar->displayUrl() + : Avatar::defaultImage(AVATAR_PROFILE_SIZE); switch($this->format) { case 'xml': $this->showXmlTimeline($this->notices); break; case 'rss': - $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo); + $link = common_local_url( + 'all', + array('nickname' => $this->user->nickname) + ); + $this->showRssTimeline( + $this->notices, + $title, + $link, + $subtitle, + null, + $logo + ); break; case 'atom': - $target_id = $this->arg('id'); + header('Content-Type: application/atom+xml; charset=utf-8'); + + $atom = new AtomNoticeFeed(); - if (isset($target_id)) { - $selfuri = common_root_url() . - 'api/statuses/home_timeline/' . - $target_id . '.atom'; - } else { - $selfuri = common_root_url() . - 'api/statuses/home_timeline.atom'; + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); + + $atom->addLink( + common_local_url( + 'all', + array('nickname' => $this->user->nickname) + ) + ); + + $id = $this->arg('id'); + $aargs = array('format' => 'atom'); + if (!empty($id)) { + $aargs['id'] = $id; } - $this->showAtomTimeline( - $this->notices, $title, $id, $link, - $subtitle, null, $selfuri, $logo + $atom->addLink( + $this->getSelfUri('ApiTimelineHome', $aargs), + array('rel' => 'self', 'type' => 'application/atom+xml') ); + + $atom->addEntryFromNotices($this->notices); + $this->raw($atom->getString()); + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/actions/apitimelinementions.php b/actions/apitimelinementions.php index 9dc2162cc..d2e31d0bd 100644 --- a/actions/apitimelinementions.php +++ b/actions/apitimelinementions.php @@ -137,12 +137,36 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo); break; case 'atom': - $selfuri = common_root_url() . - ltrim($_SERVER['QUERY_STRING'], 'p='); - $this->showAtomTimeline( - $this->notices, $title, $id, $link, $subtitle, - null, $selfuri, $logo + + $atom = new AtomNoticeFeed(); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); + + $atom->addLink( + common_local_url( + 'replies', + array('nickname' => $this->user->nickname) + ) + ); + + $id = $this->arg('id'); + $aargs = array('format' => 'atom'); + if (!empty($id)) { + $aargs['id'] = $id; + } + + $atom->addLink( + $this->getSelfUri('ApiTimelineMentions', $aargs), + array('rel' => 'self', 'type' => 'application/atom+xml') ); + + $atom->addEntryFromNotices($this->notices); + $this->raw($atom->getString()); + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php index 0fb0788e9..c1fa72a3e 100644 --- a/actions/apitimelinepublic.php +++ b/actions/apitimelinepublic.php @@ -74,7 +74,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction parent::prepare($args); $this->notices = $this->getNotices(); - + if ($this->since) { throw new ServerException("since parameter is disabled for performance; use since_id", 403); } @@ -122,11 +122,28 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $sitelogo); break; case 'atom': - $selfuri = common_root_url() . 'api/statuses/public_timeline.atom'; - $this->showAtomTimeline( - $this->notices, $title, $id, $link, - $subtitle, null, $selfuri, $sitelogo + + $atom = new AtomNoticeFeed(); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($sitelogo); + $atom->setUpdated('now'); + + $atom->addLink(common_local_url('public')); + + $atom->addLink( + $this->getSelfUri( + 'ApiTimelinePublic', array('format' => 'atom') + ), + array('rel' => 'self', 'type' => 'application/atom+xml') ); + + $atom->addEntryFromNotices($this->notices); + + $this->raw($atom->getString()); + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/actions/apitimelineretweetsofme.php b/actions/apitimelineretweetsofme.php index e4b09e9bd..26706a75e 100644 --- a/actions/apitimelineretweetsofme.php +++ b/actions/apitimelineretweetsofme.php @@ -99,6 +99,8 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction $strm = $this->auth_user->repeatsOfMe($offset, $limit, $this->since_id, $this->max_id); + common_debug(var_export($strm, true)); + switch ($this->format) { case 'xml': $this->showXmlTimeline($strm); @@ -112,10 +114,38 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction $title = sprintf(_("Repeats of %s"), $this->auth_user->nickname); $taguribase = common_config('integration', 'taguri'); $id = "tag:$taguribase:RepeatsOfMe:" . $this->auth_user->id; - $link = common_local_url('showstream', - array('nickname' => $this->auth_user->nickname)); - $this->showAtomTimeline($strm, $title, $id, $link); + header('Content-Type: application/atom+xml; charset=utf-8'); + + $atom = new AtomNoticeFeed(); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setUpdated('now'); + + $atom->addLink( + common_local_url( + 'showstream', + array('nickname' => $this->auth_user->nickname) + ) + ); + + $id = $this->arg('id'); + $aargs = array('format' => 'atom'); + if (!empty($id)) { + $aargs['id'] = $id; + } + + $atom->addLink( + $this->getSelfUri('ApiTimelineRetweetsOfMe', $aargs), + array('rel' => 'self', 'type' => 'application/atom+xml') + ); + + $atom->addEntryFromNotices($strm); + + $this->raw($atom->getString()); + break; default: diff --git a/actions/apitimelinetag.php b/actions/apitimelinetag.php index 1427d23b6..5b6ded4c0 100644 --- a/actions/apitimelinetag.php +++ b/actions/apitimelinetag.php @@ -100,10 +100,6 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction $sitename = common_config('site', 'name'); $sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'); $title = sprintf(_("Notices tagged with %s"), $this->tag); - $link = common_local_url( - 'tag', - array('tag' => $this->tag) - ); $subtitle = sprintf( _('Updates tagged with %1$s on %2$s!'), $this->tag, @@ -117,22 +113,51 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction $this->showXmlTimeline($this->notices); break; case 'rss': - $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $sitelogo); - break; - case 'atom': - $selfuri = common_root_url() . - 'api/statusnet/tags/timeline/' . - $this->tag . '.atom'; - $this->showAtomTimeline( + $link = common_local_url( + 'tag', + array('tag' => $this->tag) + ); + $this->showRssTimeline( $this->notices, $title, - $id, $link, $subtitle, null, - $selfuri, $sitelogo ); + break; + case 'atom': + + header('Content-Type: application/atom+xml; charset=utf-8'); + + $atom = new AtomNoticeFeed(); + + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); + + $atom->addLink( + common_local_url( + 'tag', + array('tag' => $this->tag) + ) + ); + + $aargs = array('format' => 'atom'); + if (!empty($this->tag)) { + $aargs['tag'] = $this->tag; + } + + $atom->addLink( + $this->getSelfUri('ApiTimelineTag', $aargs), + array('rel' => 'self', 'type' => 'application/atom+xml') + ); + + $atom->addEntryFromNotices($this->notices); + $this->raw($atom->getString()); + break; case 'json': $this->showJsonTimeline($this->notices); diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index cb8213619..d20bb0d20 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -150,6 +150,12 @@ class ApiTimelineUserAction extends ApiBareAuthAction $atom = new AtomNoticeFeed(); + $atom->setId($id); + $atom->setTitle($title); + $atom->setSubtitle($subtitle); + $atom->setLogo($logo); + $atom->setUpdated('now'); + $atom->addLink( common_local_url( 'showstream', @@ -157,25 +163,14 @@ class ApiTimelineUserAction extends ApiBareAuthAction ) ); - $atom->setId($id); - $atom->setTitle($title); - $atom->setSubtitle($subtitle); - $atom->setLogo($logo); - $atom->setUpdated('now'); - $id = $this->arg('id'); - - if ($id) { - $selfuri = common_root_url() . - 'api/statuses/user_timeline/' . - rawurlencode($id) . '.atom'; - } else { - $selfuri = common_root_url() . - 'api/statuses/user_timeline.atom'; + $aargs = array('format' => 'atom'); + if (!empty($id)) { + $aargs['id'] = $id; } $atom->addLink( - $selfuri, + $this->getSelfUri('ApiTimelineUser', $aargs), array('rel' => 'self', 'type' => 'application/atom+xml') ); diff --git a/lib/api.php b/lib/api.php index fd07bbbbe..8f1fe1ef7 100644 --- a/lib/api.php +++ b/lib/api.php @@ -1321,4 +1321,22 @@ class ApiAction extends Action } } + function getSelfUri($action, $aargs) + { + parse_str($_SERVER['QUERY_STRING'], $params); + $pstring = ''; + if (!empty($params)) { + unset($params['p']); + $pstring = http_build_query($params); + } + + $uri = common_local_url($action, $aargs); + + if (!empty($pstring)) { + $uri .= '?' . $pstring; + } + + return $uri; + } + } diff --git a/lib/atom10feed.php b/lib/atom10feed.php index a37f6521a..ccca76a09 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -27,7 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') +if (!defined('STATUSNET')) { exit(1); } @@ -108,7 +108,11 @@ class Atom10Feed extends XMLStringer $this->element('id', null, $this->id); $this->element('title', null, $this->title); $this->element('subtitle', null, $this->subtitle); - $this->element('logo', null, $this->logo); + + if (!empty($this->logo)) { + $this->element('logo', null, $this->logo); + } + $this->element('updated', null, $this->updated); $this->renderLinks(); diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index a626ab549..34ed44b2e 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -27,7 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') +if (!defined('STATUSNET')) { exit(1); } @@ -85,7 +85,7 @@ class AtomNoticeFeed extends Atom10Feed } } else { while ($notices->fetch()) { - $this->addEntryFromNotice($notice); + $this->addEntryFromNotice($notices); } } } -- cgit v1.2.3-54-g00ecf