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 --- lib/api.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'lib/api.php') 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; + } + } -- 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 'lib/api.php') 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 f3a82e787c70e8cf749c79f22fe37ce6c9c9d4d3 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 12 Feb 2010 19:00:35 -0800 Subject: Add OStatus PuSH hub and Salmon links back into user and group feeds --- actions/apitimelinegroup.php | 14 +++++++- actions/apitimelineuser.php | 14 +++++++- lib/api.php | 1 - lib/atom10feed.php | 21 +++++++----- lib/atomgroupnoticefeed.php | 67 +++++++++++++++++++++++++++++++++++++++ lib/atomnoticefeed.php | 4 ++- lib/atomusernoticefeed.php | 66 ++++++++++++++++++++++++++++++++++++++ plugins/OStatus/OStatusPlugin.php | 37 +++++++++++---------- 8 files changed, 193 insertions(+), 31 deletions(-) create mode 100644 lib/atomgroupnoticefeed.php create mode 100644 lib/atomusernoticefeed.php (limited to 'lib/api.php') diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php index 45962fa76..3c74e36b5 100644 --- a/actions/apitimelinegroup.php +++ b/actions/apitimelinegroup.php @@ -138,7 +138,19 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction try { - $atom = new AtomNoticeFeed(); + // If this was called using an integer ID, i.e.: using the canonical + // URL for this group's feed, then pass the Group object into the feed, + // so the OStatus plugin, and possibly other plugins, can access it. + // Feels sorta hacky. -- Z + + $atom = null; + $id = $this->arg('id'); + + if (strval(intval($id)) === strval($id)) { + $atom = new AtomGroupNoticeFeed($this->group); + } else { + $atom = new AtomGroupNoticeFeed(); + } $atom->setId($id); $atom->setTitle($title); diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index d20bb0d20..24752e45f 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -148,7 +148,19 @@ class ApiTimelineUserAction extends ApiBareAuthAction header('Content-Type: application/atom+xml; charset=utf-8'); - $atom = new AtomNoticeFeed(); + // If this was called using an integer ID, i.e.: using the canonical + // URL for this user's feed, then pass the User object into the feed, + // so the OStatus plugin, and possibly other plugins, can access it. + // Feels sorta hacky. -- Z + + $atom = null; + $id = $this->arg('id'); + + if (strval(intval($id)) === strval($id)) { + $atom = new AtomUserNoticeFeed($this->user); + } else { + $atom = new AtomUserNoticeFeed(); + } $atom->setId($id); $atom->setTitle($title); diff --git a/lib/api.php b/lib/api.php index 494b595d1..22eef7436 100644 --- a/lib/api.php +++ b/lib/api.php @@ -1154,7 +1154,6 @@ class ApiAction extends Action $this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom', 'xml:lang' => 'en-US', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0')); - Event::handle('StartApiAtom', array($this)); } function endTwitterAtom() diff --git a/lib/atom10feed.php b/lib/atom10feed.php index 806a9684b..14a3beb83 100644 --- a/lib/atom10feed.php +++ b/lib/atom10feed.php @@ -175,6 +175,8 @@ class Atom10Feed extends XMLStringer $this->element('updated', null, $this->updated); + $this->renderAuthors(); + $this->renderLinks(); } @@ -221,17 +223,20 @@ class Atom10Feed extends XMLStringer function getString() { - $this->validate(); + if (Event::handle('StartApiAtom', array($this))) { - $this->initFeed(); - $this->renderAuthors(); + $this->validate(); + $this->initFeed(); - if (!empty($this->subject)) { - $this->raw($this->subject); - } + if (!empty($this->subject)) { + $this->raw($this->subject); + } + + $this->renderEntries(); + $this->endFeed(); - $this->renderEntries(); - $this->endFeed(); + Event::handle('EndApiAtom', array($this)); + } return $this->xw->outputMemory(); } diff --git a/lib/atomgroupnoticefeed.php b/lib/atomgroupnoticefeed.php new file mode 100644 index 000000000..52ee4c7d6 --- /dev/null +++ b/lib/atomgroupnoticefeed.php @@ -0,0 +1,67 @@ +. + * + * @category Feed + * @package StatusNet + * @author Zach Copley + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) +{ + exit(1); +} + +/** + * Class for group notice feeds. May contains a reference to the group. + * + * @category Feed + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ +class AtomGroupNoticeFeed extends AtomNoticeFeed +{ + private $group; + + /** + * Constructor + * + * @param Group $group the group for the feed (optional) + * @param boolean $indent flag to turn indenting on or off + * + * @return void + */ + function __construct($group = null, $indent = true) { + parent::__construct($indent); + $this->group = $group; + } + + function getGroup() + { + return $this->group; + } + +} diff --git a/lib/atomnoticefeed.php b/lib/atomnoticefeed.php index 34ed44b2e..b7a60bde6 100644 --- a/lib/atomnoticefeed.php +++ b/lib/atomnoticefeed.php @@ -2,7 +2,7 @@ /** * StatusNet, the distributed open-source microblogging tool * - * Class for building and Atom feed from a collection of notices + * Class for building an Atom feed from a collection of notices * * PHP version 5 * @@ -101,3 +101,5 @@ class AtomNoticeFeed extends Atom10Feed } } + + diff --git a/lib/atomusernoticefeed.php b/lib/atomusernoticefeed.php new file mode 100644 index 000000000..9f224325c --- /dev/null +++ b/lib/atomusernoticefeed.php @@ -0,0 +1,66 @@ +. + * + * @category Feed + * @package StatusNet + * @author Zach Copley + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) +{ + exit(1); +} + +/** + * Class for user notice feeds. May contain a reference to the user. + * + * @category Feed + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ +class AtomUserNoticeFeed extends AtomNoticeFeed +{ + private $user; + + /** + * Constructor + * + * @param User $user the user for the feed (optional) + * @param boolean $indent flag to turn indenting on or off + * + * @return void + */ + function __construct($user = null, $indent = true) { + parent::__construct($indent); + $this->user = $user; + } + + function getUser() + { + return $this->user; + } +} diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 8444c3d73..bf7dde296 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -63,9 +63,9 @@ class OStatusPlugin extends Plugin $m->connect('main/ostatus?nickname=:nickname', array('action' => 'ostatusinit'), array('nickname' => '[A-Za-z0-9_-]+')); $m->connect('main/ostatussub', - array('action' => 'ostatussub')); + array('action' => 'ostatussub')); $m->connect('main/ostatussub', - array('action' => 'ostatussub'), array('feed' => '[A-Za-z0-9\.\/\:]+')); + array('action' => 'ostatussub'), array('feed' => '[A-Za-z0-9\.\/\:]+')); // PuSH actions $m->connect('main/push/hub', array('action' => 'pushhub')); @@ -112,35 +112,34 @@ class OStatusPlugin extends Plugin * Set up a PuSH hub link to our internal link for canonical timeline * Atom feeds for users and groups. */ - function onStartApiAtom(Action $action) + function onStartApiAtom(AtomNoticeFeed $feed) { - if ($action instanceof ApiTimelineUserAction) { + $id = null; + + if ($feed instanceof AtomUserNoticeFeed) { $salmonAction = 'salmon'; - } else if ($action instanceof ApiTimelineGroupAction) { + $id = $feed->getUser()->id; + } else if ($feed instanceof AtomGroupNoticeFeed) { $salmonAction = 'salmongroup'; + $id = $feed->getGroup()->id; } else { return; } - $id = $action->arg('id'); - if (strval(intval($id)) === strval($id)) { - // Canonical form of id in URL? These are used for OStatus syndication. - + if (!empty($id)) { $hub = common_config('ostatus', 'hub'); if (empty($hub)) { // Updates will be handled through our internal PuSH hub. $hub = common_local_url('pushhub'); } - $action->element('link', array('rel' => 'hub', - 'href' => $hub)); + $feed->addLink($hub, array('rel' => 'hub')); // Also, we'll add in the salmon link $salmon = common_local_url($salmonAction, array('id' => $id)); - $action->element('link', array('rel' => 'salmon', - 'href' => $salmon)); + $feed->addLink($salmon, array('rel' => 'salmon')); } } - + /** * Add the feed settings page to the Connect Settings menu * @@ -201,7 +200,7 @@ class OStatusPlugin extends Plugin $output->element('a', array('href' => $url, 'class' => 'entity_remote_subscribe'), _m('OStatus')); - + $output->elementEnd('li'); } } @@ -221,25 +220,25 @@ class OStatusPlugin extends Plugin $w = new Webfinger; $endpoint_uri = ''; - + $result = $w->lookup($webfinger); if (empty($result)) { continue; } - + foreach ($result->links as $link) { if ($link['rel'] == 'salmon') { $endpoint_uri = $link['href']; } } - + if (empty($endpoint_uri)) { continue; } $xml = ''; $xml .= $notice->asAtomEntry(); - + $salmon = new Salmon(); $salmon->post($endpoint_uri, $xml); } -- cgit v1.2.3-54-g00ecf