X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Factivity.php;h=e974ca991d4407f4a37df2cb75ee751ce3c76c7d;hb=93bea7ff28434dee5202659a99a024476d43592f;hp=b1744e68f585c681d76cab8097ee7c0b58d558b9;hpb=e458e9fe6352df6063079979b20a6924f97198f4;p=quix0rs-gnu-social.git diff --git a/lib/activity.php b/lib/activity.php index b1744e68f5..e974ca991d 100644 --- a/lib/activity.php +++ b/lib/activity.php @@ -48,11 +48,11 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ */ - class Activity { const SPEC = 'http://activitystrea.ms/spec/1.0/'; const SCHEMA = 'http://activitystrea.ms/schema/1.0/'; + const MEDIA = 'http://purl.org/syndication/atommedia'; const VERB = 'verb'; const OBJECT = 'object'; @@ -82,10 +82,11 @@ class Activity const CREATOR = 'creator'; const CONTENTNS = 'http://purl.org/rss/1.0/modules/content/'; + const ENCODED = 'encoded'; public $actor; // an ActivityObject public $verb; // a string (the URL) - public $object; // an ActivityObject + public $objects = array(); // an array of ActivityObjects public $target; // an ActivityObject public $context; // an ActivityObject public $time; // Time of the activity @@ -106,7 +107,6 @@ class Activity * @param DOMElement $entry Atom entry to poke at * @param DOMElement $feed Atom feed, for context */ - function __construct($entry = null, $feed = null) { if (is_null($entry)) { @@ -116,7 +116,8 @@ class Activity // Insist on a feed's root DOMElement; don't allow a DOMDocument if ($feed instanceof DOMDocument) { throw new ClientException( - _("Expecting a root feed element but got a whole XML document.") + // TRANS: Client exception thrown when a feed instance is a DOMDocument. + _('Expecting a root feed element but got a whole XML document.') ); } @@ -130,6 +131,7 @@ class Activity $entry->localName == 'item') { $this->_fromRssItem($entry, $feed); } else { + // Low level exception. No need for i18n. throw new Exception("Unknown DOM element: {$entry->namespaceURI} {$entry->localName}"); } } @@ -161,12 +163,15 @@ class Activity // XXX: do other implied stuff here } - $objectEl = $this->_child($entry, self::OBJECT); + $objectEls = $entry->getElementsByTagNameNS(self::SPEC, self::OBJECT); - if (!empty($objectEl)) { - $this->object = new ActivityObject($objectEl); + if ($objectEls->length > 0) { + for ($i = 0; $i < $objectEls->length; $i++) { + $objectEl = $objectEls->item($i); + $this->objects[] = new ActivityObject($objectEl); + } } else { - $this->object = new ActivityObject($entry); + $this->objects[] = new ActivityObject($entry); } $actorEl = $this->_child($entry, self::ACTOR); @@ -175,6 +180,17 @@ class Activity $this->actor = new ActivityObject($actorEl); + // Cliqset has bad actor IDs (just nickname of user). We + // work around it by getting the author data and using its + // id instead + + if (!preg_match('/^\w+:/', $this->actor->id)) { + $authorEl = ActivityUtils::child($entry, 'author'); + if (!empty($authorEl)) { + $authorObj = new ActivityObject($authorEl); + $this->actor->id = $authorObj->id; + } + } } else if (!empty($feed) && $subjectEl = $this->_child($feed, self::SUBJECT)) { @@ -238,29 +254,36 @@ 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 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 { - $dcCreatorEl = $this->_child($item, self::CREATOR, self::DC); - if (!empty($dcCreatorEl)) { - $this->actor = ActivityObject::fromDcCreator($dcCreatorEl); - } else if (!empty($channel)) { - $this->actor = ActivityObject::fromRssChannel($channel); - } + // No actor! } $this->title = ActivityUtils::childContent($item, ActivityObject::TITLE, self::RSS); - $contentEl = ActivityUtils::child($item, ActivityUtils::CONTENT, self::CONTENTNS); + $contentEl = ActivityUtils::child($item, self::ENCODED, self::CONTENTNS); if (!empty($contentEl)) { - $this->content = htmlspecialchars_decode($contentEl->textContent, ENT_QUOTES); + // XML node's text content is HTML; no further processing needed. + $this->content = $contentEl->textContent; } else { $descriptionEl = ActivityUtils::child($item, self::DESCRIPTION, self::RSS); if (!empty($descriptionEl)) { - $this->content = htmlspecialchars_decode($descriptionEl->textContent, ENT_QUOTES); + // Per spec, must be plaintext. + // In practice, often there's HTML... but these days good + // feeds are using which is explicitly + // real HTML. + // We'll treat this following spec, and do HTML escaping + // to convert from plaintext to HTML. + $this->content = htmlspecialchars($descriptionEl->textContent); } } @@ -280,8 +303,8 @@ class Activity } } - $this->object = new ActivityObject($item); - $this->context = new ActivityContext($item); + $this->objects[] = new ActivityObject($item); + $this->context = new ActivityContext($item); } /** @@ -289,13 +312,12 @@ class Activity * * @return DOMElement Atom entry */ - function toAtomEntry() { return null; } - function asString($namespace=false) + function asString($namespace=false, $author=true) { $xs = new XMLStringer(true); @@ -314,7 +336,7 @@ class Activity $xs->element('id', null, $this->id); $xs->element('title', null, $this->title); - $xs->element('published', null, common_date_iso8601($this->time)); + $xs->element('published', null, self::iso8601Date($this->time)); $xs->element('content', array('type' => 'html'), $this->content); if (!empty($this->summary)) { @@ -329,18 +351,22 @@ class Activity // XXX: add context - $xs->elementStart('author'); - $xs->element('uri', array(), $this->actor->id); - if ($this->actor->title) { - $xs->element('name', array(), $this->actor->title); + if ($author) { + $xs->elementStart('author'); + $xs->element('uri', array(), $this->actor->id); + if ($this->actor->title) { + $xs->element('name', array(), $this->actor->title); + } + $xs->elementEnd('author'); + $xs->raw($this->actor->asString('activity:actor')); } - $xs->elementEnd('author'); - $xs->raw($this->actor->asString('activity:actor')); $xs->element('activity:verb', null, $this->verb); - if ($this->object) { - $xs->raw($this->object->asString()); + if (!empty($this->objects)) { + foreach($this->objects as $object) { + $xs->raw($object->asString()); + } } if ($this->target) { @@ -360,50 +386,12 @@ class Activity { return ActivityUtils::child($element, $tag, $namespace); } -} - -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) + static function iso8601Date($tm) { - $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(); + $dateStr = date('d F Y H:i:s', $tm); + $d = new DateTime($dateStr, new DateTimeZone('UTC')); + $d->setTimezone(new DateTimeZone(common_timezone())); + return $d->format('c'); } }