]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - classes/Notice.php
Notice::getReplyTo more specific now (getInlineReplyTo)
[quix0rs-gnu-social.git] / classes / Notice.php
index a72e04746c5bdc1ab77c9e9d1fcc780f58b1c79a..461e8f9aabdfc941967ba4a9a731e6b4beef7238 100644 (file)
@@ -141,14 +141,14 @@ class Notice extends Managed_DataObject
     const GROUP_SCOPE     = 4;
     const FOLLOWER_SCOPE  = 8;
 
-    protected $_profile = -1;
+    protected $_profile = array();
     
     public function getProfile()
     {
-        if ($this->_profile === -1) {
+        if (!isset($this->_profile[$this->profile_id])) {
             $this->_setProfile(Profile::getKV('id', $this->profile_id));
         }
-        return $this->_profile;
+        return $this->_profile[$this->profile_id];
     }
     
     public function _setProfile(Profile $profile=null)
@@ -156,7 +156,7 @@ class Notice extends Managed_DataObject
         if (!$profile instanceof Profile) {
             throw new NoProfileException($this->profile_id);
         }
-        $this->_profile = $profile;
+        $this->_profile[$this->profile_id] = $profile;
     }
 
     function delete($useWhere=false)
@@ -210,6 +210,27 @@ class Notice extends Managed_DataObject
         return $this->uri;
     }
 
