]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - plugins/OStatus/classes/Ostatus_profile.php
Merge remote-tracking branch 'upstream/master' into social-master
[quix0rs-gnu-social.git] / plugins / OStatus / classes / Ostatus_profile.php
index c63bf84dd155d5d1bc15eb901cc2b407bb8cbcab..ca1708282e9c392cff1a5b452033ffb4ff348de7 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-if (!defined('STATUSNET')) {
-    exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
 
 /**
  * @package OStatusPlugin
- * @maintainer Brion Vibber <brion@status.net>
+ * @author Brion Vibber <brion@status.net>
+ * @maintainer Mikael Nordfeldth <mmn@hethane.se>
  */
 class Ostatus_profile extends Managed_DataObject
 {
@@ -346,7 +345,7 @@ class Ostatus_profile extends Managed_DataObject
         $xml = $entry->getString();
         common_log(LOG_INFO, "Posting to Salmon endpoint $this->salmonuri: $xml");
 
-        Salmon::post($this->salmonuri, $xml, $actor->getUser());
+        Salmon::post($this->salmonuri, $xml, $actor);
     }
 
     /**
@@ -360,7 +359,7 @@ class Ostatus_profile extends Managed_DataObject
     public function notifyActivity($entry, Profile $actor)
     {
         if ($this->salmonuri) {
-            return Salmon::post($this->salmonuri, $this->notifyPrepXml($entry), $actor->getUser());
+            return Salmon::post($this->salmonuri, $this->notifyPrepXml($entry), $actor, $this->localProfile());
         }
         common_debug(__CLASS__.' error: No salmonuri for Ostatus_profile uri: '.$this->uri);
 
@@ -380,7 +379,8 @@ class Ostatus_profile extends Managed_DataObject
         if ($this->salmonuri) {
             $data = array('salmonuri' => $this->salmonuri,
                           'entry' => $this->notifyPrepXml($entry),
-                          'actor' => $actor->id);
+                          'actor' => $actor->getID(),
+                          'target' => $this->localProfile()->getID());
 
             $qm = QueueManager::get();
             return $qm->enqueue($data, 'salmon');
@@ -445,10 +445,7 @@ class Ostatus_profile extends Managed_DataObject
             return;
         }
 
-        for ($i = 0; $i < $entries->length; $i++) {
-            $entry = $entries->item($i);
-            $this->processEntry($entry, $feed, $source);
-        }
+        $this->processEntries($entries, $feed, $source);
     }
 
     public function processRssFeed(DOMElement $rss, $source)
@@ -466,9 +463,18 @@ class Ostatus_profile extends Managed_DataObject
 
         $items = $channel->getElementsByTagName('item');
 
-        for ($i = 0; $i < $items->length; $i++) {
-            $item = $items->item($i);
-            $this->processEntry($item, $channel, $source);
+        $this->processEntries($items, $channel, $source);
+    }
+
+    public function processEntries(DOMNodeList $entries, DOMElement $feed, $source)
+    {
+        for ($i = 0; $i < $entries->length; $i++) {
+            $entry = $entries->item($i);
+            try {
+                $this->processEntry($entry, $feed, $source);
+            } catch (AlreadyFulfilledException $e) {
+                common_debug('We already had this entry: '.$e->getMessage());
+            }
         }
     }
 
@@ -497,26 +503,7 @@ class Ostatus_profile extends Managed_DataObject
         if (Event::handle('StartHandleFeedEntryWithProfile', array($activity, $this->localProfile(), &$notice)) &&
             Event::handle('StartHandleFeedEntry', array($activity))) {
 
-            switch ($activity->verb) {
-            case ActivityVerb::POST:
-                // @todo process all activity objects
-                switch ($activity->objects[0]->type) {
-                case ActivityObject::ARTICLE:
-                case ActivityObject::BLOGENTRY:
-                case ActivityObject::NOTE:
-                case ActivityObject::STATUS:
-                case ActivityObject::COMMENT:
-                case null:
-                    $notice = $this->processPost($activity, $source);
-                    break;
-                default:
-                    // TRANS: Client exception.
-                    throw new ClientException(_m('Cannot handle that kind of post.'));
-                }
-                break;
-            default:
-                common_log(LOG_INFO, "Ignoring activity with unrecognized verb $activity->verb");
-            }
+            common_log(LOG_INFO, "Ignoring activity with unrecognized verb $activity->verb");
 
             Event::handle('EndHandleFeedEntry', array($activity));
             Event::handle('EndHandleFeedEntryWithProfile', array($activity, $this, $notice));
@@ -530,178 +517,21 @@ class Ostatus_profile extends Managed_DataObject
      * @param Activity $activity
      * @param string $method 'push' or 'salmon'
      * @return mixed saved Notice or false
-     * @todo FIXME: Break up this function, it's getting nasty long
      */
     public function processPost(Activity $activity, $method)
     {
-        $notice = null;
-
-        $profile = ActivityUtils::checkAuthorship($activity, $this->localProfile());
-
-        // It's not always an ActivityObject::NOTE, but... let's just say it is.
-
-        $note = $activity->objects[0];
-
-        // The id URI will be used as a unique identifier for the notice,
-        // protecting against duplicate saves. It isn't required to be a URL;
-        // tag: URIs for instance are found in Google Buzz feeds.
-        $sourceUri = $note->id;
-        $dupe = Notice::getKV('uri', $sourceUri);
-        if ($dupe instanceof Notice) {
-            common_log(LOG_INFO, "OStatus: ignoring duplicate post: $sourceUri");
-            return $dupe;
-        }
-
-        // We'll also want to save a web link to the original notice, if provided.
-        $sourceUrl = null;
-        if ($note->link) {
-            $sourceUrl = $note->link;
-        } else if ($activity->link) {
-            $sourceUrl = $activity->link;
-        } else if (preg_match('!^https?://!', $note->id)) {
-            $sourceUrl = $note->id;
-        }
-
-        // Use summary as fallback for content
-
-        if (!empty($note->content)) {
-            $sourceContent = $note->content;
-        } else if (!empty($note->summary)) {
-            $sourceContent = $note->summary;
-        } else if (!empty($note->title)) {
-            $sourceContent = $note->title;
-        } else {
-            // @todo FIXME: Fetch from $sourceUrl?
-            // TRANS: Client exception. %s is a source URI.
-            throw new ClientException(sprintf(_m('No content for notice %s.'),$sourceUri));
-        }
-
-        // Get (safe!) HTML and text versions of the content
-
-        $rendered = common_purify($sourceContent);
-        $content = common_strip_html($rendered);
-
-        $shortened = common_shorten_links($content);
-
-        // If it's too long, try using the summary, and make the
-        // HTML an attachment.
-
-        $attachment = null;
-
-        if (Notice::contentTooLong($shortened)) {
-            $attachment = $this->saveHTMLFile($note->title, $rendered);
-            $summary = common_strip_html($note->summary);
-            if (empty($summary)) {
-                $summary = $content;
-            }
-            $shortSummary = common_shorten_links($summary);
-            if (Notice::contentTooLong($shortSummary)) {
-                $url = common_shorten_url($sourceUrl);
-                $shortSummary = substr($shortSummary,
-                                       0,
-                                       Notice::maxContent() - (mb_strlen($url) + 2));
-                $content = $shortSummary . ' ' . $url;
-
-                // We mark up the attachment link specially for the HTML output
-                // so we can fold-out the full version inline.
-
-                // @todo FIXME i18n: This tooltip will be saved with the site's default language
-                // TRANS: Shown when a notice is longer than supported and/or when attachments are present. At runtime
-                // TRANS: this will usually be replaced with localised text from StatusNet core messages.
-                $showMoreText = _m('Show more');
-                $attachUrl = common_local_url('attachment',
-                                              array('attachment' => $attachment->id));
-                $rendered = common_render_text($shortSummary) .
-                            '<a href="' . htmlspecialchars($attachUrl) .'"'.
-                            ' class="attachment more"' .
-                            ' title="'. htmlspecialchars($showMoreText) . '">' .
-                            '&#8230;' .
-                            '</a>';
-            }
-        }
-
-        $options = array('is_local' => Notice::REMOTE,
-                        'url' => $sourceUrl,
-                        'uri' => $sourceUri,
-                        'rendered' => $rendered,
-                        'replies' => array(),
-                        'groups' => array(),
-                        'peopletags' => array(),
-                        'tags' => array(),
-                        'urls' => array());
-
-        // Check for optional attributes...
+        $actor = ActivityUtils::checkAuthorship($activity, $this->localProfile());
 
-        if (!empty($activity->time)) {
-            $options['created'] = common_sql_date($activity->time);
-        }
-
-        if ($activity->context) {
-            // TODO: context->attention
-            list($options['groups'], $options['replies'])
-                = self::filterAttention($profile, $activity->context->attention);
-
-            // Maintain direct reply associations
-            // @todo FIXME: What about conversation ID?
-            if (!empty($activity->context->replyToID)) {
-                $orig = Notice::getKV('uri', $activity->context->replyToID);
-                if ($orig instanceof Notice) {
-                    $options['reply_to'] = $orig->id;
-                }
-            }
-            if (!empty($activity->context->conversation)) {
-                // we store the URI here, Notice class can look it up later
-                $options['conversation'] = $activity->context->conversation;
-            }
-
-            $location = $activity->context->location;
-            if ($location) {
-                $options['lat'] = $location->lat;
-                $options['lon'] = $location->lon;
-                if ($location->location_id) {
-                    $options['location_ns'] = $location->location_ns;
-                    $options['location_id'] = $location->location_id;
-                }
-            }
-        }
-
-        if ($this->isPeopletag()) {
-            $options['peopletags'][] = $this->localPeopletag();
-        }
-
-        // Atom categories <-> hashtags
-        foreach ($activity->categories as $cat) {
-            if ($cat->term) {
-                $term = common_canonical_tag($cat->term);
-                if ($term) {
-                    $options['tags'][] = $term;
-                }
-            }
-        }
-
-        // Atom enclosures -> attachment URLs
-        foreach ($activity->enclosures as $href) {
-            // @todo FIXME: Save these locally or....?
-            $options['urls'][] = $href;
-        }
+        $options = array('is_local' => Notice::REMOTE);
 
         try {
-            $saved = Notice::saveNew($profile->id,
-                                     $content,
-                                     'ostatus',
-                                     $options);
-            if ($saved instanceof Notice) {
-                Ostatus_source::saveNew($saved, $this, $method);
-                if (!empty($attachment)) {
-                    File_to_post::processNew($attachment->id, $saved->id);
-                }
-            }
+            $stored = Notice::saveActivity($activity, $actor, $options);
+            Ostatus_source::saveNew($stored, $this, $method);
         } catch (Exception $e) {
             common_log(LOG_ERR, "OStatus save of remote message $sourceUri failed: " . $e->getMessage());
             throw $e;
         }
-        common_log(LOG_INFO, "OStatus saved remote message $sourceUri as notice id $saved->id");
-        return $saved;
+        return $stored;
     }
 
     /**
@@ -812,14 +642,21 @@ class Ostatus_profile extends Managed_DataObject
             }
         }
 
-        // Try to get some hCard data
+        if (in_array(
+            preg_replace('/\s*;.*$/', '', $response->getHeader('Content-Type')),
+            array('application/rss+xml', 'application/atom+xml', 'application/xml', 'text/xml'))
+        ) {
+            $hints['feedurl'] = $response->getUrl();
+        } else {
+            // Try to get some hCard data
 
-        $body = $response->getBody();
+            $body = $response->getBody();
 
-        $hcardHints = DiscoveryHints::hcardHints($body, $finalUrl);
+            $hcardHints = DiscoveryHints::hcardHints($body, $finalUrl);
 
-        if (!empty($hcardHints)) {
-            $hints = array_merge($hints, $hcardHints);
+            if (!empty($hcardHints)) {
+                $hints = array_merge($hints, $hcardHints);
+            }
         }
 
         // Check if they've got an LRDD header
@@ -1005,11 +842,13 @@ class Ostatus_profile extends Managed_DataObject
             }
         }
 
+        $obj = ActivityUtils::getFeedAuthor($feedEl);
+
         // @todo FIXME: We should check whether this feed has elements
         // with different <author> or <dc:creator> elements, and... I dunno.
         // Do something about that.
 
-        $obj = ActivityObject::fromRssChannel($feedEl);
+        if(empty($obj)) { $obj = ActivityObject::fromRssChannel($feedEl); }
 
         return self::ensureActivityObjectProfile($obj, $hints);
     }
@@ -1747,11 +1586,8 @@ class Ostatus_profile extends Managed_DataObject
             throw new Exception(_m('Not a valid webfinger address.'));
         }
 
-        $hints = array('webfinger' => $addr);
-
-        $dhints = DiscoveryHints::fromXRD($xrd);
-
-        $hints = array_merge($hints, $dhints);
+        $hints = array_merge(array('webfinger' => $addr),
+                             DiscoveryHints::fromXRD($xrd));
 
         // If there's an Hcard, let's grab its info
         if (array_key_exists('hcard', $hints)) {
@@ -1982,6 +1818,38 @@ class Ostatus_profile extends Managed_DataObject
 
         return $oprofile->localProfile();
     }
+
+    public function updateUriKeys($profile_uri, array $hints=array())
+    {
+        $orig = clone($this);
+
+        common_debug('URIFIX These identities both say they are each other: "'.$orig->uri.'" and "'.$profile_uri.'"');
+        $this->uri = $profile_uri;
+
+        if (array_key_exists('feedurl', $hints)) {
+            if (!empty($this->feeduri)) {
+                common_debug('URIFIX Changing FeedSub ['.$feedsub->id.'] feeduri "'.$feedsub->uri.'" to "'.$hints['feedurl']);
+                $feedsub = FeedSub::getKV('uri', $this->feeduri);
+                $feedorig = clone($feedsub);
+                $feedsub->uri = $hints['feedurl'];
+                $feedsub->updateWithKeys($feedorig);
+            } else {
+                common_debug('URIFIX Old Ostatus_profile did not have feedurl set, ensuring feed: '.$hints['feedurl']);
+                FeedSub::ensureFeed($hints['feedurl']);
+            }
+            $this->feeduri = $hints['feedurl'];
+        }
+        if (array_key_exists('salmon', $hints)) {
+            common_debug('URIFIX Changing Ostatus_profile salmonuri from "'.$this->salmonuri.'" to "'.$hints['salmon'].'"');
+            $this->salmonuri = $hints['salmon'];
+        }
+
+        common_debug('URIFIX Updating Ostatus_profile URI for '.$orig->uri.' to '.$this->uri);
+        $this->updateWithKeys($orig, 'uri');    // 'uri' is the primary key column
+
+        common_debug('URIFIX Subscribing/renewing feedsub for Ostatus_profile '.$this->uri);
+        $this->subscribe();
+    }
 }
 
 /**