Merge branch 'testing' into 0.9.x
This commit is contained in:
commit
be7efe7504
|
@ -238,17 +238,17 @@ class Activity
|
|||
$this->time = strtotime($pubDateEl->textContent);
|
||||
}
|
||||
|
||||
$authorEl = $this->_child($item, self::AUTHOR, self::RSS);
|
||||
|
||||
if (!empty($authorEl)) {
|
||||
if ($authorEl = $this->_child($item, self::AUTHOR, self::RSS)) {
|
||||
$this->actor = ActivityObject::fromRssAuthor($authorEl);
|
||||
} else {
|
||||
$dcCreatorEl = $this->_child($item, self::CREATOR, self::DC);
|
||||
if (!empty($dcCreatorEl)) {
|
||||
} else if ($dcCreatorEl = $this->_child($item, self::CREATOR, self::DC)) {
|
||||
$this->actor = ActivityObject::fromDcCreator($dcCreatorEl);
|
||||
} else if ($posterousEl = $this->_child($item, ActivityObject::AUTHOR, ActivityObject::POSTEROUS)) {
|
||||
// Special case for Posterous.com
|
||||
$this->actor = ActivityObject::fromPosterousAuthor($posterousEl);
|
||||
} else if (!empty($channel)) {
|
||||
$this->actor = ActivityObject::fromRssChannel($channel);
|
||||
}
|
||||
} else {
|
||||
// No actor!
|
||||
}
|
||||
|
||||
$this->title = ActivityUtils::childContent($item, ActivityObject::TITLE, self::RSS);
|
||||
|
@ -362,48 +362,3 @@ class Activity
|
|||
}
|
||||
}
|
||||
|
||||
class AtomCategory
|
||||
{
|
||||
public $term;
|
||||
public $scheme;
|
||||
public $label;
|
||||
|
||||
function __construct($element=null)
|
||||
{
|
||||
if ($element && $element->attributes) {
|
||||
$this->term = $this->extract($element, 'term');
|
||||
$this->scheme = $this->extract($element, 'scheme');
|
||||
$this->label = $this->extract($element, 'label');
|
||||
}
|
||||
}
|
||||
|
||||
protected function extract($element, $attrib)
|
||||
{
|
||||
$node = $element->attributes->getNamedItemNS(Activity::ATOM, $attrib);
|
||||
if ($node) {
|
||||
return trim($node->textContent);
|
||||
}
|
||||
$node = $element->attributes->getNamedItem($attrib);
|
||||
if ($node) {
|
||||
return trim($node->textContent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function asString()
|
||||
{
|
||||
$attribs = array();
|
||||
if ($this->term !== null) {
|
||||
$attribs['term'] = $this->term;
|
||||
}
|
||||
if ($this->scheme !== null) {
|
||||
$attribs['scheme'] = $this->scheme;
|
||||
}
|
||||
if ($this->label !== null) {
|
||||
$attribs['label'] = $this->label;
|
||||
}
|
||||
$xs = new XMLStringer();
|
||||
$xs->element('category', $attribs);
|
||||
return $xs->asString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,13 @@ class ActivityObject
|
|||
const URI = 'uri';
|
||||
const EMAIL = 'email';
|
||||
|
||||
const POSTEROUS = 'http://posterous.com/help/rss/1.0';
|
||||
const AUTHOR = 'author';
|
||||
const USERIMAGE = 'userImage';
|
||||
const PROFILEURL = 'profileUrl';
|
||||
const NICKNAME = 'nickName';
|
||||
const DISPLAYNAME = 'displayName';
|
||||
|
||||
public $element;
|
||||
public $type;
|
||||
public $id;
|
||||
|
@ -149,7 +156,11 @@ class ActivityObject
|
|||
{
|
||||
$this->type = self::PERSON; // XXX: is this fair?
|
||||
$this->title = $this->_childContent($element, self::NAME);
|
||||
$this->id = $this->_childContent($element, self::URI);
|
||||
|
||||
$id = $this->_childContent($element, self::URI);
|
||||
if (ActivityUtils::validateUri($id)) {
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
if (empty($this->id)) {
|
||||
$email = $this->_childContent($element, self::EMAIL);
|
||||
|
@ -162,6 +173,15 @@ class ActivityObject
|
|||
|
||||
private function _fromAtomEntry($element)
|
||||
{
|
||||
if ($element->localName == 'actor') {
|
||||
// Old-fashioned <activity:actor>...
|
||||
// First pull anything from <author>, then we'll add on top.
|
||||
$author = ActivityUtils::child($element->parentNode, 'author');
|
||||
if ($author) {
|
||||
$this->_fromAuthor($author);
|
||||
}
|
||||
}
|
||||
|
||||
$this->type = $this->_childContent($element, Activity::OBJECTTYPE,
|
||||
Activity::SPEC);
|
||||
|
||||
|
@ -169,7 +189,11 @@ class ActivityObject
|
|||
$this->type = ActivityObject::NOTE;
|
||||
}
|
||||
|
||||
$this->id = $this->_childContent($element, self::ID);
|
||||
$id = $this->_childContent($element, self::ID);
|
||||
if (ActivityUtils::validateUri($id)) {
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
$this->summary = ActivityUtils::childHtmlContent($element, self::SUMMARY);
|
||||
$this->content = ActivityUtils::getContent($element);
|
||||
|
||||
|
@ -290,12 +314,42 @@ class ActivityObject
|
|||
$imageEl = ActivityUtils::child($el, Activity::IMAGE, Activity::RSS);
|
||||
|
||||
if (!empty($imageEl)) {
|
||||
$obj->avatarLinks[] = ActivityUtils::childContent($imageEl, Activity::URL, Activity::RSS);
|
||||
$url = ActivityUtils::childContent($imageEl, Activity::URL, Activity::RSS);
|
||||
$al = new AvatarLink();
|
||||
$al->url = $url;
|
||||
$obj->avatarLinks[] = $al;
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public static function fromPosterousAuthor($el)
|
||||
{
|
||||
$obj = new ActivityObject();
|
||||
|
||||
$obj->type = ActivityObject::PERSON; // @fixme any others...?
|
||||
|
||||
$userImage = ActivityUtils::childContent($el, self::USERIMAGE, self::POSTEROUS);
|
||||
|
||||
if (!empty($userImage)) {
|
||||
$al = new AvatarLink();
|
||||
$al->url = $userImage;
|
||||
$obj->avatarLinks[] = $al;
|
||||
}
|
||||
|
||||
$obj->link = ActivityUtils::childContent($el, self::PROFILEURL, self::POSTEROUS);
|
||||
$obj->id = $obj->link;
|
||||
|
||||
$obj->poco = new PoCo();
|
||||
|
||||
$obj->poco->preferredUsername = ActivityUtils::childContent($el, self::NICKNAME, self::POSTEROUS);
|
||||
$obj->poco->displayName = ActivityUtils::childContent($el, self::DISPLAYNAME, self::POSTEROUS);
|
||||
|
||||
$obj->title = $obj->poco->displayName;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
private function _childContent($element, $tag, $namespace=ActivityUtils::ATOM)
|
||||
{
|
||||
return ActivityUtils::childContent($element, $tag, $namespace);
|
||||
|
|
|
@ -240,4 +240,26 @@ class ActivityUtils
|
|||
throw new ClientException(_("Can't handle embedded Base64 content yet."));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a valid URI for remote profile/notice identification?
|
||||
* Does not have to be a resolvable URL.
|
||||
* @param string $uri
|
||||
* @return boolean
|
||||
*/
|
||||
static function validateUri($uri)
|
||||
{
|
||||
if (Validate::uri($uri)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Possibly an upstream bug; tag: URIs aren't validated properly
|
||||
// unless you explicitly ask for them. All other schemes are accepted
|
||||
// for basic URI validation without asking.
|
||||
if (Validate::uri($uri, array('allowed_scheme' => array('tag')))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
77
lib/atomcategory.php
Normal file
77
lib/atomcategory.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Feed
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class AtomCategory
|
||||
{
|
||||
public $term;
|
||||
public $scheme;
|
||||
public $label;
|
||||
|
||||
function __construct($element=null)
|
||||
{
|
||||
if ($element && $element->attributes) {
|
||||
$this->term = $this->extract($element, 'term');
|
||||
$this->scheme = $this->extract($element, 'scheme');
|
||||
$this->label = $this->extract($element, 'label');
|
||||
}
|
||||
}
|
||||
|
||||
protected function extract($element, $attrib)
|
||||
{
|
||||
$node = $element->attributes->getNamedItemNS(Activity::ATOM, $attrib);
|
||||
if ($node) {
|
||||
return trim($node->textContent);
|
||||
}
|
||||
$node = $element->attributes->getNamedItem($attrib);
|
||||
if ($node) {
|
||||
return trim($node->textContent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function asString()
|
||||
{
|
||||
$attribs = array();
|
||||
if ($this->term !== null) {
|
||||
$attribs['term'] = $this->term;
|
||||
}
|
||||
if ($this->scheme !== null) {
|
||||
$attribs['scheme'] = $this->scheme;
|
||||
}
|
||||
if ($this->label !== null) {
|
||||
$attribs['label'] = $this->label;
|
||||
}
|
||||
$xs = new XMLStringer();
|
||||
$xs->element('category', $attribs);
|
||||
return $xs->asString();
|
||||
}
|
||||
}
|
|
@ -947,23 +947,4 @@ class OStatusPlugin extends Plugin
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to check if the given URL is a canonical user profile
|
||||
* page, and if so return the ID number.
|
||||
*
|
||||
* @param string $url
|
||||
* @return mixed int or false
|
||||
*/
|
||||
public static function localProfileFromUrl($url)
|
||||
{
|
||||
$template = common_local_url('userbyid', array('id' => '31337'));
|
||||
$template = preg_quote($template, '/');
|
||||
$template = str_replace('31337', '(\d+)', $template);
|
||||
if (preg_match("/$template/", $url, $matches)) {
|
||||
return intval($matches[1]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -708,9 +708,13 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
}
|
||||
|
||||
/**
|
||||
* Look up and if necessary create an Ostatus_profile for the remote entity
|
||||
* with the given profile page URL. This should never return null -- you
|
||||
* will either get an object or an exception will be thrown.
|
||||
*
|
||||
* @param string $profile_url
|
||||
* @return Ostatus_profile
|
||||
* @throws FeedSubException
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
public static function ensureProfileURL($profile_url, $hints=array())
|
||||
|
@ -731,7 +735,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
$response = $client->get($profile_url);
|
||||
|
||||
if (!$response->isOk()) {
|
||||
return null;
|
||||
throw new Exception("Could not reach profile page: " . $profile_url);
|
||||
}
|
||||
|
||||
// Check if we have a non-canonical URL
|
||||
|
@ -785,11 +789,20 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
|
||||
if (!empty($feedurl)) {
|
||||
$hints['feedurl'] = $feedurl;
|
||||
|
||||
return self::ensureFeedURL($feedurl, $hints);
|
||||
}
|
||||
|
||||
throw new Exception("Could not find a feed URL for profile page " . $finalUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the Ostatus_profile, if present, for a remote entity with the
|
||||
* given profile page URL. Will return null for both unknown and invalid
|
||||
* remote profiles.
|
||||
*
|
||||
* @return mixed Ostatus_profile or null
|
||||
* @throws Exception for local profiles
|
||||
*/
|
||||
static function getFromProfileURL($profile_url)
|
||||
{
|
||||
$profile = Profile::staticGet('profileurl', $profile_url);
|
||||
|
@ -821,6 +834,14 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up and if necessary create an Ostatus_profile for remote entity
|
||||
* with the given update feed. This should never return null -- you will
|
||||
* either get an object or an exception will be thrown.
|
||||
*
|
||||
* @return Ostatus_profile
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function ensureFeedURL($feed_url, $hints=array())
|
||||
{
|
||||
$discover = new FeedDiscovery();
|
||||
|
@ -849,6 +870,18 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up and, if necessary, create an Ostatus_profile for the remote
|
||||
* profile with the given Atom feed - actually loaded from the feed.
|
||||
* This should never return null -- you will either get an object or
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @param DOMElement $feedEl root element of a loaded Atom feed
|
||||
* @param array $hints additional discovery information passed from higher levels
|
||||
* @fixme should this be marked public?
|
||||
* @return Ostatus_profile
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function ensureAtomFeed($feedEl, $hints)
|
||||
{
|
||||
// Try to get a profile from the feed activity:subject
|
||||
|
@ -899,8 +932,40 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
throw new FeedSubException("Can't find enough profile information to make a feed.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up and, if necessary, create an Ostatus_profile for the remote
|
||||
* profile with the given RSS feed - actually loaded from the feed.
|
||||
* This should never return null -- you will either get an object or
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @param DOMElement $feedEl root element of a loaded RSS feed
|
||||
* @param array $hints additional discovery information passed from higher levels
|
||||
* @fixme should this be marked public?
|
||||
* @return Ostatus_profile
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function ensureRssChannel($feedEl, $hints)
|
||||
{
|
||||
// Special-case for Posterous. They have some nice metadata in their
|
||||
// posterous:author elements. We should use them instead of the channel.
|
||||
|
||||
$items = $feedEl->getElementsByTagName('item');
|
||||
|
||||
if ($items->length > 0) {
|
||||
$item = $items->item(0);
|
||||
$authorEl = ActivityUtils::child($item, ActivityObject::AUTHOR, ActivityObject::POSTEROUS);
|
||||
if (!empty($authorEl)) {
|
||||
$obj = ActivityObject::fromPosterousAuthor($authorEl);
|
||||
// Posterous has multiple authors per feed, and multiple feeds
|
||||
// per author. We check if this is the "main" feed for this author.
|
||||
if (array_key_exists('profileurl', $hints) &&
|
||||
!empty($obj->poco) &&
|
||||
common_url_to_nickname($hints['profileurl']) == $obj->poco->preferredUsername) {
|
||||
return self::ensureActivityObjectProfile($obj, $hints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @fixme we should check whether this feed has elements
|
||||
// with different <author> or <dc:creator> elements, and... I dunno.
|
||||
// Do something about that.
|
||||
|
@ -1042,11 +1107,14 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
/**
|
||||
* Fetch, or build if necessary, an Ostatus_profile for the actor
|
||||
* in a given Activity Streams activity.
|
||||
* This should never return null -- you will either get an object or
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @param Activity $activity
|
||||
* @param string $feeduri if we already know the canonical feed URI!
|
||||
* @param string $salmonuri if we already know the salmon return channel URI
|
||||
* @return Ostatus_profile
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
public static function ensureActorProfile($activity, $hints=array())
|
||||
|
@ -1054,6 +1122,18 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
return self::ensureActivityObjectProfile($activity->actor, $hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch, or build if necessary, an Ostatus_profile for the profile
|
||||
* in a given Activity Streams object (can be subject, actor, or object).
|
||||
* This should never return null -- you will either get an object or
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @param ActivityObject $object
|
||||
* @param array $hints additional discovery information passed from higher levels
|
||||
* @return Ostatus_profile
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
public static function ensureActivityObjectProfile($object, $hints=array())
|
||||
{
|
||||
$profile = self::getActivityObjectProfile($object);
|
||||
|
@ -1068,35 +1148,45 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
/**
|
||||
* @param Activity $activity
|
||||
* @return mixed matching Ostatus_profile or false if none known
|
||||
* @throws ServerException if feed info invalid
|
||||
*/
|
||||
public static function getActorProfile($activity)
|
||||
{
|
||||
return self::getActivityObjectProfile($activity->actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ActivityObject $activity
|
||||
* @return mixed matching Ostatus_profile or false if none known
|
||||
* @throws ServerException if feed info invalid
|
||||
*/
|
||||
protected static function getActivityObjectProfile($object)
|
||||
{
|
||||
$uri = self::getActivityObjectProfileURI($object);
|
||||
return Ostatus_profile::staticGet('uri', $uri);
|
||||
}
|
||||
|
||||
protected static function getActorProfileURI($activity)
|
||||
{
|
||||
return self::getActivityObjectProfileURI($activity->actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Activity $activity
|
||||
* Get the identifier URI for the remote entity described
|
||||
* by this ActivityObject. This URI is *not* guaranteed to be
|
||||
* a resolvable HTTP/HTTPS URL.
|
||||
*
|
||||
* @param ActivityObject $object
|
||||
* @return string
|
||||
* @throws ServerException
|
||||
* @throws ServerException if feed info invalid
|
||||
*/
|
||||
protected static function getActivityObjectProfileURI($object)
|
||||
{
|
||||
$opts = array('allowed_schemes' => array('http', 'https'));
|
||||
if ($object->id && Validate::uri($object->id, $opts)) {
|
||||
if ($object->id) {
|
||||
if (ActivityUtils::validateUri($object->id)) {
|
||||
return $object->id;
|
||||
}
|
||||
if ($object->link && Validate::uri($object->link, $opts)) {
|
||||
}
|
||||
|
||||
// If the id is missing or invalid (we've seen feeds mistakenly listing
|
||||
// things like local usernames in that field) then we'll use the profile
|
||||
// page link, if valid.
|
||||
if ($object->link && common_valid_http_url($object->link)) {
|
||||
return $object->link;
|
||||
}
|
||||
throw new ServerException("No author ID URI found");
|
||||
|
@ -1109,6 +1199,8 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
/**
|
||||
* Create local ostatus_profile and profile/user_group entries for
|
||||
* the provided remote user or group.
|
||||
* This should never return null -- you will either get an object or
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @param ActivityObject $object
|
||||
* @param array $hints
|
||||
|
@ -1125,7 +1217,8 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
throw new Exception("No profile URI");
|
||||
}
|
||||
|
||||
if (OStatusPlugin::localProfileFromUrl($homeuri)) {
|
||||
$user = User::staticGet('uri', $homeuri);
|
||||
if ($user) {
|
||||
throw new Exception("Local user can't be referenced as remote.");
|
||||
}
|
||||
|
||||
|
@ -1425,6 +1518,11 @@ class Ostatus_profile extends Memcached_DataObject
|
|||
}
|
||||
|
||||
/**
|
||||
* Look up, and if necessary create, an Ostatus_profile for the remote
|
||||
* entity with the given webfinger address.
|
||||
* This should never return null -- you will either get an object or
|
||||
* an exception will be thrown.
|
||||
*
|
||||
* @param string $addr webfinger address
|
||||
* @return Ostatus_profile
|
||||
* @throws Exception on error conditions
|
||||
|
|
|
@ -170,6 +170,51 @@ class ActivityParseTests extends PHPUnit_Framework_TestCase
|
|||
$this->assertFalse(empty($actor));
|
||||
$this->assertEquals($actor->title, "Joseph Scott");
|
||||
}
|
||||
|
||||
public function testExample7()
|
||||
{
|
||||
global $_example7;
|
||||
|
||||
$dom = DOMDocument::loadXML($_example7);
|
||||
|
||||
$rss = $dom->documentElement;
|
||||
|
||||
$channels = $dom->getElementsByTagName('channel');
|
||||
|
||||
$channel = $channels->item(0);
|
||||
|
||||
$items = $channel->getElementsByTagName('item');
|
||||
|
||||
$item = $items->item(0);
|
||||
|
||||
$act = new Activity($item, $channel);
|
||||
|
||||
$this->assertEquals(ActivityVerb::POST, $act->verb);
|
||||
$this->assertEquals('http://evanpro.posterous.com/checking-out-captain-bones', $act->link);
|
||||
$this->assertEquals('http://evanpro.posterous.com/checking-out-captain-bones', $act->id);
|
||||
$this->assertEquals('Checking out captain bones', $act->title);
|
||||
$this->assertEquals(1269095551, $act->time);
|
||||
|
||||
$actor = $act->actor;
|
||||
|
||||
$this->assertEquals(ActivityObject::PERSON, $actor->type);
|
||||
$this->assertEquals('http://posterous.com/people/3sDslhaepotz', $actor->id);
|
||||
$this->assertEquals('Evan Prodromou', $actor->title);
|
||||
$this->assertNull($actor->summary);
|
||||
$this->assertNull($actor->content);
|
||||
$this->assertEquals('http://posterous.com/people/3sDslhaepotz', $actor->link);
|
||||
$this->assertNull($actor->source);
|
||||
$this->assertTrue(is_array($actor->avatarLinks));
|
||||
$this->assertEquals(1, count($actor->avatarLinks));
|
||||
$this->assertEquals('http://files.posterous.com/user_profile_pics/480326/2009-08-05-142447.jpg',
|
||||
$actor->avatarLinks[0]);
|
||||
$this->assertNotNull($actor->poco);
|
||||
$this->assertEquals('evanpro', $actor->poco->preferredUsername);
|
||||
$this->assertEquals('Evan Prodromou', $actor->poco->displayName);
|
||||
$this->assertNull($actor->poco->note);
|
||||
$this->assertNull($actor->poco->address);
|
||||
$this->assertEquals(0, count($actor->poco->urls));
|
||||
}
|
||||
}
|
||||
|
||||
$_example1 = <<<EXAMPLE1
|
||||
|
@ -423,3 +468,43 @@ $_example6 = <<<EXAMPLE6
|
|||
</rss>
|
||||
EXAMPLE6;
|
||||
|
||||
$_example7 = <<<EXAMPLE7
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:posterous="http://posterous.com/help/rss/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
|
||||
<channel>
|
||||
<title>evanpro's posterous</title>
|
||||
<link>http://evanpro.posterous.com</link>
|
||||
<description>Most recent posts at evanpro's posterous</description>
|
||||
<generator>posterous.com</generator>
|
||||
<link type="application/json" xmlns="http://www.w3.org/2005/Atom" rel="http://api.friendfeed.com/2008/03#sup" href="http://posterous.com/api/sup_update#56bcc5eb7"/>
|
||||
<atom:link rel="self" href="http://evanpro.posterous.com/rss.xml"/>
|
||||
<atom:link rel="hub" href="http://posterous.superfeedr.com"/>
|
||||
<item>
|
||||
<pubDate>Sat, 20 Mar 2010 07:32:31 -0700</pubDate>
|
||||
<title>Checking out captain bones</title>
|
||||
<link>http://evanpro.posterous.com/checking-out-captain-bones</link>
|
||||
<guid>http://evanpro.posterous.com/checking-out-captain-bones</guid>
|
||||
<description>
|
||||
<![CDATA[<p>
|
||||
<p>Bones!</p>
|
||||
|
||||
</p>
|
||||
|
||||
<p><a href="http://evanpro.posterous.com/checking-out-captain-bones">Permalink</a>
|
||||
|
||||
| <a href="http://evanpro.posterous.com/checking-out-captain-bones#comment">Leave a comment »</a>
|
||||
|
||||
</p>]]>
|
||||
</description>
|
||||
<posterous:author>
|
||||
<posterous:userImage>http://files.posterous.com/user_profile_pics/480326/2009-08-05-142447.jpg</posterous:userImage>
|
||||
<posterous:profileUrl>http://posterous.com/people/3sDslhaepotz</posterous:profileUrl>
|
||||
<posterous:firstName>Evan</posterous:firstName>
|
||||
<posterous:lastnNme>Prodromou</posterous:lastnNme>
|
||||
<posterous:nickName>evanpro</posterous:nickName>
|
||||
<posterous:displayName>Evan Prodromou</posterous:displayName>
|
||||
</posterous:author>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
EXAMPLE7;
|
||||
|
|
Loading…
Reference in New Issue
Block a user