]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - classes/Notice.php
Use recently implemented functions in saveKnownReplies
[quix0rs-gnu-social.git] / classes / Notice.php
index e4d10a5bad5b8876d71f312863d03dbd432ac936..b359139abcad270e404554adf014f10752a6b24d 100644 (file)
@@ -158,43 +158,14 @@ class Notice extends Managed_DataObject
         $this->_profile[$this->profile_id] = $profile;
     }
 
-    public function deleteAs(Profile $actor)
+    public function deleteAs(Profile $actor, $delete_event=true)
     {
-        if ($this->getProfile()->sameAs($actor) || $actor->hasRight(Right::DELETEOTHERSNOTICE)) {
-            return $this->delete();
-        }
-        throw new AuthorizationException('You are not allowed to delete other user\'s notices');
-    }
-
-    function delete($useWhere=false)
-    {
-        // For auditing purposes, save a record that the notice
-        // was deleted.
-
-        // @fixme we have some cases where things get re-run and so the
-        // insert fails.
-        $deleted = Deleted_notice::getKV('id', $this->id);
-
-        if (!$deleted instanceof Deleted_notice) {
-            $deleted = Deleted_notice::getKV('uri', $this->uri);
-        }
-
-        if (!$deleted instanceof Deleted_notice) {
-            $deleted = new Deleted_notice();
-
-            $deleted->id         = $this->id;
-            $deleted->profile_id = $this->profile_id;
-            $deleted->uri        = $this->uri;
-            $deleted->created    = $this->created;
-            $deleted->deleted    = common_sql_now();
-
-            $deleted->insert();
+        if (!$this->getProfile()->sameAs($actor) && !$actor->hasRight(Right::DELETEOTHERSNOTICE)) {
+            throw new AuthorizationException(_('You are not allowed to delete another user\'s notice.'));
         }
 
         if (Event::handle('NoticeDeleteRelated', array($this))) {
-
             // Clear related records
-
             $this->clearReplies();
             $this->clearLocation();
             $this->clearRepeats();
@@ -202,10 +173,21 @@ class Notice extends Managed_DataObject
             $this->clearGroupInboxes();
             $this->clearFiles();
             $this->clearAttentions();
-
             // NOTE: we don't clear queue items
         }
 
+        $result = null;
+        if (!$delete_event || Event::handle('DeleteNoticeAsProfile', array($this, $actor, &$result))) {
+            // If $delete_event is true, we run the event. If the Event then 
+            // returns false it is assumed everything was handled properly 
+            // and the notice was deleted.
+            $result = $this->delete();
+        }
+        return $result;
+    }
+
+    public function delete($useWhere=false)
+    {
         $result = parent::delete($useWhere);
 
         $this->blowOnDelete();
@@ -275,6 +257,11 @@ class Notice extends Managed_DataObject
         return $this->content;
     }
 
+    public function getRendered()
+    {
+        return $this->rendered;
+    }
+
     /*
      * Get the original representation URL of this notice.
      *
@@ -298,10 +285,8 @@ class Notice extends Managed_DataObject
         }
     }
 
-    public function get_object_type($canonical=false) {
-        return $canonical
-                ? ActivityObject::canonicalType($this->object_type)
-                : $this->object_type;
+    public function getObjectType($canonical=false) {
+        return ActivityUtils::resolveUri($this->object_type, $canonical);
     }
 
     public static function getByUri($uri)
@@ -769,7 +754,7 @@ class Notice extends Managed_DataObject
 
         $defaults = array(
                           'groups'   => array(),
-                          'is_local' => self::LOCAL_PUBLIC,
+                          'is_local' => $actor->isLocal() ? self::LOCAL_PUBLIC : self::REMOTE,
                           'mentions' => array(),
                           'reply_to' => null,
                           'repeat_of' => null,
@@ -789,12 +774,36 @@ class Notice extends Managed_DataObject
         }
         extract($options, EXTR_SKIP);
 
+        // dupe check
         $stored = new Notice();
-        if (!empty($uri)) {
+        if (!empty($uri) && !ActivityUtils::compareVerbs($act->verb, array(ActivityVerb::DELETE))) {
             $stored->uri = $uri;
             if ($stored->find()) {
                 common_debug('cannot create duplicate Notice URI: '.$stored->uri);
-                throw new Exception('Notice URI already exists');
+                // I _assume_ saving a Notice with a colliding URI means we're really trying to
+                // save the same notice again...
+                throw new AlreadyFulfilledException('Notice URI already exists');
+            }
+        }
+
+        $autosource = common_config('public', 'autosource');
+
+        // Sandboxed are non-false, but not 1, either
+        if (!$actor->hasRight(Right::PUBLICNOTICE) ||
+                ($source && $autosource && in_array($source, $autosource))) {
+            // FIXME: ...what about remote nonpublic? Hmmm. That is, if we sandbox remote profiles...
+            $stored->is_local = Notice::LOCAL_NONPUBLIC;
+        } else {
+            $stored->is_local = intval($is_local);
+        }
+
+        if (!$stored->isLocal()) {
+            // Only do these checks for non-local notices. Local notices will generate these values later.
+            if (!common_valid_http_url($url)) {
+                common_debug('Bad notice URL: ['.$url.'], URI: ['.$uri.']. Cannot link back to original! This is normal for shared notices etc.');
+            }
+            if (empty($uri)) {
+                throw new ServerException('No URI for remote notice. Cannot accept that.');
             }
         }
 
@@ -807,17 +816,9 @@ class Notice extends Managed_DataObject
         // Use the local user's shortening preferences, if applicable.
         $stored->rendered = $actor->isLocal()
                                 ? $actor->shortenLinks($act->content)
-                                : $act->content;
+                                : common_purify($act->content);
         $stored->content = common_strip_html($stored->rendered);
 
-        $autosource = common_config('public', 'autosource');
-
-        // Sandboxed are non-false, but not 1, either
-        if (!$actor->hasRight(Right::PUBLICNOTICE) ||
-            ($source && $autosource && in_array($source, $autosource))) {
-            $stored->is_local = Notice::LOCAL_NONPUBLIC;
-        }
-
         // Maybe a missing act-time should be fatal if the actor is not local?
         if (!empty($act->time)) {
             $stored->created = common_sql_date($act->time);
@@ -846,7 +847,6 @@ class Notice extends Managed_DataObject
             // 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();
                 $replyGroups = $reply->getGroups();
                 foreach ($replyGroups as $group) {
                     if ($actor->isMember($group)) {
@@ -901,11 +901,24 @@ class Notice extends Managed_DataObject
             $urls[] = $href;
         }
 
+        if (ActivityUtils::compareVerbs($stored->verb, array(ActivityVerb::POST))) {
+            if (empty($act->objects[0]->type)) {
+                // Default type for the post verb is 'note', but we know it's
+                // a 'comment' if it is in reply to something.
+                $stored->object_type = empty($stored->reply_to) ? ActivityObject::NOTE : ActivityObject::COMMENT;
+            } else {
+                //TODO: Is it safe to always return a relative URI? The
+                // JSON version of ActivityStreams always use it, so we
+                // should definitely be able to handle it...
+                $stored->object_type = ActivityUtils::resolveUri($act->objects[0]->type, true);
+            }
+        }
+
         if (Event::handle('StartNoticeSave', array(&$stored))) {
             // XXX: some of these functions write to the DB
 
             try {
-                $stored->insert();    // throws exception on error
+                $result = $stored->insert();    // throws exception on error
 
                 if ($notloc instanceof Notice_location) {
                     $notloc->notice_id = $stored->getID();
@@ -917,7 +930,7 @@ class Notice extends Managed_DataObject
                 $object = null;
                 Event::handle('StoreActivityObject', array($act, $stored, $options, &$object));
                 if (empty($object)) {
-                    throw new ServerException('Unsuccessful call to StoreActivityObject '.$stored->uri . ': '.$act->asString());
+                    throw new ServerException('Unsuccessful call to StoreActivityObject '.$stored->getUri() . ': '.$act->asString());
                 }
 
                 // If it's not part of a conversation, it's the beginning
@@ -946,11 +959,11 @@ class Notice extends Managed_DataObject
 
         // Save per-notice metadata...
         $mentions = array();
-        $groups   = array();
+        $group_ids   = array();
 
         // This event lets plugins filter out non-local recipients (attentions we don't care about)
         // Used primarily for OStatus (and if we don't federate, all attentions would be local anyway)
-        Event::handle('GetLocalAttentions', array($actor, $act->context->attention, &$mentions, &$groups));
+        Event::handle('GetLocalAttentions', array($actor, $act->context->attention, &$mentions, &$group_ids));
 
         if (!empty($mentions)) {
             $stored->saveKnownReplies($mentions);
@@ -968,7 +981,7 @@ class Notice extends Managed_DataObject
         // to avoid errors on duplicates.
         // Note: groups should always be set.
 
-        $stored->saveKnownGroups($groups);
+        $stored->saveKnownGroups($group_ids);
 
         if (!empty($urls)) {
             $stored->saveKnownUrls($urls);
@@ -985,15 +998,13 @@ class Notice extends Managed_DataObject
     }
 
     static public function figureOutScope(Profile $actor, array $groups, $scope=null) {
-        if (is_null($scope)) {
-            $scope = self::defaultScope();
-        }
+        $scope = is_null($scope) ? self::defaultScope() : intval($scope);
 
         // For private streams
         try {
             $user = $actor->getUser();
             // FIXME: We can't do bit comparison with == (Legacy StatusNet thing. Let's keep it for now.)
-            if ($user->private_stream && ($scope == Notice::PUBLIC_SCOPE || $scope == Notice::SITE_SCOPE)) {
+            if ($user->private_stream && ($scope === Notice::PUBLIC_SCOPE || $scope === Notice::SITE_SCOPE)) {
                 $scope |= Notice::FOLLOWER_SCOPE;
             }
         } catch (NoSuchUserException $e) {
@@ -1495,13 +1506,8 @@ class Notice extends Managed_DataObject
      *        best with generalizations on user_group to support
      *        remote groups better.
      */
-    function saveKnownGroups($group_ids)
+    function saveKnownGroups(array $group_ids)
     {
-        if (!is_array($group_ids)) {
-            // TRANS: Server exception thrown when no array is provided to the method saveKnownGroups().
-            throw new ServerException(_('Bad type provided to saveKnownGroups.'));
-        }
-
         $groups = array();
         foreach (array_unique($group_ids) as $id) {
             $group = User_group::getKV('id', $id);
@@ -1577,7 +1583,7 @@ class Notice extends Managed_DataObject
             return;
         }
 
-        $sender = Profile::getKV($this->profile_id);
+        $sender = $this->getProfile();
 
         foreach (array_unique($uris) as $uri) {
             try {
@@ -1592,11 +1598,9 @@ class Notice extends Managed_DataObject
                 continue;
             }
 
-            $this->saveReply($profile->id);
-            self::blow('reply:stream:%d', $profile->id);
+            $this->saveReply($profile->getID());
+            self::blow('reply:stream:%d', $profile->getID());
         }
-
-        return;
     }
 
     /**
@@ -1630,6 +1634,8 @@ class Notice extends Managed_DataObject
             self::blow('reply:stream:%d', $parentauthor->id);
         } catch (NoParentNoticeException $e) {
             // Not a reply, since it has no parent!
+        } catch (NoResultException $e) {
+            // Parent notice was probably deleted
         }
 
         // @todo ideally this parser information would only
@@ -1724,7 +1730,6 @@ class Notice extends Managed_DataObject
     function sendReplyNotifications()
     {
         // Don't send reply notifications for repeats
-
         if ($this->isRepeat()) {
             return array();
         }
@@ -1734,9 +1739,11 @@ class Notice extends Managed_DataObject
             require_once INSTALLDIR.'/lib/mail.php';
 
             foreach ($recipientIds as $recipientId) {
-                $user = User::getKV('id', $recipientId);
-                if ($user instanceof User) {
+                try {
+                    $user = User::getByID($recipientId);
                     mail_notify_attn($user, $this);
+                } catch (NoResultException $e) {
+                    // No such user
                 }
             }
             Event::handle('EndNotifyMentioned', array($this, $recipientIds));
@@ -1855,6 +1862,8 @@ class Notice extends Managed_DataObject
                 $ctx->replyToUrl = $reply->getUrl(true);    // true for fallback to local URL, less messy
             } catch (NoParentNoticeException $e) {
                 // This is not a reply to something
+            } catch (NoResultException $e) {
+                // Parent notice was probably deleted
             }
 
             try {
@@ -2411,7 +2420,7 @@ class Notice extends Managed_DataObject
             $this->uri = sprintf('%s%s=%d:%s=%s',
                                 TagURI::mint(),
                                 'noticeId', $this->id,
-                                'objectType', $this->get_object_type(true));
+                                'objectType', $this->getObjectType(true));
             $changed = true;
         }
 
@@ -2473,8 +2482,13 @@ class Notice extends Managed_DataObject
 
     public function isLocal()
     {
-        return ($this->is_local == Notice::LOCAL_PUBLIC ||
-                $this->is_local == Notice::LOCAL_NONPUBLIC);
+        $is_local = intval($this->is_local);
+        return ($is_local === self::LOCAL_PUBLIC || $is_local === self::LOCAL_NONPUBLIC);
+    }
+
+    public function getScope()
+    {
+        return intval($this->scope);
     }
 
     public function isRepeat()
@@ -2667,13 +2681,9 @@ class Notice extends Managed_DataObject
 
     protected function _inScope($profile)
     {
-        if (!is_null($this->scope)) {
-            $scope = $this->scope;
-        } else {
-            $scope = self::defaultScope();
-        }
+        $scope = is_null($this->scope) ? self::defaultScope() : $this->getScope();
 
-        if ($scope == 0 && !$this->getProfile()->isPrivateStream()) { // Not scoping, so it is public.
+        if ($scope === 0 && !$this->getProfile()->isPrivateStream()) { // Not scoping, so it is public.
             return !$this->isHiddenSpam($profile);
         }
 
@@ -2760,10 +2770,24 @@ class Notice extends Managed_DataObject
 
     public function getParent()
     {
+       $reply_to_id = null;
+
         if (empty($this->reply_to)) {
             throw new NoParentNoticeException($this);
         }
-        return self::getByID($this->reply_to);
+
+       // The reply_to ID in the table Notice could exist with a number
+       // however, the replied to notice might not exist in the database.
+       // Thus we need to catch the exception and throw the NoParentNoticeException else 
+       // the timeline will not display correctly.
+       try {
+               $reply_to_id = self::getByID($this->reply_to);
+       } catch(Exception $e){
+               throw new NoParentNoticeException($this);
+       }
+
+
+        return $reply_to_id;
     }
 
     /**