+    /*
+     * @param $root boolean If true, link to just the conversation root.
+     *
+     * @return URL to conversation
+     */
+    public function getConversationUrl($anchor=true)
+    {
+        return Conversation::getUrlFromNotice($this, $anchor);
+    }
+
+    /*
+     * Get the local representation URL of this notice.
+     */
+    public function getLocalUrl()
+    {
+        return common_local_url('shownotice', array('notice' => $this->id), null, null, false);
+    }
+
+    /*
+     * Get the original representation URL of this notice.
+     */
     public function getUrl()
     {
         // The risk is we start having empty urls and non-http uris...
@@ -488,10 +509,19 @@ class Notice extends Managed_DataObject
 
             $notice->repeat_of = $repeat_of;
         } else {
-            $reply = self::getReplyTo($reply_to, $profile_id, $source, $final);
+            $reply = null;
 
-            if (!empty($reply)) {
+            // If $reply_to is specified, we check that it exists, and then
+            // return it if it does
+            if (!empty($reply_to)) {
+                $reply = Notice::getKV('id', $reply_to);
+            } elseif (in_array($source, array('xmpp', 'mail', 'sms'))) {
+                // If the source lacks capability of sending the "reply_to"
+                // metadata, let's try to find an inline replyto-reference.
+                $reply = self::getInlineReplyTo($profile, $final);
+            }
 
+            if ($reply instanceof Notice) {
                 if (!$reply->inScope($profile)) {
                     // TRANS: Client error displayed when trying to reply to a notice a the target has no access to.
                     // TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
@@ -502,8 +532,8 @@ class Notice extends Managed_DataObject
                 $notice->reply_to     = $reply->id;
                 $notice->conversation = $reply->conversation;
 
-                // If the original is private to a group, and notice has no group specified,
-                // make it to the same group(s)
+                // If the original is private to a group, and notice has
+                // no group specified, make it to the same group(s)
 
                 if (empty($groups) && ($reply->scope & Notice::GROUP_SCOPE)) {
                     $groups = array();
@@ -801,7 +831,11 @@ class Notice extends Managed_DataObject
         if (common_config('attachments', 'process_links')) {
             // @fixme validation?
             foreach (array_unique($urls) as $url) {
-                File::processNew($url, $this->id);
+                try {
+                    File::processNew($url, $this->id);
+                } catch (ServerException $e) {
+                    // Could not save URL. Log it?
+                }
             }
         }
     }
@@ -810,7 +844,11 @@ class Notice extends Managed_DataObject
      * @private callback
      */
     function saveUrl($url, $notice_id) {
-        File::processNew($url, $notice_id);
+        try {
+            File::processNew($url, $notice_id);
+        } catch (ServerException $e) {
+            // Could not save URL. Log it?
+        }
     }
 
     static function checkDupes($profile_id, $content) {
@@ -1235,10 +1273,9 @@ class Notice extends Managed_DataObject
         $sender = Profile::getKV($this->profile_id);
 
         foreach (array_unique($uris) as $uri) {
-
-            $profile = Profile::fromURI($uri);
-
-            if (!$profile instanceof Profile) {
+            try {
+                $profile = Profile::fromUri($uri);
+            } catch (UnknownUriException $e) {
                 common_log(LOG_WARNING, "Unable to determine profile for URI '$uri'");
                 continue;
             }
@@ -1472,7 +1509,12 @@ class Notice extends Managed_DataObject
 
             $act->id      = $this->uri;
             $act->time    = strtotime($this->created);
-            $act->link    = $this->getUrl();
+            try {
+                $act->link    = $this->getUrl();
+            } catch (InvalidUrlException $e) {
+                // The notice is probably a share or similar, which don't
+                // have a representational URL of their own.
+            }
             $act->content = common_xml_safe_str($this->rendered);
 
             $profile = $this->getProfile();
@@ -1697,90 +1739,41 @@ class Notice extends Managed_DataObject
         return $noun->asString('activity:' . $element);
     }
 
-    // FIXME: Replace all bestUrl with getUrl and do exception handling
-    function bestUrl()
-    {
-        try {
-            return $this->getUrl();
-        } catch (InvalidUrlException $e) {
-            return common_local_url('shownotice', array('notice' => $this->id));
-        }
-    }
-
-
     /**
      * Determine which notice, if any, a new notice is in reply to.
      *
      * For conversation tracking, we try to see where this notice fits
-     * in the tree. Rough algorithm is:
-     *
-     * if (reply_to is set and valid) {
-     *     return reply_to;
-     * } else if ((source not API or Web) and (content starts with "T NAME" or "@name ")) {
-     *     return ID of last notice by initial @name in content;
-     * }
+     * in the tree. Beware that this may very well give false positives
+     * and add replies to wrong threads (if there have been newer posts
+     * by the same user as we're replying to).
      *
-     * Note that all @nickname instances will still be used to save "reply" records,
-     * so the notice shows up in the mentioned users' "replies" tab.
-     *
-     * @param integer $reply_to   ID passed in by Web or API
-     * @param integer $profile_id ID of author
-     * @param string  $source     Source tag, like 'web' or 'gwibber'
+     * @param Profile $sender     Author profile
      * @param string  $content    Final notice content
      *
      * @return integer ID of replied-to notice, or null for not a reply.
      */
 
-    static function getReplyTo($reply_to, $profile_id, $source, $content)
+    static function getInlineReplyTo(Profile $sender, $content)
     {
-        static $lb = array('xmpp', 'mail', 'sms', 'omb');
-
-        // If $reply_to is specified, we check that it exists, and then
-        // return it if it does
-
-        if (!empty($reply_to)) {
-            $reply_notice = Notice::getKV('id', $reply_to);
-            if ($reply_notice instanceof Notice) {
-                return $reply_notice;
-            }
-        }
-
-        // If it's not a "low bandwidth" source (one where you can't set
-        // a reply_to argument), we return. This is mostly web and API
-        // clients.
-
-        if (!in_array($source, $lb)) {
-            return null;
-        }
-
         // Is there an initial @ or T?
-
-        if (preg_match('/^T ([A-Z0-9]{1,64}) /', $content, $match) ||
-            preg_match('/^@([a-z0-9]{1,64})\s+/', $content, $match)) {
+        if (preg_match('/^T ([A-Z0-9]{1,64}) /', $content, $match)
+                || preg_match('/^@([a-z0-9]{1,64})\s+/', $content, $match)) {
             $nickname = common_canonical_nickname($match[1]);
         } else {
             return null;
         }
 
         // Figure out who that is.
-
-        $sender = Profile::getKV('id', $profile_id);
-        if (!$sender instanceof Profile) {
-            return null;
-        }
-
         $recipient = common_relative_profile($sender, $nickname, common_sql_now());
 
-        if (!$recipient instanceof Profile) {
-            return null;
-        }
-
-        // Get their last notice
-
-        $last = $recipient->getCurrentNotice();
-
-        if ($last instanceof Notice) {
-            return $last;
+        if ($recipient instanceof Profile) {
+            // Get their last notice
+            $last = $recipient->getCurrentNotice();
+            if ($last instanceof Notice) {
+                return $last;
+            }
+            // Maybe in the future we want to handle something else below
+            // so don't return getCurrentNotice() immediately.
         }
 
         return null;
@@ -1822,36 +1815,24 @@ class Notice extends Managed_DataObject
     /**
      * Convenience function for posting a repeat of an existing message.
      *
-     * @param int $repeater_id: profile ID of user doing the repeat
+     * @param Profile $repeater Profile which is doing the repeat
      * @param string $source: posting source key, eg 'web', 'api', etc
      * @return Notice
      *
      * @throws Exception on failure or permission problems
      */
-    function repeat($repeater_id, $source)
+    function repeat(Profile $repeater, $source)
     {
-        $author = Profile::getKV('id', $this->profile_id);
+        $author = $this->getProfile();
 
         // TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
         // TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
         $content = sprintf(_('RT @%1$s %2$s'),
-                           $author->nickname,
+                           $author->getNickname(),
                            $this->content);
 
-        $maxlen = common_config('site', 'textlimit');
-        if ($maxlen > 0 && mb_strlen($content) > $maxlen) {
-            // Web interface and current Twitter API clients will
-            // pull the original notice's text, but some older
-            // clients and RSS/Atom feeds will see this trimmed text.
-            //
-            // Unfortunately this is likely to lose tags or URLs
-            // at the end of long notices.
-            $content = mb_substr($content, 0, $maxlen - 4) . ' ...';
-        }
-
         // Scope is same as this one's
-
-        return self::saveNew($repeater_id,
+        return self::saveNew($repeater->id,
                              $content,
                              $source,
                              array('repeat_of' => $this->id,
@@ -2518,7 +2499,7 @@ class Notice extends Managed_DataObject
                                $notice->_setProfile($map[$notice->profile_id]);
                        }
             } catch (NoProfileException $e) {
-                common_log(LOG_WARNING, "Failed to fill profile in Notice with non-existing entry for profile_id: {$e->id}");
+                common_log(LOG_WARNING, "Failed to fill profile in Notice with non-existing entry for profile_id: {$e->profile_id}");
                 unset($notices[$entry]);
             }
                }