From: Art4 Date: Thu, 23 Jan 2025 08:56:07 +0000 (+0000) Subject: Merge branch 'develop' into introduce-phpmd X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=4c95605711a2fb90c738a18877a0620a567fff96;p=friendica.git Merge branch 'develop' into introduce-phpmd --- 4c95605711a2fb90c738a18877a0620a567fff96 diff --cc src/Model/APContact.php index bfb80686b4,a364344a51..9c20b5b283 --- a/src/Model/APContact.php +++ b/src/Model/APContact.php @@@ -164,11 -162,9 +162,11 @@@ class APContac DI::cache()->set($cachekey, System::callstack(20), Duration::FIVE_MINUTES); } + $local_owner = []; + if (DI::baseUrl()->isLocalUrl($url) && ($local_uid = User::getIdForURL($url))) { try { - $data = Transmitter::getProfile($local_uid); + $data = Transmitter::getProfile($local_uid); $local_owner = User::getOwnerDataById($local_uid); } catch(HTTPException\NotFoundException $e) { $data = null; @@@ -209,22 -205,13 +207,22 @@@ return $fetched_contact; } + return self::compactProfile($apcontact, $compacted, $url, $fetched_contact, $webfinger, $local_owner); + } + + /** + * @param array|bool $fetched_contact + * @param array|bool $local_owner + */ + private static function compactProfile(array $apcontact, array $compacted, string $url, $fetched_contact, bool $webfinger, $local_owner): array + { - $apcontact['url'] = $compacted['@id']; - $apcontact['uuid'] = JsonLD::fetchElement($compacted, 'diaspora:guid', '@value'); - $apcontact['type'] = str_replace('as:', '', JsonLD::fetchElement($compacted, '@type')); + $apcontact['url'] = $compacted['@id']; + $apcontact['uuid'] = JsonLD::fetchElement($compacted, 'diaspora:guid', '@value'); + $apcontact['type'] = str_replace('as:', '', JsonLD::fetchElement($compacted, '@type')); $apcontact['following'] = JsonLD::fetchElement($compacted, 'as:following', '@id'); $apcontact['followers'] = JsonLD::fetchElement($compacted, 'as:followers', '@id'); - $apcontact['inbox'] = (JsonLD::fetchElement($compacted, 'ldp:inbox', '@id') ?? ''); - $apcontact['outbox'] = JsonLD::fetchElement($compacted, 'as:outbox', '@id'); + $apcontact['inbox'] = (JsonLD::fetchElement($compacted, 'ldp:inbox', '@id') ?? ''); + $apcontact['outbox'] = JsonLD::fetchElement($compacted, 'as:outbox', '@id'); $apcontact['sharedinbox'] = ''; if (!empty($compacted['as:endpoints'])) { diff --cc src/Model/GServer.php index 4d7743f0db,90f68b7725..d78d9ecbcb --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@@ -815,31 -817,12 +817,31 @@@ class GServe } // Count the number of known contacts from this server + self::countNumberOfKnownContacts((int) $id, $serverdata); + + if (in_array($serverdata['network'], [Protocol::DFRN, Protocol::DIASPORA])) { + self::discoverRelay($url); + } + + if (!empty($systemactor)) { + $contact = Contact::getByURL($systemactor, true, ['gsid', 'baseurl', 'id', 'network', 'url', 'name']); - Logger::debug('Fetched system actor', ['url' => $url, 'gsid' => $id, 'contact' => $contact]); ++ DI::logger()->debug('Fetched system actor', ['url' => $url, 'gsid' => $id, 'contact' => $contact]); + } + + return $ret; + } + + /** + * Count the number of known contacts from this server + */ + private static function countNumberOfKnownContacts(int $id, array $serverdata): void + { if (!empty($id) && !in_array($serverdata['network'], [Protocol::PHANTOM, Protocol::FEED])) { $apcontacts = DBA::count('apcontact', ['gsid' => $id]); - $contacts = DBA::count('contact', ['uid' => 0, 'gsid' => $id, 'failed' => false]); - $max_users = max($apcontacts, $contacts); + $contacts = DBA::count('contact', ['uid' => 0, 'gsid' => $id, 'failed' => false]); + $max_users = max($apcontacts, $contacts); if ($max_users > $serverdata['registered-users']) { - Logger::info('Update registered users', ['id' => $id, 'url' => $serverdata['nurl'], 'registered-users' => $max_users]); + DI::logger()->info('Update registered users', ['id' => $id, 'url' => $serverdata['nurl'], 'registered-users' => $max_users]); self::update(['registered-users' => $max_users], ['id' => $id]); } diff --cc src/Model/Item.php index 6833597a7c,10fc41cc23..7d63188461 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@@ -917,11 -1027,52 +916,11 @@@ class Ite return 0; } - $parent_id = $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'] : ''; - } - + $parent_id = (int) $toplevel_parent['id']; + $item = self::handleToplevelParent($item, $toplevel_parent, $defined_permissions); $parent_origin = $toplevel_parent['origin']; - - // 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']) { - DBA::update('post-thread-user', ['mention' => true], ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]); - DI::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']); } else { - $parent_id = 0; + $parent_id = 0; $parent_origin = $item['origin']; if ($item['wall'] && empty($item['context'])) { @@@ -1191,13 -1342,8 +1190,13 @@@ Post\ThreadUser::insert($item['uri-id'], $item['uid'], $item); } - Logger::notice('created item', ['post-id' => $post_user_id, 'uid' => $item['uid'], 'network' => $item['network'], 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]); + DI::logger()->notice('created item', ['post-id' => $post_user_id, 'uid' => $item['uid'], 'network' => $item['network'], 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]); + return self::handleCreatedItem($orig_item, $post_user_id, $uid, $notify, $copy_permissions, $parent_origin, $priority, $notify_type, $inserted, $source); + } + + private static function handleCreatedItem(array $orig_item, int $post_user_id, int $uid, int $notify, bool $copy_permissions, $parent_origin, int $priority, string $notify_type, bool $inserted, $source): int + { $posted_item = Post::selectFirst(self::ITEM_FIELDLIST, ['post-user-id' => $post_user_id]); if (!DBA::isResult($posted_item)) { // On failure store the data into a spool file so that the "SpoolPost" worker can try again later. @@@ -1338,130 -1484,6 +1337,130 @@@ return $post_user_id; } + private static function validateItemData(array $item, ItemInserter $itemInserter): 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'] ?? self::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'] ?? '') ?: DI::baseUrl() . '/display/' . urlencode($item['guid']); + + $item['gravity'] = $itemInserter->getGravity($item); + + if ($item['gravity'] === self::GRAVITY_UNKNOWN) { - Logger::info('Unknown gravity for verb', ['verb' => $item['verb']]); ++ DI::logger()->info('Unknown gravity for verb', ['verb' => $item['verb']]); + } + + $default = [ - 'url' => $item['author-link'], 'name' => $item['author-name'], ++ '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'], ++ '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'] = self::getPostReason($item); + + return $item; + } + + private static 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']) { + DBA::update('post-thread-user', ['mention' => true], ['uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]); - Logger::info('tagged thread as mention', ['parent' => $parent_id, 'parent-uri-id' => $item['parent-uri-id'], 'uid' => $item['uid']]); ++ DI::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 static function hasRestrictions(array $item, int $author_id, int $restrictions = null): bool { if (empty($restrictions) || ($author_id == $item['author-id'])) { diff --cc src/Model/ItemInserter.php index cf824190ca,0000000000..0db7ea1d0a mode 100644,000000..100644 --- a/src/Model/ItemInserter.php +++ b/src/Model/ItemInserter.php @@@ -1,80 -1,0 +1,80 @@@ +itemContent = $itemContent; + $this->activity = $activity; + } + + 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); ++ $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; + } + + /** + * Get the gravity for the given item array + * + * @return int gravity + */ + public 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 + } +}