]> git.mxchange.org Git - friendica.git/commitdiff
Rename ItemInserter into ItemHelper
authorArt4 <art4@wlabs.de>
Thu, 23 Jan 2025 12:11:18 +0000 (12:11 +0000)
committerArt4 <art4@wlabs.de>
Thu, 23 Jan 2025 12:11:18 +0000 (12:11 +0000)
src/Model/Item.php
src/Model/ItemHelper.php [new file with mode: 0644]
src/Model/ItemInserter.php [deleted file]

index 18015b700a5aa9ad63d5f4b995c9a79bbaf776cb..b0ec02956357a4860c3b1ba7280f5dc71b782ea0 100644 (file)
@@ -760,7 +760,7 @@ class Item
         */
        public static function insert(array $item, int $notify = 0, bool $post_local = true): int
        {
-               $itemInserter = new ItemInserter(
+               $itemHelper = new ItemHelper(
                        DI::contentItem(),
                        DI::activity(),
                        DI::logger(),
@@ -776,7 +776,7 @@ class Item
 
                // If it is a posting where users should get notifications, then define it as wall posting
                if ($notify) {
-                       $item = $itemInserter->prepareOriginPost($item);
+                       $item = $itemHelper->prepareOriginPost($item);
 
                        if (is_int($notify) && in_array($notify, Worker::PRIORITIES)) {
                                $priority = $notify;
@@ -789,7 +789,7 @@ class Item
                        $item['network'] = trim(($item['network'] ?? '') ?: Protocol::PHANTOM);
                }
 
-               $item = $itemInserter->prepareItemData($item, (bool) $notify);
+               $item = $itemHelper->prepareItemData($item, (bool) $notify);
 
                // Store conversation data
                $source = $item['source'] ?? '';
@@ -830,7 +830,7 @@ class Item
                        }
                }
 
-               $item = $itemInserter->validateItemData($item);
+               $item = $itemHelper->validateItemData($item);
 
                // Ensure that there is an avatar cache
                Contact::checkAvatarCache($item['author-id']);
@@ -851,13 +851,13 @@ class Item
                }
 
                if ($item['gravity'] !== self::GRAVITY_PARENT) {
-                       $toplevel_parent = $itemInserter->getTopLevelParent($item);
+                       $toplevel_parent = $itemHelper->getTopLevelParent($item);
                        if (empty($toplevel_parent)) {
                                return 0;
                        }
 
                        $parent_id     = (int) $toplevel_parent['id'];
-                       $item          = $itemInserter->handleToplevelParent($item, $toplevel_parent, $defined_permissions);
+                       $item          = $itemHelper->handleToplevelParent($item, $toplevel_parent, $defined_permissions);
                        $parent_origin = $toplevel_parent['origin'];
                } else {
                        $parent_id     = 0;
diff --git a/src/Model/ItemHelper.php b/src/Model/ItemHelper.php
new file mode 100644 (file)
index 0000000..ab17b84
--- /dev/null
@@ -0,0 +1,318 @@
+<?php
+
+// Copyright (C) 2010-2024, the Friendica project
+// SPDX-FileCopyrightText: 2010-2024 the Friendica project
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+namespace Friendica\Model;
+
+use Friendica\App\BaseURL;
+use Friendica\Content\Item as ItemContent;
+use Friendica\Core\Protocol;
+use Friendica\Database\Database;
+use Friendica\Protocol\Activity;
+use Friendica\Util\DateTimeFormat;
+use Psr\Log\LoggerInterface;
+
+/**
+ * A helper class for handling an Item Model
+ *
+ * @internal only for use in Friendica\Content\Item class
+ *
+ * @see Item::insert()
+ */
+final class ItemHelper
+{
+       private ItemContent $itemContent;
+
+       private Activity $activity;
+
+       private LoggerInterface $logger;
+
+       private Database $database;
+
+       private string $baseUrl;
+
+       public function __construct(
+               ItemContent $itemContent,
+               Activity $activity,
+               LoggerInterface $logger,
+               Database $database,
+               BaseURL $baseURL
+       ) {
+               $this->itemContent = $itemContent;
+               $this->activity    = $activity;
+               $this->logger      = $logger;
+               $this->database    = $database;
+               $this->baseUrl     = $baseURL->__toString();
+       }
+
+       public function prepareOriginPost(array $item): array
+       {
+               $item = $this->itemContent->initializePost($item);
+               $item = $this->itemContent->finalizePost($item, false);
+
+               return $item;
+       }
+
+       public function prepareItemData(array $item, bool $notify): array
+       {
+               $item['guid'] = Item::guid($item, $notify);
+               $item['uri']  = substr(trim($item['uri'] ?? '') ?: Item::newURI($item['guid']), 0, 255);
+
+               // Store URI data
+               $item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]);
+
+               // Backward compatibility: parent-uri used to be the direct parent uri.
+               // If it is provided without a thr-parent, it probably is the old behavior.
+               if (empty($item['thr-parent']) || empty($item['parent-uri'])) {
+                       $item['thr-parent'] = trim($item['thr-parent'] ?? $item['parent-uri'] ?? $item['uri']);
+                       $item['parent-uri'] = $item['thr-parent'];
+               }
+
+               $item['thr-parent-id'] = ItemURI::getIdByURI($item['thr-parent']);
+               $item['parent-uri-id'] = ItemURI::getIdByURI($item['parent-uri']);
+
+               return $item;
+       }
+
+       public function validateItemData(array $item): array
+       {
+               $item['wall']          = intval($item['wall'] ?? 0);
+               $item['extid']         = trim($item['extid'] ?? '');
+               $item['author-name']   = trim($item['author-name'] ?? '');
+               $item['author-link']   = trim($item['author-link'] ?? '');
+               $item['author-avatar'] = trim($item['author-avatar'] ?? '');
+               $item['owner-name']    = trim($item['owner-name'] ?? '');
+               $item['owner-link']    = trim($item['owner-link'] ?? '');
+               $item['owner-avatar']  = trim($item['owner-avatar'] ?? '');
+               $item['received']      = (isset($item['received'])  ? DateTimeFormat::utc($item['received'])  : DateTimeFormat::utcNow());
+               $item['created']       = (isset($item['created'])   ? DateTimeFormat::utc($item['created'])   : $item['received']);
+               $item['edited']        = (isset($item['edited'])    ? DateTimeFormat::utc($item['edited'])    : $item['created']);
+               $item['changed']       = (isset($item['changed'])   ? DateTimeFormat::utc($item['changed'])   : $item['created']);
+               $item['commented']     = (isset($item['commented']) ? DateTimeFormat::utc($item['commented']) : $item['created']);
+               $item['title']         = substr(trim($item['title'] ?? ''), 0, 255);
+               $item['location']      = trim($item['location'] ?? '');
+               $item['coord']         = trim($item['coord'] ?? '');
+               $item['visible']       = (isset($item['visible']) ? intval($item['visible']) : 1);
+               $item['deleted']       = 0;
+               $item['verb']          = trim($item['verb'] ?? '');
+               $item['object-type']   = trim($item['object-type'] ?? '');
+               $item['object']        = trim($item['object'] ?? '');
+               $item['target-type']   = trim($item['target-type'] ?? '');
+               $item['target']        = trim($item['target'] ?? '');
+               $item['plink']         = substr(trim($item['plink'] ?? ''), 0, 255);
+               $item['allow_cid']     = trim($item['allow_cid'] ?? '');
+               $item['allow_gid']     = trim($item['allow_gid'] ?? '');
+               $item['deny_cid']      = trim($item['deny_cid'] ?? '');
+               $item['deny_gid']      = trim($item['deny_gid'] ?? '');
+               $item['private']       = intval($item['private'] ?? Item::PUBLIC);
+               $item['body']          = trim($item['body'] ?? '');
+               $item['raw-body']      = trim($item['raw-body'] ?? $item['body']);
+               $item['app']           = trim($item['app'] ?? '');
+               $item['origin']        = intval($item['origin'] ?? 0);
+               $item['postopts']      = trim($item['postopts'] ?? '');
+               $item['resource-id']   = trim($item['resource-id'] ?? '');
+               $item['event-id']      = intval($item['event-id'] ?? 0);
+               $item['inform']        = trim($item['inform'] ?? '');
+               $item['file']          = trim($item['file'] ?? '');
+
+               // Items cannot be stored before they happen ...
+               if ($item['created'] > DateTimeFormat::utcNow()) {
+                       $item['created'] = DateTimeFormat::utcNow();
+               }
+
+               // We haven't invented time travel by now.
+               if ($item['edited'] > DateTimeFormat::utcNow()) {
+                       $item['edited'] = DateTimeFormat::utcNow();
+               }
+
+               $item['plink'] = ($item['plink'] ?? '') ?: $this->baseUrl . '/display/' . urlencode($item['guid']);
+
+               $item['gravity'] = $this->getGravity($item);
+
+               if ($item['gravity'] === Item::GRAVITY_UNKNOWN) {
+                       $this->logger->info('Unknown gravity for verb', ['verb' => $item['verb']]);
+               }
+
+               $default = [
+                       'url'   => $item['author-link'], 'name' => $item['author-name'],
+                       'photo' => $item['author-avatar'], 'network' => $item['network']
+               ];
+               $item['author-id'] = ($item['author-id'] ?? 0) ?: Contact::getIdForURL($item['author-link'], 0, null, $default);
+
+               $default = [
+                       'url'   => $item['owner-link'], 'name' => $item['owner-name'],
+                       'photo' => $item['owner-avatar'], 'network' => $item['network']
+               ];
+               $item['owner-id'] = ($item['owner-id'] ?? 0) ?: Contact::getIdForURL($item['owner-link'], 0, null, $default);
+
+               $item['post-reason'] = Item::getPostReason($item);
+
+               return $item;
+       }
+
+       /**
+        * Fetch top-level parent data for the given item array
+        *
+        * @param array $item
+        * @return array item array with parent data
+        * @throws \Exception
+        */
+       public function getTopLevelParent(array $item): array
+       {
+               $fields = [
+                       'uid', 'uri', 'parent-uri', 'id', 'deleted',
+                       'uri-id', 'parent-uri-id', 'restrictions', 'verb',
+                       'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
+                       'wall', 'private', 'origin', 'author-id'
+               ];
+               $condition = ['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => $item['uid']];
+               $params    = ['order' => ['id' => false]];
+               $parent    = Post::selectFirst($fields, $condition, $params);
+
+               if (!$this->database->isResult($parent) && Post::exists(['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => 0])) {
+                       $stored = Item::storeForUserByUriId($item['thr-parent-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
+                       if (!$stored && ($item['thr-parent-id'] != $item['parent-uri-id'])) {
+                               $stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
+                       }
+                       if ($stored) {
+                               $this->logger->info('Stored thread parent item for user', ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid'], 'stored' => $stored]);
+                               $parent = Post::selectFirst($fields, $condition, $params);
+                       }
+               }
+
+               if (!$this->database->isResult($parent)) {
+                       $this->logger->notice('item parent was not found - ignoring item', ['uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
+                       return [];
+               }
+
+               if ($this->hasRestrictions($item, $parent['author-id'], $parent['restrictions'])) {
+                       $this->logger->notice('Restrictions apply - ignoring item', ['restrictions' => $parent['restrictions'], 'verb' => $parent['verb'], 'uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
+                       return [];
+               }
+
+               if ($parent['uri-id'] == $parent['parent-uri-id']) {
+                       return $parent;
+               }
+
+               $condition = [
+                       'uri-id'        => $parent['parent-uri-id'],
+                       'parent-uri-id' => $parent['parent-uri-id'],
+                       'uid'           => $parent['uid']
+               ];
+               $params          = ['order' => ['id' => false]];
+               $toplevel_parent = Post::selectFirst($fields, $condition, $params);
+
+               if (!$this->database->isResult($toplevel_parent) && $item['origin']) {
+                       $stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
+                       $this->logger->info('Stored parent item for user', ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid'], 'stored' => $stored]);
+                       $toplevel_parent = Post::selectFirst($fields, $condition, $params);
+               }
+
+               if (!$this->database->isResult($toplevel_parent)) {
+                       $this->logger->notice('item top level parent was not found - ignoring item', ['parent-uri-id' => $parent['parent-uri-id'], 'uid' => $parent['uid']]);
+                       return [];
+               }
+
+               return $toplevel_parent;
+       }
+
+       public function handleToplevelParent(array $item, array $toplevel_parent, bool $defined_permissions): array
+       {
+               $parent_id             = (int) $toplevel_parent['id'];
+               $item['parent-uri']    = $toplevel_parent['uri'];
+               $item['parent-uri-id'] = $toplevel_parent['uri-id'];
+               $item['deleted']       = $toplevel_parent['deleted'];
+               $item['wall']          = $toplevel_parent['wall'];
+
+               // Reshares have to keep their permissions to allow groups to work
+               if (!$defined_permissions && (!$item['origin'] || ($item['verb'] != Activity::ANNOUNCE))) {
+                       // Don't store the permissions on pure AP posts
+                       $store_permissions = ($item['network'] != Protocol::ACTIVITYPUB) || $item['origin'] || !empty($item['diaspora_signed_text']);
+                       $item['allow_cid'] = $store_permissions ? $toplevel_parent['allow_cid'] : '';
+                       $item['allow_gid'] = $store_permissions ? $toplevel_parent['allow_gid'] : '';
+                       $item['deny_cid']  = $store_permissions ? $toplevel_parent['deny_cid'] : '';
+                       $item['deny_gid']  = $store_permissions ? $toplevel_parent['deny_gid'] : '';
+               }
+
+               // Don't federate received participation messages
+               if ($item['verb'] != Activity::FOLLOW) {
+                       $item['wall'] = $toplevel_parent['wall'];
+               } else {
+                       $item['wall'] = false;
+                       // Participations are technical messages, so they are set to "seen" automatically
+                       $item['unseen'] = false;
+               }
+
+               /*
+                * If the parent is private, force privacy for the entire conversation
+                * This differs from the above settings as it subtly allows comments from
+                * email correspondents to be private even if the overall thread is not.
+                */
+               if (!$defined_permissions && $toplevel_parent['private']) {
+                       $item['private'] = $toplevel_parent['private'];
+               }
+
+               // If its a post that originated here then tag the thread as "mention"
+               if ($item['origin'] && $item['uid']) {
+                       $this->database->update('post-thread-user', ['mention' => true], ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
+                       $this->logger->info('tagged thread as mention', ['parent' => $parent_id, 'parent-uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
+               }
+
+               // Update the contact relations
+               Contact\Relation::store($toplevel_parent['author-id'], $item['author-id'], $item['created']);
+
+               return $item;
+       }
+
+       private function hasRestrictions(array $item, int $author_id, int $restrictions = null): bool
+       {
+               if (empty($restrictions) || ($author_id == $item['author-id'])) {
+                       return false;
+               }
+
+               // We only have to apply restrictions if the post originates from our server or is federated.
+               // Every other time we can trust the remote system.
+               if (!in_array($item['network'], Protocol::FEDERATED) && !$item['origin']) {
+                       return false;
+               }
+
+               if (($restrictions & Item::CANT_REPLY) && ($item['verb'] == Activity::POST)) {
+                       return true;
+               }
+
+               if (($restrictions & Item::CANT_ANNOUNCE) && ($item['verb'] == Activity::ANNOUNCE)) {
+                       return true;
+               }
+
+               if (($restrictions & Item::CANT_LIKE) && in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE, Activity::ATTEND, Activity::ATTENDMAYBE, Activity::ATTENDNO])) {
+                       return true;
+               }
+
+               return false;
+       }
+
+       /**
+        * Get the gravity for the given item array
+        *
+        * @return int gravity
+        */
+       private function getGravity(array $item): int
+       {
+               if (isset($item['gravity'])) {
+                       return intval($item['gravity']);
+               } elseif ($item['parent-uri-id'] === $item['uri-id']) {
+                       return Item::GRAVITY_PARENT;
+               } elseif ($this->activity->match($item['verb'], Activity::POST)) {
+                       return Item::GRAVITY_COMMENT;
+               } elseif ($this->activity->match($item['verb'], Activity::FOLLOW)) {
+                       return Item::GRAVITY_ACTIVITY;
+               } elseif ($this->activity->match($item['verb'], Activity::ANNOUNCE)) {
+                       return Item::GRAVITY_ACTIVITY;
+               }
+
+               return Item::GRAVITY_UNKNOWN;   // Should not happen
+       }
+}
diff --git a/src/Model/ItemInserter.php b/src/Model/ItemInserter.php
deleted file mode 100644 (file)
index fc042bb..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-<?php
-
-// Copyright (C) 2010-2024, the Friendica project
-// SPDX-FileCopyrightText: 2010-2024 the Friendica project
-//
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-namespace Friendica\Model;
-
-use Friendica\App\BaseURL;
-use Friendica\Content\Item as ItemContent;
-use Friendica\Core\Protocol;
-use Friendica\Database\Database;
-use Friendica\Protocol\Activity;
-use Friendica\Util\DateTimeFormat;
-use Psr\Log\LoggerInterface;
-
-/**
- * A helper class for inserting an Item Model
- *
- * @internal only for use in Friendica\Content\Item class
- *
- * @see Item::insert()
- */
-final class ItemInserter
-{
-       private ItemContent $itemContent;
-
-       private Activity $activity;
-
-       private LoggerInterface $logger;
-
-       private Database $database;
-
-       private string $baseUrl;
-
-       public function __construct(
-               ItemContent $itemContent,
-               Activity $activity,
-               LoggerInterface $logger,
-               Database $database,
-               BaseURL $baseURL
-       ) {
-               $this->itemContent = $itemContent;
-               $this->activity    = $activity;
-               $this->logger      = $logger;
-               $this->database    = $database;
-               $this->baseUrl     = $baseURL->__toString();
-       }
-
-       public function prepareOriginPost(array $item): array
-       {
-               $item = $this->itemContent->initializePost($item);
-               $item = $this->itemContent->finalizePost($item, false);
-
-               return $item;
-       }
-
-       public function prepareItemData(array $item, bool $notify): array
-       {
-               $item['guid'] = Item::guid($item, $notify);
-               $item['uri']  = substr(trim($item['uri'] ?? '') ?: Item::newURI($item['guid']), 0, 255);
-
-               // Store URI data
-               $item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]);
-
-               // Backward compatibility: parent-uri used to be the direct parent uri.
-               // If it is provided without a thr-parent, it probably is the old behavior.
-               if (empty($item['thr-parent']) || empty($item['parent-uri'])) {
-                       $item['thr-parent'] = trim($item['thr-parent'] ?? $item['parent-uri'] ?? $item['uri']);
-                       $item['parent-uri'] = $item['thr-parent'];
-               }
-
-               $item['thr-parent-id'] = ItemURI::getIdByURI($item['thr-parent']);
-               $item['parent-uri-id'] = ItemURI::getIdByURI($item['parent-uri']);
-
-               return $item;
-       }
-
-       public function validateItemData(array $item): array
-       {
-               $item['wall']          = intval($item['wall'] ?? 0);
-               $item['extid']         = trim($item['extid'] ?? '');
-               $item['author-name']   = trim($item['author-name'] ?? '');
-               $item['author-link']   = trim($item['author-link'] ?? '');
-               $item['author-avatar'] = trim($item['author-avatar'] ?? '');
-               $item['owner-name']    = trim($item['owner-name'] ?? '');
-               $item['owner-link']    = trim($item['owner-link'] ?? '');
-               $item['owner-avatar']  = trim($item['owner-avatar'] ?? '');
-               $item['received']      = (isset($item['received'])  ? DateTimeFormat::utc($item['received'])  : DateTimeFormat::utcNow());
-               $item['created']       = (isset($item['created'])   ? DateTimeFormat::utc($item['created'])   : $item['received']);
-               $item['edited']        = (isset($item['edited'])    ? DateTimeFormat::utc($item['edited'])    : $item['created']);
-               $item['changed']       = (isset($item['changed'])   ? DateTimeFormat::utc($item['changed'])   : $item['created']);
-               $item['commented']     = (isset($item['commented']) ? DateTimeFormat::utc($item['commented']) : $item['created']);
-               $item['title']         = substr(trim($item['title'] ?? ''), 0, 255);
-               $item['location']      = trim($item['location'] ?? '');
-               $item['coord']         = trim($item['coord'] ?? '');
-               $item['visible']       = (isset($item['visible']) ? intval($item['visible']) : 1);
-               $item['deleted']       = 0;
-               $item['verb']          = trim($item['verb'] ?? '');
-               $item['object-type']   = trim($item['object-type'] ?? '');
-               $item['object']        = trim($item['object'] ?? '');
-               $item['target-type']   = trim($item['target-type'] ?? '');
-               $item['target']        = trim($item['target'] ?? '');
-               $item['plink']         = substr(trim($item['plink'] ?? ''), 0, 255);
-               $item['allow_cid']     = trim($item['allow_cid'] ?? '');
-               $item['allow_gid']     = trim($item['allow_gid'] ?? '');
-               $item['deny_cid']      = trim($item['deny_cid'] ?? '');
-               $item['deny_gid']      = trim($item['deny_gid'] ?? '');
-               $item['private']       = intval($item['private'] ?? Item::PUBLIC);
-               $item['body']          = trim($item['body'] ?? '');
-               $item['raw-body']      = trim($item['raw-body'] ?? $item['body']);
-               $item['app']           = trim($item['app'] ?? '');
-               $item['origin']        = intval($item['origin'] ?? 0);
-               $item['postopts']      = trim($item['postopts'] ?? '');
-               $item['resource-id']   = trim($item['resource-id'] ?? '');
-               $item['event-id']      = intval($item['event-id'] ?? 0);
-               $item['inform']        = trim($item['inform'] ?? '');
-               $item['file']          = trim($item['file'] ?? '');
-
-               // Items cannot be stored before they happen ...
-               if ($item['created'] > DateTimeFormat::utcNow()) {
-                       $item['created'] = DateTimeFormat::utcNow();
-               }
-
-               // We haven't invented time travel by now.
-               if ($item['edited'] > DateTimeFormat::utcNow()) {
-                       $item['edited'] = DateTimeFormat::utcNow();
-               }
-
-               $item['plink'] = ($item['plink'] ?? '') ?: $this->baseUrl . '/display/' . urlencode($item['guid']);
-
-               $item['gravity'] = $this->getGravity($item);
-
-               if ($item['gravity'] === Item::GRAVITY_UNKNOWN) {
-                       $this->logger->info('Unknown gravity for verb', ['verb' => $item['verb']]);
-               }
-
-               $default = [
-                       'url'   => $item['author-link'], 'name' => $item['author-name'],
-                       'photo' => $item['author-avatar'], 'network' => $item['network']
-               ];
-               $item['author-id'] = ($item['author-id'] ?? 0) ?: Contact::getIdForURL($item['author-link'], 0, null, $default);
-
-               $default = [
-                       'url'   => $item['owner-link'], 'name' => $item['owner-name'],
-                       'photo' => $item['owner-avatar'], 'network' => $item['network']
-               ];
-               $item['owner-id'] = ($item['owner-id'] ?? 0) ?: Contact::getIdForURL($item['owner-link'], 0, null, $default);
-
-               $item['post-reason'] = Item::getPostReason($item);
-
-               return $item;
-       }
-
-       /**
-        * Fetch top-level parent data for the given item array
-        *
-        * @param array $item
-        * @return array item array with parent data
-        * @throws \Exception
-        */
-       public function getTopLevelParent(array $item): array
-       {
-               $fields = [
-                       'uid', 'uri', 'parent-uri', 'id', 'deleted',
-                       'uri-id', 'parent-uri-id', 'restrictions', 'verb',
-                       'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid',
-                       'wall', 'private', 'origin', 'author-id'
-               ];
-               $condition = ['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => $item['uid']];
-               $params    = ['order' => ['id' => false]];
-               $parent    = Post::selectFirst($fields, $condition, $params);
-
-               if (!$this->database->isResult($parent) && Post::exists(['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => 0])) {
-                       $stored = Item::storeForUserByUriId($item['thr-parent-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
-                       if (!$stored && ($item['thr-parent-id'] != $item['parent-uri-id'])) {
-                               $stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
-                       }
-                       if ($stored) {
-                               $this->logger->info('Stored thread parent item for user', ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid'], 'stored' => $stored]);
-                               $parent = Post::selectFirst($fields, $condition, $params);
-                       }
-               }
-
-               if (!$this->database->isResult($parent)) {
-                       $this->logger->notice('item parent was not found - ignoring item', ['uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
-                       return [];
-               }
-
-               if ($this->hasRestrictions($item, $parent['author-id'], $parent['restrictions'])) {
-                       $this->logger->notice('Restrictions apply - ignoring item', ['restrictions' => $parent['restrictions'], 'verb' => $parent['verb'], 'uri-id' => $item['uri-id'], 'thr-parent-id' => $item['thr-parent-id'], 'uid' => $item['uid']]);
-                       return [];
-               }
-
-               if ($parent['uri-id'] == $parent['parent-uri-id']) {
-                       return $parent;
-               }
-
-               $condition = [
-                       'uri-id'        => $parent['parent-uri-id'],
-                       'parent-uri-id' => $parent['parent-uri-id'],
-                       'uid'           => $parent['uid']
-               ];
-               $params          = ['order' => ['id' => false]];
-               $toplevel_parent = Post::selectFirst($fields, $condition, $params);
-
-               if (!$this->database->isResult($toplevel_parent) && $item['origin']) {
-                       $stored = Item::storeForUserByUriId($item['parent-uri-id'], $item['uid'], ['post-reason' => Item::PR_COMPLETION]);
-                       $this->logger->info('Stored parent item for user', ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid'], 'stored' => $stored]);
-                       $toplevel_parent = Post::selectFirst($fields, $condition, $params);
-               }
-
-               if (!$this->database->isResult($toplevel_parent)) {
-                       $this->logger->notice('item top level parent was not found - ignoring item', ['parent-uri-id' => $parent['parent-uri-id'], 'uid' => $parent['uid']]);
-                       return [];
-               }
-
-               return $toplevel_parent;
-       }
-
-       public function handleToplevelParent(array $item, array $toplevel_parent, bool $defined_permissions): array
-       {
-               $parent_id             = (int) $toplevel_parent['id'];
-               $item['parent-uri']    = $toplevel_parent['uri'];
-               $item['parent-uri-id'] = $toplevel_parent['uri-id'];
-               $item['deleted']       = $toplevel_parent['deleted'];
-               $item['wall']          = $toplevel_parent['wall'];
-
-               // Reshares have to keep their permissions to allow groups to work
-               if (!$defined_permissions && (!$item['origin'] || ($item['verb'] != Activity::ANNOUNCE))) {
-                       // Don't store the permissions on pure AP posts
-                       $store_permissions = ($item['network'] != Protocol::ACTIVITYPUB) || $item['origin'] || !empty($item['diaspora_signed_text']);
-                       $item['allow_cid'] = $store_permissions ? $toplevel_parent['allow_cid'] : '';
-                       $item['allow_gid'] = $store_permissions ? $toplevel_parent['allow_gid'] : '';
-                       $item['deny_cid']  = $store_permissions ? $toplevel_parent['deny_cid'] : '';
-                       $item['deny_gid']  = $store_permissions ? $toplevel_parent['deny_gid'] : '';
-               }
-
-               // Don't federate received participation messages
-               if ($item['verb'] != Activity::FOLLOW) {
-                       $item['wall'] = $toplevel_parent['wall'];
-               } else {
-                       $item['wall'] = false;
-                       // Participations are technical messages, so they are set to "seen" automatically
-                       $item['unseen'] = false;
-               }
-
-               /*
-                * If the parent is private, force privacy for the entire conversation
-                * This differs from the above settings as it subtly allows comments from
-                * email correspondents to be private even if the overall thread is not.
-                */
-               if (!$defined_permissions && $toplevel_parent['private']) {
-                       $item['private'] = $toplevel_parent['private'];
-               }
-
-               // If its a post that originated here then tag the thread as "mention"
-               if ($item['origin'] && $item['uid']) {
-                       $this->database->update('post-thread-user', ['mention' => true], ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
-                       $this->logger->info('tagged thread as mention', ['parent' => $parent_id, 'parent-uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]);
-               }
-
-               // Update the contact relations
-               Contact\Relation::store($toplevel_parent['author-id'], $item['author-id'], $item['created']);
-
-               return $item;
-       }
-
-       private function hasRestrictions(array $item, int $author_id, int $restrictions = null): bool
-       {
-               if (empty($restrictions) || ($author_id == $item['author-id'])) {
-                       return false;
-               }
-
-               // We only have to apply restrictions if the post originates from our server or is federated.
-               // Every other time we can trust the remote system.
-               if (!in_array($item['network'], Protocol::FEDERATED) && !$item['origin']) {
-                       return false;
-               }
-
-               if (($restrictions & Item::CANT_REPLY) && ($item['verb'] == Activity::POST)) {
-                       return true;
-               }
-
-               if (($restrictions & Item::CANT_ANNOUNCE) && ($item['verb'] == Activity::ANNOUNCE)) {
-                       return true;
-               }
-
-               if (($restrictions & Item::CANT_LIKE) && in_array($item['verb'], [Activity::LIKE, Activity::DISLIKE, Activity::ATTEND, Activity::ATTENDMAYBE, Activity::ATTENDNO])) {
-                       return true;
-               }
-
-               return false;
-       }
-
-       /**
-        * Get the gravity for the given item array
-        *
-        * @return int gravity
-        */
-       private function getGravity(array $item): int
-       {
-               if (isset($item['gravity'])) {
-                       return intval($item['gravity']);
-               } elseif ($item['parent-uri-id'] === $item['uri-id']) {
-                       return Item::GRAVITY_PARENT;
-               } elseif ($this->activity->match($item['verb'], Activity::POST)) {
-                       return Item::GRAVITY_COMMENT;
-               } elseif ($this->activity->match($item['verb'], Activity::FOLLOW)) {
-                       return Item::GRAVITY_ACTIVITY;
-               } elseif ($this->activity->match($item['verb'], Activity::ANNOUNCE)) {
-                       return Item::GRAVITY_ACTIVITY;
-               }
-
-               return Item::GRAVITY_UNKNOWN;   // Should not happen
-       }
-}