From 1e4e5b57e3f4512f0135e93c29c03a794aaacb3e Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Fri, 23 Feb 2024 16:56:41 -0500 Subject: [PATCH] Stop generating photo URLs with contact IDs in favor of guids - This prevents an enumeration attack against avatar pictures - Replace several DB calls to `contact` table with `account-view` or `account-user-view` - Remove unused parameter photo_size from Directory::formatEntry --- mod/message.php | 14 +-- src/Content/GroupManager.php | 24 ++-- src/Content/Item.php | 21 ++-- src/Content/Nav.php | 6 +- src/Content/Text/BBCode.php | 18 +-- src/Content/Widget/ContactBlock.php | 13 +- src/Content/Widget/VCard.php | 46 +++---- src/Factory/Api/Mastodon/Account.php | 2 +- src/Factory/Api/Twitter/User.php | 10 +- src/Model/Contact.php | 78 +++++------- src/Model/Profile.php | 8 +- src/Module/Contact/Advanced.php | 20 +-- src/Module/Contact/Contacts.php | 12 +- src/Module/Contact/Conversations.php | 18 +-- src/Module/Contact/Follow.php | 30 ++--- src/Module/Contact/Media.php | 10 +- src/Module/Contact/Profile.php | 114 +++++++++--------- src/Module/Directory.php | 3 +- src/Module/Photo.php | 1 + src/Module/Search/Acl.php | 40 +++--- .../Notifications/Factory/Introduction.php | 3 +- src/Network/Probe.php | 2 +- src/Object/Api/Mastodon/Account.php | 8 +- src/Object/Api/Twitter/User.php | 36 +++--- src/Protocol/ActivityPub/Transmitter.php | 28 +++-- static/routes.config.php | 1 + view/theme/frio/theme.php | 16 +-- 27 files changed, 286 insertions(+), 296 deletions(-) diff --git a/mod/message.php b/mod/message.php index 369d3545ba..168b34b788 100644 --- a/mod/message.php +++ b/mod/message.php @@ -308,16 +308,15 @@ function message_content(App $a) $body_e = BBCode::convertForUriId($message['uri-id'], $message['body']); $to_name_e = $message['name']; - $contact = Contact::getByURL($message['from-url'], false, ['thumb', 'addr', 'id', 'avatar', 'url']); - $from_photo = Contact::getThumb($contact); + $account = Contact::selectFirstAccount(['thumb', 'addr', 'id', 'avatar', 'url', 'guid', 'updated'], ['url' => $message['from-url']]); $mails[] = [ 'id' => $message['id'], 'from_name' => $from_name_e, 'from_url' => $from_url, - 'from_addr' => $contact['addr'] ?? $from_url, + 'from_addr' => $account['addr'] ?? $from_url, 'sparkle' => $sparkle, - 'from_photo' => $from_photo, + 'from_photo' => Contact::getThumb($account), 'subject' => $subject_e, 'body' => $body_e, 'delete' => DI::l10n()->t('Delete message'), @@ -439,16 +438,15 @@ function render_messages(array $msg, string $t): string continue; } - $contact = Contact::getByURL($rr['url'], false, ['thumb', 'addr', 'id', 'avatar', 'url']); - $from_photo = Contact::getThumb($contact); + $account = Contact::selectFirstAccount(['thumb', 'addr', 'id', 'avatar', 'url', 'guid', 'updated'], ['url' => $rr['url']]); $rslt .= Renderer::replaceMacros($tpl, [ '$id' => $rr['id'], '$from_name' => $participants, '$from_url' => Contact::magicLink($rr['url']), - '$from_addr' => $contact['addr'] ?? '', + '$from_addr' => $account['addr'] ?? '', '$sparkle' => ' sparkle', - '$from_photo' => $from_photo, + '$from_photo' => Contact::getThumb($account), '$subject' => $rr['title'], '$delete' => DI::l10n()->t('Delete conversation'), '$body' => $body_e, diff --git a/src/Content/GroupManager.php b/src/Content/GroupManager.php index 2bddf0011d..4a0a682fcb 100644 --- a/src/Content/GroupManager.php +++ b/src/Content/GroupManager.php @@ -78,23 +78,25 @@ class GroupManager $groupList = []; - $fields = ['id', 'url', 'alias', 'name', 'micro', 'thumb', 'avatar', 'network', 'uid']; - $contacts = DBA::select('account-user-view', $fields, $condition, $params); - if (!$contacts) { + $fields = ['id', 'url', 'alias', 'name', 'micro', 'thumb', 'avatar', 'network', 'uid', 'guid', 'updated']; + $accounts = DBA::select('account-user-view', $fields, $condition, $params); + if (!$accounts) { return $groupList; } - while ($contact = DBA::fetch($contacts)) { + while ($account = DBA::fetch($accounts)) { $groupList[] = [ - 'url' => $contact['url'], - 'alias' => $contact['alias'], - 'name' => $contact['name'], - 'id' => $contact['id'], - 'micro' => $contact['micro'], - 'thumb' => $contact['thumb'], + 'url' => $account['url'], + 'alias' => $account['alias'], + 'name' => $account['name'], + 'id' => $account['id'], + 'micro' => $account['micro'], + 'thumb' => $account['thumb'], + 'guid' => $account['guid'], + 'updated' => $account['updated'], ]; } - DBA::close($contacts); + DBA::close($accounts); return($groupList); } diff --git a/src/Content/Item.php b/src/Content/Item.php index c7438d2593..3439f793ff 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -590,18 +590,18 @@ class Item public function getAuthorAvatar(array $item): string { if (in_array($item['network'], [Protocol::FEED, Protocol::MAIL])) { - $author_avatar = $item['contact-id']; + $author_id = $item['contact-id']; $author_updated = ''; $author_thumb = $item['contact-avatar']; } else { - $author_avatar = $item['author-id']; + $author_id = $item['author-id']; $author_updated = $item['author-updated']; $author_thumb = $item['author-avatar']; } - if (empty($author_thumb) || Photo::isPhotoURI($author_thumb)) { - $author_thumb = Contact::getAvatarUrlForId($author_avatar, Proxy::SIZE_THUMB, $author_updated); + $author = Contact::selectFirstAccount(['guid', 'updated'], ['id' => $author_id]); + $author_thumb = Contact::getAvatarUrlForId($author['guid'], $author['updated'] ?? $author_updated, Proxy::SIZE_THUMB); } return $author_thumb; @@ -610,17 +610,18 @@ class Item public function getOwnerAvatar(array $item): string { if (in_array($item['network'], [Protocol::FEED, Protocol::MAIL])) { - $owner_avatar = $item['contact-id']; + $owner_id = $item['contact-id']; $owner_updated = ''; $owner_thumb = $item['contact-avatar']; } else { - $owner_avatar = $item['owner-id']; - $owner_updated = $item['owner-updated']; - $owner_thumb = $item['owner-avatar']; + $owner_id = $item['owner-id']; + $owner_updated = $item['owner-updated']; + $owner_thumb = $item['owner-avatar']; } if (empty($owner_thumb) || Photo::isPhotoURI($owner_thumb)) { - $owner_thumb = Contact::getAvatarUrlForId($owner_avatar, Proxy::SIZE_THUMB, $owner_updated); + $owner = Contact::selectFirstAccount(['guid', 'updated'], ['id' => $owner_id]); + $owner_thumb = Contact::getAvatarUrlForId($owner['guid'], $owner['updated'] ?? $owner_updated, Proxy::SIZE_THUMB); } return $owner_thumb; @@ -1078,7 +1079,7 @@ class Item $to_author = DBA::selectFirst('account-view', ['ap-followers'], ['id' => $to['author-id']]); $parent = Post::selectFirstPost(['author-id'], ['uri-id' => $parentUriId]); $parent_author = DBA::selectFirst('account-view', ['ap-followers'], ['id' => $parent['author-id']]); - + $followers = ''; foreach (array_column(Tag::getByURIId($parentUriId, [Tag::TO, Tag::CC, Tag::BCC]), 'url') as $url) { if ($url == $parent_author['ap-followers']) { diff --git a/src/Content/Nav.php b/src/Content/Nav.php index a8f568630f..ba67ff2552 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -234,10 +234,10 @@ class Nav $nav['usermenu'][] = ['notes/', $this->l10n->t('Personal notes'), '', $this->l10n->t('Your personal notes')]; // user info - $contact = $this->database->selectFirst('contact', ['id', 'url', 'avatar', 'micro', 'name', 'nick', 'baseurl', 'updated'], ['uid' => $this->session->getLocalUserId(), 'self' => true]); + $account = Contact::selectFirstAccountUser(['id', 'url', 'guid', 'avatar', 'micro', 'name', 'nick', 'baseurl', 'updated'], ['uid' => $this->session->getLocalUserId(), 'self' => true]); $userinfo = [ - 'icon' => Contact::getMicro($contact), - 'name' => $contact['name'], + 'icon' => Contact::getMicro($account), + 'name' => $account['name'], ]; } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 877e3e2e55..05a2164969 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -875,23 +875,23 @@ class BBCode function ($match) use ($callback, $uriid) { $attributes = self::extractShareAttributes($match[2]); - $author_contact = Contact::getByURL($attributes['profile'], false, ['id', 'url', 'addr', 'name', 'micro']); - $author_contact['url'] = ($author_contact['url'] ?? $attributes['profile']); - $author_contact['addr'] = ($author_contact['addr'] ?? ''); + $author_account = Contact::selectFirstAccount(['id', 'url', 'addr', 'name', 'micro', 'guid', 'updated'], ['url' => $attributes['profile']]); + $author_account['url'] = ($author_account['url'] ?? $attributes['profile']); + $author_account['addr'] = ($author_account['addr'] ?? ''); - $attributes['author'] = ($author_contact['name'] ?? '') ?: $attributes['author']; - $attributes['avatar'] = ($author_contact['micro'] ?? '') ?: $attributes['avatar']; - $attributes['profile'] = ($author_contact['url'] ?? '') ?: $attributes['profile']; + $attributes['author'] = ($author_account['name'] ?? '') ?: $attributes['author']; + $attributes['avatar'] = ($author_account['micro'] ?? '') ?: $attributes['avatar']; + $attributes['profile'] = ($author_account['url'] ?? '') ?: $attributes['profile']; - if (!empty($author_contact['id'])) { - $attributes['avatar'] = Contact::getAvatarUrlForId($author_contact['id'], Proxy::SIZE_THUMB); + if (!empty($author_account['id'])) { + $attributes['avatar'] = Contact::getAvatarUrlForId($author_account['guid'], $author_account['updated'], Proxy::SIZE_THUMB); } elseif ($attributes['avatar']) { $attributes['avatar'] = self::proxyUrl($attributes['avatar'], self::INTERNAL, $uriid, Proxy::SIZE_THUMB); } $content = preg_replace(Strings::autoLinkRegEx(), '$1', $match[3]); - return $match[1] . $callback($attributes, $author_contact, $content, trim($match[1]) != ''); + return $match[1] . $callback($attributes, $author_account, $content, trim($match[1]) != ''); }, $text ); diff --git a/src/Content/Widget/ContactBlock.php b/src/Content/Widget/ContactBlock.php index 4b7d8d8ae8..c7d1f01ae4 100644 --- a/src/Content/Widget/ContactBlock.php +++ b/src/Content/Widget/ContactBlock.php @@ -104,19 +104,18 @@ class ContactBlock $contact_uriids = array_column($personal_contacts, 'uri-id'); if (!empty($contact_uriids)) { - $contacts_stmt = DBA::select('contact', ['id', 'uid', 'addr', 'url', 'alias', 'name', 'thumb', 'avatar', 'network'], ['uri-id' => $contact_uriids, 'uid' => $contact_uid]); + $accounts_stmt = DBA::select('account-user-view', ['id', 'uid', 'addr', 'url', 'alias', 'name', 'thumb', 'avatar', 'network', 'guid', 'updated'], ['uri-id' => $contact_uriids, 'uid' => $contact_uid]); - if (DBA::isResult($contacts_stmt)) { + if (DBA::isResult($accounts_stmt)) { $contacts_title = DI::l10n()->tt('%d Contact', '%d Contacts', $total); - $micropro = []; - while ($contact = DBA::fetch($contacts_stmt)) { - $contacts[] = $contact; - $micropro[] = HTML::micropro($contact, true, 'mpfriend'); + while ($account = DBA::fetch($accounts_stmt)) { + $contacts[] = $account; + $micropro[] = HTML::micropro($account, true, 'mpfriend'); } } - DBA::close($contacts_stmt); + DBA::close($accounts_stmt); } } diff --git a/src/Content/Widget/VCard.php b/src/Content/Widget/VCard.php index c784517abf..83b4c283a3 100644 --- a/src/Content/Widget/VCard.php +++ b/src/Content/Widget/VCard.php @@ -41,21 +41,21 @@ class VCard * Get HTML for vcard block * * @template widget/vcard.tpl - * @param array $contact + * @param array $account Account array (from account-* view) * @param bool $hide_mention * @return string */ - public static function getHTML(array $contact, bool $hide_mention = false): string + public static function getHTML(array $account, bool $hide_mention = false): string { - if (!isset($contact['network']) || !isset($contact['id'])) { - Logger::warning('Incomplete contact', ['contact' => $contact ?? []]); + if (!isset($account['network']) || !isset($account['id'])) { + Logger::warning('Incomplete contact', ['contact' => $account ?? []]); } - $contact_url = Contact::getProfileLink($contact); + $contact_url = Contact::getProfileLink($account); - if ($contact['network'] != '') { - $network_link = Strings::formatNetworkName($contact['network'], $contact_url); - $network_avatar = ContactSelector::networkToIcon($contact['network'], $contact_url); + if ($account['network'] != '') { + $network_link = Strings::formatNetworkName($account['network'], $contact_url); + $network_avatar = ContactSelector::networkToIcon($account['network'], $contact_url); } else { $network_link = ''; $network_avatar = ''; @@ -68,15 +68,15 @@ class VCard $mention_link = ''; $showgroup_link = ''; - $photo = Contact::getPhoto($contact); + $photo = Contact::getPhoto($account); if (DI::userSession()->getLocalUserId()) { - if ($contact['uid']) { - $id = $contact['id']; - $rel = $contact['rel']; - $pending = $contact['pending']; + if ($account['uid']) { + $id = $account['id']; + $rel = $account['rel']; + $pending = $account['pending']; } else { - $pcontact = Contact::selectFirst([], ['uid' => DI::userSession()->getLocalUserId(), 'uri-id' => $contact['uri-id'], 'deleted' => false]); + $pcontact = Contact::selectFirst([], ['uid' => DI::userSession()->getLocalUserId(), 'uri-id' => $account['uri-id'], 'deleted' => false]); $id = $pcontact['id'] ?? 0; $rel = $pcontact['rel'] ?? Contact::NOTHING; @@ -87,7 +87,7 @@ class VCard } } - if (empty($contact['self']) && Protocol::supportsFollow($contact['network'])) { + if (empty($account['self']) && Protocol::supportsFollow($account['network'])) { if (in_array($rel, [Contact::SHARING, Contact::FRIEND])) { $unfollow_link = 'contact/unfollow?url=' . urlencode($contact_url) . '&auto=1'; } elseif (!$pending) { @@ -95,34 +95,34 @@ class VCard } } - if (in_array($rel, [Contact::FOLLOWER, Contact::FRIEND]) && Contact::canReceivePrivateMessages($contact)) { + if (in_array($rel, [Contact::FOLLOWER, Contact::FRIEND]) && Contact::canReceivePrivateMessages($account)) { $wallmessage_link = 'message/new/' . $id; } - if ($contact['contact-type'] == Contact::TYPE_COMMUNITY) { + if ($account['contact-type'] == Contact::TYPE_COMMUNITY) { if (!$hide_mention) { $mention_label = DI::l10n()->t('Post to group'); - $mention_link = 'compose/0?body=!' . $contact['addr']; + $mention_link = 'compose/0?body=!' . $account['addr']; } $showgroup_link = 'network/group/' . $id; } elseif (!$hide_mention) { $mention_label = DI::l10n()->t('Mention'); - $mention_link = 'compose/0?body=@' . $contact['addr']; + $mention_link = 'compose/0?body=@' . $account['addr']; } } return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/vcard.tpl'), [ - '$contact' => $contact, + '$contact' => $account, '$photo' => $photo, - '$url' => Contact::magicLinkByContact($contact, $contact_url), - '$about' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'] ?? ''), + '$url' => Contact::magicLinkByContact($account, $contact_url), + '$about' => BBCode::convertForUriId($account['uri-id'] ?? 0, $account['about'] ?? ''), '$xmpp' => DI::l10n()->t('XMPP:'), '$matrix' => DI::l10n()->t('Matrix:'), '$location' => DI::l10n()->t('Location:'), '$network_link' => $network_link, '$network_avatar' => $network_avatar, '$network' => DI::l10n()->t('Network:'), - '$account_type' => Contact::getAccountType($contact['contact-type']), + '$account_type' => Contact::getAccountType($account['contact-type']), '$follow' => DI::l10n()->t('Follow'), '$follow_link' => $follow_link, '$unfollow' => DI::l10n()->t('Unfollow'), diff --git a/src/Factory/Api/Mastodon/Account.php b/src/Factory/Api/Mastodon/Account.php index f7b48599b5..16a7666b8a 100644 --- a/src/Factory/Api/Mastodon/Account.php +++ b/src/Factory/Api/Mastodon/Account.php @@ -81,7 +81,7 @@ class Account extends BaseFactory */ public function createFromUriId(int $contactUriId, int $uid = 0): \Friendica\Object\Api\Mastodon\Account { - $account = DBA::selectFirst('account-user-view', [], ['uri-id' => $contactUriId, 'uid' => [0, $uid]], ['order' => ['id' => true]]); + $account = Contact::selectFirstAccountUser([], ['uri-id' => $contactUriId, 'uid' => [0, $uid]], ['order' => ['id' => true]]); if (empty($account)) { throw new HTTPException\NotFoundException('Contact ' . $contactUriId . ' not found'); } diff --git a/src/Factory/Api/Twitter/User.php b/src/Factory/Api/Twitter/User.php index 8fb3193606..4d9a2b5310 100644 --- a/src/Factory/Api/Twitter/User.php +++ b/src/Factory/Api/Twitter/User.php @@ -56,27 +56,27 @@ class User extends BaseFactory { $cdata = Contact::getPublicAndUserContactID($contactId, $uid); if (!empty($cdata)) { - $publicContact = Contact::getById($cdata['public']); + $publicAccount = Contact::selectFirstAccount([], ['id' => $cdata['public']]); $userContact = Contact::getById($cdata['user']); } else { - $publicContact = Contact::getById($contactId); + $publicAccount = Contact::selectFirstAccount([], ['id' => $contactId]); $userContact = []; } - $apcontact = APContact::getByURL($publicContact['url'], false); + $apcontact = APContact::getByURL($publicAccount['url'], false); $status = null; if (!$skip_status) { $post = Post::selectFirstPost(['uri-id'], - ['author-id' => $publicContact['id'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_PARENT], 'private' => [Item::PUBLIC, Item::UNLISTED]], + ['author-id' => $publicAccount['id'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_PARENT], 'private' => [Item::PUBLIC, Item::UNLISTED]], ['order' => ['uri-id' => true]]); if (!empty($post['uri-id'])) { $status = $this->status->createFromUriId($post['uri-id'], $uid)->toArray(); } } - return new \Friendica\Object\Api\Twitter\User($publicContact, $apcontact, $userContact, $status, $include_user_entities); + return new \Friendica\Object\Api\Twitter\User($publicAccount, $apcontact, $userContact, $status, $include_user_entities); } /** diff --git a/src/Model/Contact.php b/src/Model/Contact.php index e673822ef2..2b59e30375 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1818,72 +1818,72 @@ class Contact /** * Return the photo path for a given contact array in the given size * - * @param array $contact contact array + * @param array $account Account array (from account-* view) * @param string $size Size of the avatar picture * @param bool $no_update Don't perform an update if no cached avatar was found * @return string photo path */ - private static function getAvatarPath(array $contact, string $size, bool $no_update = false): string + private static function getAvatarPath(array $account, string $size, bool $no_update = false): string { - $contact = self::checkAvatarCacheByArray($contact, $no_update); + $account = self::checkAvatarCacheByArray($account, $no_update); if (DI::config()->get('system', 'avatar_cache')) { switch ($size) { case Proxy::SIZE_MICRO: - if (!empty($contact['micro']) && !Photo::isPhotoURI($contact['micro'])) { - return $contact['micro']; + if (!empty($account['micro']) && !Photo::isPhotoURI($account['micro'])) { + return $account['micro']; } break; case Proxy::SIZE_THUMB: - if (!empty($contact['thumb']) && !Photo::isPhotoURI($contact['thumb'])) { - return $contact['thumb']; + if (!empty($account['thumb']) && !Photo::isPhotoURI($account['thumb'])) { + return $account['thumb']; } break; case Proxy::SIZE_SMALL: - if (!empty($contact['photo']) && !Photo::isPhotoURI($contact['photo'])) { - return $contact['photo']; + if (!empty($account['photo']) && !Photo::isPhotoURI($account['photo'])) { + return $account['photo']; } break; } } - return self::getAvatarUrlForId($contact['id'] ?? 0, $size, $contact['updated'] ?? ''); + return self::getAvatarUrlForId($account['guid'], $account['updated'], $size); } /** * Return the photo path for a given contact array * - * @param array $contact Contact array + * @param array $account Account array (from account-* view) * @param bool $no_update Don't perform an update if no cached avatar was found * @return string photo path */ - public static function getPhoto(array $contact, bool $no_update = false): string + public static function getPhoto(array $account, bool $no_update = false): string { - return self::getAvatarPath($contact, Proxy::SIZE_SMALL, $no_update); + return self::getAvatarPath($account, Proxy::SIZE_SMALL, $no_update); } /** * Return the photo path (thumb size) for a given contact array * - * @param array $contact Contact array + * @param array $account Account array (from account-* view) * @param bool $no_update Don't perform an update if no cached avatar was found * @return string photo path */ - public static function getThumb(array $contact, bool $no_update = false): string + public static function getThumb(array $account, bool $no_update = false): string { - return self::getAvatarPath($contact, Proxy::SIZE_THUMB, $no_update); + return self::getAvatarPath($account, Proxy::SIZE_THUMB, $no_update); } /** * Return the photo path (micro size) for a given contact array * - * @param array $contact Contact array + * @param array $account Account array (from account-* view) * @param bool $no_update Don't perform an update if no cached avatar was found * @return string photo path */ - public static function getMicro(array $contact, bool $no_update = false): string + public static function getMicro(array $account, bool $no_update = false): string { - return self::getAvatarPath($contact, Proxy::SIZE_MICRO, $no_update); + return self::getAvatarPath($account, Proxy::SIZE_MICRO, $no_update); } /** @@ -2148,24 +2148,16 @@ class Contact } /** - * Get avatar link for given contact id + * Get avatar link for given contact guid * - * @param integer $cid contact id - * @param string $size One of the Proxy::SIZE_* constants + * @param string $guid Contact guid (from account-* views) * @param string $updated Contact update date + * @param ?string $size One of the Proxy::SIZE_* constants or empty for original size * @param bool $static If "true" a parameter is added to convert the avatar to a static one * @return string avatar link */ - public static function getAvatarUrlForId(int $cid, string $size = '', string $updated = '', string $guid = '', bool $static = false): string + public static function getAvatarUrlForId(string $guid, string $updated, string $size = null, bool $static = false): string { - // We have to fetch the "updated" variable when it wasn't provided - // The parameter can be provided to improve performance - if (empty($updated)) { - $account = DBA::selectFirst('account-user-view', ['updated', 'guid'], ['id' => $cid]); - $updated = $account['updated'] ?? ''; - $guid = $account['guid'] ?? ''; - } - $guid = urlencode($guid); $url = DI::baseUrl() . '/photo/contact/'; @@ -2194,7 +2186,7 @@ class Contact $query_params['static'] = true; } - return $url . ($guid ?: $cid) . (!empty($query_params) ? '?' . http_build_query($query_params) : ''); + return $url . $guid . (!empty($query_params) ? '?' . http_build_query($query_params) : ''); } /** @@ -2211,29 +2203,21 @@ class Contact "`nurl` = ? AND ((`uid` = ? AND `network` IN (?, ?)) OR `uid` = ?)", Strings::normaliseLink($url), $uid, Protocol::FEED, Protocol::MAIL, 0 ]; - $contact = self::selectFirst(['id', 'updated'], $condition, ['order' => ['uid' => true]]); - return self::getAvatarUrlForId($contact['id'] ?? 0, $size, $contact['updated'] ?? ''); + $account = self::selectFirstAccountUser(['id', 'guid', 'updated'], $condition, ['order' => ['uid' => true]]); + return self::getAvatarUrlForId($account['guid'] ?? '', $account['updated'] ?? DBA::NULL_DATETIME, $size); } /** - * Get header link for given contact id + * Get header link for given contact guid * - * @param integer $cid contact id - * @param string $size One of the Proxy::SIZE_* constants + * @param string $guid Contact guid (from account-* views) * @param string $updated Contact update date + * @param ?string $size One of the Proxy::SIZE_* constants or empty for original size * @param bool $static If "true" a parameter is added to convert the header to a static one * @return string header link */ - public static function getHeaderUrlForId(int $cid, string $size = '', string $updated = '', string $guid = '', bool $static = false): string + public static function getHeaderUrlForId(string $guid, string $updated, string $size = null, bool $static = false): string { - // We have to fetch the "updated" variable when it wasn't provided - // The parameter can be provided to improve performance - if (empty($updated) || empty($guid)) { - $account = DBA::selectFirst('account-user-view', ['updated', 'guid'], ['id' => $cid]); - $updated = $account['updated'] ?? ''; - $guid = $account['guid'] ?? ''; - } - $guid = urlencode($guid); $url = DI::baseUrl() . '/photo/header/'; @@ -2263,7 +2247,7 @@ class Contact $query_params['static'] = true; } - return $url . ($guid ?: $cid) . (!empty($query_params) ? '?' . http_build_query($query_params) : ''); + return $url . $guid . (!empty($query_params) ? '?' . http_build_query($query_params) : ''); } /** diff --git a/src/Model/Profile.php b/src/Model/Profile.php index 44835bda9a..a80f7ddb17 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -308,12 +308,12 @@ class Profile $profile_url = $profile['url']; - $contact = Contact::selectFirst(['id'], ['uri-id' => $profile['uri-id'], 'uid' => 0]); - if (!$contact) { + $account = Contact::selectFirstAccount(['id', 'guid', 'updated'], ['uri-id' => $profile['uri-id']]); + if (!$account) { return $o; } - $cid = $contact['id']; + $cid = $account['id']; $follow_link = null; $unfollow_link = null; @@ -449,7 +449,7 @@ class Profile $p['address'] = BBCode::convertForUriId($profile['uri-id'] ?? 0, $p['address']); } - $p['photo'] = Contact::getAvatarUrlForId($cid, Proxy::SIZE_SMALL); + $p['photo'] = Contact::getAvatarUrlForId($account['guid'], $account['updated'], Proxy::SIZE_SMALL); $p['url'] = Contact::magicLinkById($cid, $profile['url']); diff --git a/src/Module/Contact/Advanced.php b/src/Module/Contact/Advanced.php index af5cd4224c..abf9176b9f 100644 --- a/src/Module/Contact/Advanced.php +++ b/src/Module/Contact/Advanced.php @@ -104,37 +104,37 @@ class Advanced extends BaseModule { $cid = $this->parameters['id']; - $contact = Model\Contact::selectFirst([], ['id' => $cid, 'uid' => DI::userSession()->getLocalUserId()]); - if (empty($contact)) { + $account = Model\Contact::selectFirstAccountUser([], ['id' => $cid, 'uid' => DI::userSession()->getLocalUserId()]); + if (empty($account)) { throw new BadRequestException($this->t('Contact not found.')); } - $this->page['aside'] = Widget\VCard::getHTML($contact); + $this->page['aside'] = Widget\VCard::getHTML($account); $returnaddr = "contact/$cid"; // This data is fetched automatically for most networks. // Editing does only makes sense for mail and feed contacts. - if (!in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) { + if (!in_array($account['network'], [Protocol::FEED, Protocol::MAIL])) { $readonly = 'readonly'; } else { $readonly = ''; } - $tab_str = Contact::getTabsHTML($contact, Contact::TAB_ADVANCED); + $tab_str = Contact::getTabsHTML($account, Contact::TAB_ADVANCED); $tpl = Renderer::getMarkupTemplate('contact/advanced.tpl'); return Renderer::replaceMacros($tpl, [ '$tab_str' => $tab_str, '$returnaddr' => $returnaddr, '$return' => $this->t('Return to contact editor'), - '$contact_id' => $contact['id'], + '$contact_id' => $account['id'], '$lbl_submit' => $this->t('Submit'), - '$name' => ['name', $this->t('Name'), $contact['name'], '', '', $readonly], - '$nick' => ['nick', $this->t('Account Nickname'), $contact['nick'], '', '', 'readonly'], - '$url' => ['url', $this->t('Account URL'), $contact['url'], '', '', 'readonly'], - 'poll' => ['poll', $this->t('Poll/Feed URL'), $contact['poll'], '', '', ($contact['network'] == Protocol::FEED) ? '' : 'readonly'], + '$name' => ['name', $this->t('Name'), $account['name'], '', '', $readonly], + '$nick' => ['nick', $this->t('Account Nickname'), $account['nick'], '', '', 'readonly'], + '$url' => ['url', $this->t('Account URL'), $account['url'], '', '', 'readonly'], + 'poll' => ['poll', $this->t('Poll/Feed URL'), $account['poll'], '', '', ($account['network'] == Protocol::FEED) ? '' : 'readonly'], 'photo' => ['photo', $this->t('New photo from this URL'), '', '', '', $readonly], ]); } diff --git a/src/Module/Contact/Contacts.php b/src/Module/Contact/Contacts.php index 11721c3753..a1ca888bdb 100644 --- a/src/Module/Contact/Contacts.php +++ b/src/Module/Contact/Contacts.php @@ -66,14 +66,14 @@ class Contacts extends BaseModule throw new HTTPException\BadRequestException($this->t('Invalid contact.')); } - $contact = Model\Contact::getById($cid, []); - if (empty($contact)) { + $account = Model\Contact::selectFirstAccount([], ['id' => $cid]); + if (empty($account)) { throw new HTTPException\NotFoundException($this->t('Contact not found.')); } $localContactId = Model\Contact::getPublicIdByUserId($this->userSession->getLocalUserId()); - $this->page['aside'] = Widget\VCard::getHTML($contact); + $this->page['aside'] = Widget\VCard::getHTML($account); $condition = [ 'blocked' => false, @@ -123,7 +123,7 @@ class Contacts extends BaseModule $title = $this->tt('Mutual friend (%s)', 'Mutual friends (%s)', $total); $desc = $this->t( 'These contacts both follow and are followed by %s.', - htmlentities($contact['name'], ENT_COMPAT, 'UTF-8') + htmlentities($account['name'], ENT_COMPAT, 'UTF-8') ); break; case 'common': @@ -131,7 +131,7 @@ class Contacts extends BaseModule $title = $this->tt('Common contact (%s)', 'Common contacts (%s)', $total); $desc = $this->t( 'Both %s and yourself have publicly interacted with these contacts (follow, comment or likes on public posts).', - htmlentities($contact['name'], ENT_COMPAT, 'UTF-8') + htmlentities($account['name'], ENT_COMPAT, 'UTF-8') ); break; default: @@ -139,7 +139,7 @@ class Contacts extends BaseModule $title = $this->tt('Contact (%s)', 'Contacts (%s)', $total); } - $o = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_CONTACTS); + $o = Module\Contact::getTabsHTML($account, Module\Contact::TAB_CONTACTS); $tabs = self::getContactFilterTabs('contact/' . $cid, $type, true); diff --git a/src/Module/Contact/Conversations.php b/src/Module/Contact/Conversations.php index 46ad6d293a..d16a0808ee 100644 --- a/src/Module/Contact/Conversations.php +++ b/src/Module/Contact/Conversations.php @@ -86,19 +86,19 @@ class Conversations extends BaseModule throw new NotFoundException($this->t('Contact not found.')); } - $contact = Model\Contact::getById($data['public']); - if (empty($contact)) { + $account = Model\Contact::selectFirstAccount([], ['id' => $data['public']]); + if (empty($account)) { throw new NotFoundException($this->t('Contact not found.')); } // Don't display contacts that are about to be deleted - if (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM) { + if (!empty($account['deleted']) || !empty($account['network']) && $account['network'] == Protocol::PHANTOM) { throw new NotFoundException($this->t('Contact not found.')); } - $localRelationship = $this->localRelationship->getForUserContact($this->userSession->getLocalUserId(), $contact['id']); + $localRelationship = $this->localRelationship->getForUserContact($this->userSession->getLocalUserId(), $account['id']); if ($localRelationship->rel === Model\Contact::SELF) { - $this->baseUrl->redirect('profile/' . $contact['nick']); + $this->baseUrl->redirect('profile/' . $account['nick']); } // Load necessary libraries for the status editor @@ -107,7 +107,7 @@ class Conversations extends BaseModule $this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css')); $this->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css')); - $this->page['aside'] .= Widget\VCard::getHTML($contact, true); + $this->page['aside'] .= Widget\VCard::getHTML($account, true); Nav::setSelected('contact'); @@ -115,12 +115,12 @@ class Conversations extends BaseModule 'lockstate' => ACL::getLockstateForUserId($this->userSession->getLocalUserId()) ? 'lock' : 'unlock', 'acl' => ACL::getFullSelectorHTML($this->page, $this->userSession->getLocalUserId(), true, []), 'bang' => '', - 'content' => ($contact['contact-type'] == ModelContact::TYPE_COMMUNITY ? '!' : '@') . ($contact['addr'] ?: $contact['url']), + 'content' => ($account['contact-type'] == ModelContact::TYPE_COMMUNITY ? '!' : '@') . ($account['addr'] ?: $account['url']), ]; $o = $this->conversation->statusEditor($options); - $o .= Contact::getTabsHTML($contact, Contact::TAB_CONVERSATIONS); - $o .= Model\Contact::getThreadsFromId($contact['id'], $this->userSession->getLocalUserId(), 0, 0, $request['last_created'] ?? ''); + $o .= Contact::getTabsHTML($account, Contact::TAB_CONVERSATIONS); + $o .= Model\Contact::getThreadsFromId($account['id'], $this->userSession->getLocalUserId(), 0, 0, $request['last_created'] ?? ''); return $o; } diff --git a/src/Module/Contact/Follow.php b/src/Module/Contact/Follow.php index 28a13da033..94dddc8fd6 100644 --- a/src/Module/Contact/Follow.php +++ b/src/Module/Contact/Follow.php @@ -116,23 +116,23 @@ class Follow extends BaseModule $submit = ''; } - $contact = Contact::getByURL($url, true); + $account = Contact::selectFirstAccount([], ['id' => Contact::getIdForURL($url, 0, true)]); // Possibly it is a mail contact - if (empty($contact)) { - $contact = Probe::uri($url, Protocol::MAIL, $uid); + if (empty($account)) { + $account = Probe::uri($url, Protocol::MAIL, $uid); } - if (empty($contact) || ($contact['network'] == Protocol::PHANTOM)) { + if (empty($account) || ($account['network'] == Protocol::PHANTOM)) { // Possibly it is a remote item and not an account $this->followRemoteItem($url); $this->sysMessages->addNotice($this->t('The network type couldn\'t be detected. Contact can\'t be added.')); $submit = ''; - $contact = ['url' => $url, 'network' => Protocol::PHANTOM, 'name' => $url, 'keywords' => '']; + $account = ['url' => $url, 'network' => Protocol::PHANTOM, 'name' => $url, 'keywords' => '']; } - $protocol = Contact::getProtocol($contact['url'], $contact['network']); + $protocol = Contact::getProtocol($account['url'], $account['network']); if (($protocol == Protocol::DIASPORA) && !$this->config->get('system', 'diaspora_enabled')) { $this->sysMessages->addNotice($this->t('Diaspora support isn\'t enabled. Contact can\'t be added.')); @@ -145,11 +145,11 @@ class Follow extends BaseModule } if ($protocol == Protocol::MAIL) { - $contact['url'] = $contact['addr']; + $account['url'] = $account['addr']; } if (!empty($request['auto'])) { - $this->process($contact['url']); + $this->process($account['url']); } $requestUrl = $this->baseUrl . '/contact/follow'; @@ -173,27 +173,27 @@ class Follow extends BaseModule '$cancel' => $this->t('Cancel'), '$action' => $requestUrl, - '$name' => $contact['name'], - '$url' => $contact['url'], - '$zrl' => Profile::zrl($contact['url']), + '$name' => $account['name'], + '$url' => $account['url'], + '$zrl' => Profile::zrl($account['url']), '$myaddr' => $myaddr, - '$keywords' => $contact['keywords'], + '$keywords' => $account['keywords'], - '$does_know_you' => ['knowyou', $this->t('%s knows you', $contact['name'])], + '$does_know_you' => ['knowyou', $this->t('%s knows you', $account['name'])], '$addnote_field' => ['dfrn-request-message', $this->t('Add a personal note:')], ]); $this->page['aside'] = ''; if (!in_array($protocol, [Protocol::PHANTOM, Protocol::MAIL])) { - $this->page['aside'] = VCard::getHTML($contact); + $this->page['aside'] = VCard::getHTML($account); $output .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), ['$title' => $this->t('Posts and Replies')] ); // Show last public posts - $output .= Contact::getPostsFromUrl($contact['url'], $this->session->getLocalUserId()); + $output .= Contact::getPostsFromUrl($account['url'], $this->session->getLocalUserId()); } return $output; diff --git a/src/Module/Contact/Media.php b/src/Module/Contact/Media.php index b8a8afa8e7..34dd52c367 100644 --- a/src/Module/Contact/Media.php +++ b/src/Module/Contact/Media.php @@ -56,16 +56,16 @@ class Media extends BaseModule { $cid = $this->parameters['id']; - $contact = Model\Contact::selectFirst([], ['id' => $cid]); - if (empty($contact)) { + $account = Model\Contact::selectFirstAccount([], ['id' => $cid]); + if (empty($account)) { throw new BadRequestException(DI::l10n()->t('Contact not found.')); } - DI::page()['aside'] = Widget\VCard::getHTML($contact); + DI::page()['aside'] = Widget\VCard::getHTML($account); - $o = Contact::getTabsHTML($contact, Contact::TAB_MEDIA); + $o = Contact::getTabsHTML($account, Contact::TAB_MEDIA); - $o .= ModelContact::getPostsFromUrl($contact['url'], $this->userSession->getLocalUserId(), true); + $o .= ModelContact::getPostsFromUrl($account['url'], $this->userSession->getLocalUserId(), true); return $o; } diff --git a/src/Module/Contact/Profile.php b/src/Module/Contact/Profile.php index 38260e9da7..5dc27f9f57 100644 --- a/src/Module/Contact/Profile.php +++ b/src/Module/Contact/Profile.php @@ -154,43 +154,43 @@ class Profile extends BaseModule throw new HTTPException\NotFoundException($this->t('Contact not found.')); } - $contact = Contact::getById($data['public']); - if (!$this->db->isResult($contact)) { + $account = Contact::selectFirstAccount([], ['id' => $data['public']]); + if (!$this->db->isResult($account)) { throw new HTTPException\NotFoundException($this->t('Contact not found.')); } // Don't display contacts that are about to be deleted - if ($this->db->isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) { + if ($this->db->isResult($account) && (!empty($account['deleted']) || !empty($account['network']) && $account['network'] == Protocol::PHANTOM)) { throw new HTTPException\NotFoundException($this->t('Contact not found.')); } - $localRelationship = $this->localRelationship->getForUserContact($this->session->getLocalUserId(), $contact['id']); + $localRelationship = $this->localRelationship->getForUserContact($this->session->getLocalUserId(), $account['id']); if ($localRelationship->rel === Contact::SELF) { - $this->baseUrl->redirect('profile/' . $contact['nick'] . '/profile'); + $this->baseUrl->redirect('profile/' . $account['nick'] . '/profile'); } if (isset($this->parameters['action'])) { - self::checkFormSecurityTokenRedirectOnError('contact/' . $contact['id'], 'contact_action', 't'); + self::checkFormSecurityTokenRedirectOnError('contact/' . $account['id'], 'contact_action', 't'); $cmd = $this->parameters['action']; if ($cmd === 'update' && $localRelationship->rel !== Contact::NOTHING) { - Module\Contact::updateContactFromPoll($contact['id']); + Module\Contact::updateContactFromPoll($account['id']); } if ($cmd === 'updateprofile') { - $this->updateContactFromProbe($contact['id']); + $this->updateContactFromProbe($account['id']); } if ($cmd === 'block') { if ($localRelationship->blocked) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), false); + Contact\User::setBlocked($account['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been unblocked'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), true); + Contact\User::setBlocked($account['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been blocked'); } @@ -201,12 +201,12 @@ class Profile extends BaseModule if ($cmd === 'ignore') { if ($localRelationship->ignored) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), false); + Contact\User::setIgnored($account['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been unignored'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), true); + Contact\User::setIgnored($account['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been ignored'); } @@ -217,12 +217,12 @@ class Profile extends BaseModule if ($cmd === 'collapse') { if ($localRelationship->collapsed) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), false); + Contact\User::setCollapsed($account['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been uncollapsed'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), true); + Contact\User::setCollapsed($account['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been collapsed'); } @@ -230,10 +230,10 @@ class Profile extends BaseModule $this->systemMessages->addInfo($message); } - $this->baseUrl->redirect('contact/' . $contact['id']); + $this->baseUrl->redirect('contact/' . $account['id']); } - $vcard_widget = Widget\VCard::getHTML($contact); + $vcard_widget = Widget\VCard::getHTML($account); $circles_widget = ''; if (!in_array($localRelationship->rel, [Contact::NOTHING, Contact::SELF])) { @@ -251,18 +251,18 @@ class Profile extends BaseModule ]); switch ($localRelationship->rel) { - case Contact::FRIEND: $relation_text = $this->t('You are mutual friends with %s', $contact['name']); break; - case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $contact['name']); break; - case Contact::SHARING: $relation_text = $this->t('%s is sharing with you', $contact['name']); break; + case Contact::FRIEND: $relation_text = $this->t('You are mutual friends with %s', $account['name']); break; + case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $account['name']); break; + case Contact::SHARING: $relation_text = $this->t('%s is sharing with you', $account['name']); break; default: $relation_text = ''; } - if (!Protocol::supportsFollow($contact['network'])) { + if (!Protocol::supportsFollow($account['network'])) { $relation_text = ''; } - $url = Contact::magicLinkByContact($contact); + $url = Contact::magicLinkByContact($account); if (strpos($url, 'contact/redir/') === 0) { $sparkle = ' class="sparkle" '; } else { @@ -272,34 +272,34 @@ class Profile extends BaseModule $insecure = $this->t('Private communications are not available for this contact.'); // @TODO: Figure out why gsid can be empty - if (empty($contact['gsid'])) { - $this->logger->notice('Empty gsid for contact', ['contact' => $contact]); + if (empty($account['gsid'])) { + $this->logger->notice('Empty gsid for contact', ['contact' => $account]); } $serverIgnored = - $contact['gsid'] && - $this->userGServer->isIgnoredByUser($this->session->getLocalUserId(), $contact['gsid']) ? + $account['gsid'] && + $this->userGServer->isIgnoredByUser($this->session->getLocalUserId(), $account['gsid']) ? $this->t('This contact is on a server you ignored.') : ''; - $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? $this->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A')); + $last_update = (($account['last-update'] <= DBA::NULL_DATETIME) ? $this->t('Never') : DateTimeFormat::local($account['last-update'], 'D, j M Y, g:i A')); - if ($contact['last-update'] > DBA::NULL_DATETIME) { - $last_update .= ' ' . ($contact['failed'] ? $this->t('(Update was not successful)') : $this->t('(Update was successful)')); + if ($account['last-update'] > DBA::NULL_DATETIME) { + $last_update .= ' ' . ($account['failed'] ? $this->t('(Update was not successful)') : $this->t('(Update was successful)')); } - $lblsuggest = (($contact['network'] === Protocol::DFRN) ? $this->t('Suggest friends') : ''); + $lblsuggest = (($account['network'] === Protocol::DFRN) ? $this->t('Suggest friends') : ''); - $poll_enabled = in_array($contact['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]); + $poll_enabled = in_array($account['network'], [Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]); - $nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['url'], $contact['protocol'], $contact['gsid'])); + $nettype = $this->t('Network type: %s', ContactSelector::networkToName($account['network'], $account['url'], $account['protocol'], $account['gsid'])); // tabs - $tab_str = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_PROFILE); + $tab_str = Module\Contact::getTabsHTML($account, Module\Contact::TAB_PROFILE); - $lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? $this->t('Communications lost with this contact!') : ''); + $lost_contact = (($account['archive'] && $account['term-date'] > DBA::NULL_DATETIME && $account['term-date'] < DateTimeFormat::utcNow()) ? $this->t('Communications lost with this contact!') : ''); $fetch_further_information = null; - if ($contact['network'] == Protocol::FEED) { + if ($account['network'] == Protocol::FEED) { $fetch_further_information = [ 'fetch_further_information', $this->t('Fetch further information for feeds'), @@ -314,20 +314,20 @@ class Profile extends BaseModule ]; } - $allow_remote_self = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER]) + $allow_remote_self = in_array($account['network'], [Protocol::ACTIVITYPUB, Protocol::FEED, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER]) && $this->config->get('system', 'allow_users_remote_self'); - if ($contact['network'] == Protocol::FEED) { + if ($account['network'] == Protocol::FEED) { $remote_self_options = [ Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'), Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting') ]; - } elseif ($contact['network'] == Protocol::ACTIVITYPUB) { + } elseif ($account['network'] == Protocol::ACTIVITYPUB) { $remote_self_options = [ Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'), Contact::MIRROR_NATIVE_RESHARE => $this->t('Native reshare') ]; - } elseif ($contact['network'] == Protocol::DFRN) { + } elseif ($account['network'] == Protocol::DFRN) { $remote_self_options = [ Contact::MIRROR_DEACTIVATED => $this->t('No mirroring'), Contact::MIRROR_OWN_POST => $this->t('Mirror as my own posting'), @@ -340,14 +340,14 @@ class Profile extends BaseModule ]; } - $channel_frequency = Contact\User::getChannelFrequency($contact['id'], $this->session->getLocalUserId()); + $channel_frequency = Contact\User::getChannelFrequency($account['id'], $this->session->getLocalUserId()); $poll_interval = null; - if ((($contact['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) { + if ((($account['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($account['network'] == Protocol::MAIL)) { $poll_interval = ContactSelector::pollInterval($localRelationship->priority, !$poll_enabled); } - $contact_actions = $this->getContactActions($contact, $localRelationship); + $contact_actions = $this->getContactActions($account, $localRelationship); if ($localRelationship->rel !== Contact::NOTHING) { $lbl_info1 = $this->t('Contact Information / Notes'); @@ -364,11 +364,11 @@ class Profile extends BaseModule '$submit' => $this->t('Submit'), '$lbl_info1' => $lbl_info1, '$lbl_info2' => $this->t('Their personal note'), - '$reason' => trim($contact['reason'] ?? ''), + '$reason' => trim($account['reason'] ?? ''), '$infedit' => $this->t('Edit contact notes'), - '$common_link' => 'contact/' . $contact['id'] . '/contacts/common', + '$common_link' => 'contact/' . $account['id'] . '/contacts/common', '$relation_text' => $relation_text, - '$visit' => $this->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']), + '$visit' => $this->t('Visit %s\'s profile [%s]', $account['name'], $account['url']), '$blockunblock' => $this->t('Block/Unblock contact'), '$ignorecont' => $this->t('Ignore contact'), '$lblrecent' => $this->t('View conversations'), @@ -381,13 +381,13 @@ class Profile extends BaseModule '$updpub' => $this->t('Update public posts'), '$last_update' => $last_update, '$udnow' => $this->t('Update now'), - '$contact_id' => $contact['id'], + '$contact_id' => $account['id'], '$pending' => $localRelationship->pending ? $this->t('Awaiting connection acknowledge') : '', '$blocked' => $localRelationship->blocked ? $this->t('Currently blocked') : '', '$ignored' => $localRelationship->ignored ? $this->t('Currently ignored') : '', '$collapsed' => $localRelationship->collapsed ? $this->t('Currently collapsed') : '', - '$archived' => ($contact['archive'] ? $this->t('Currently archived') : ''), - '$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure), + '$archived' => ($account['archive'] ? $this->t('Currently archived') : ''), + '$insecure' => (in_array($account['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure), '$serverIgnored' => $serverIgnored, '$manageServers' => $this->t('Manage remote servers'), '$cinfo' => ['info', '', $localRelationship->info, ''], @@ -395,22 +395,22 @@ class Profile extends BaseModule '$notify_new_posts' => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')], '$fetch_further_information' => $fetch_further_information, '$ffi_keyword_denylist' => ['ffi_keyword_denylist', $this->t('Keyword Deny List'), $localRelationship->ffiKeywordDenylist, $this->t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')], - '$photo' => Contact::getPhoto($contact), - '$name' => $contact['name'], + '$photo' => Contact::getPhoto($account), + '$name' => $account['name'], '$sparkle' => $sparkle, '$url' => $url, '$profileurllabel' => $this->t('Profile URL'), - '$profileurl' => $contact['url'], - '$account_type' => Contact::getAccountType($contact['contact-type']), - '$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']), + '$profileurl' => $account['url'], + '$account_type' => Contact::getAccountType($account['contact-type']), + '$location' => BBCode::convertForUriId($account['uri-id'] ?? 0, $account['location']), '$location_label' => $this->t('Location:'), - '$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']), + '$xmpp' => BBCode::convertForUriId($account['uri-id'] ?? 0, $account['xmpp']), '$xmpp_label' => $this->t('XMPP:'), - '$matrix' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['matrix']), + '$matrix' => BBCode::convertForUriId($account['uri-id'] ?? 0, $account['matrix']), '$matrix_label' => $this->t('Matrix:'), - '$about' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'], BBCode::EXTERNAL), + '$about' => BBCode::convertForUriId($account['uri-id'] ?? 0, $account['about'], BBCode::EXTERNAL), '$about_label' => $this->t('About:'), - '$keywords' => $contact['keywords'], + '$keywords' => $account['keywords'], '$keywords_label' => $this->t('Tags:'), '$contact_action_button' => $this->t('Actions'), '$contact_actions' => $contact_actions, @@ -434,7 +434,7 @@ class Profile extends BaseModule '$frequency_never' => ['channel_frequency', $this->t('Never display posts'), Contact\User::FREQUENCY_NEVER, $this->t('Posts from this contact will never be displayed in any channel'), $channel_frequency == Contact\User::FREQUENCY_NEVER], ]); - $arr = ['contact' => $contact, 'output' => $o]; + $arr = ['contact' => $account, 'output' => $o]; Hook::callAll('contact_edit', $arr); diff --git a/src/Module/Directory.php b/src/Module/Directory.php index 9d7370df51..308167e824 100644 --- a/src/Module/Directory.php +++ b/src/Module/Directory.php @@ -105,13 +105,12 @@ class Directory extends BaseModule * array for displaying directory entries. * * @param array $contact The directory entry from the database. - * @param string $photo_size Avatar size (thumb, photo or micro). * * @return array * * @throws \Exception */ - public static function formatEntry(array $contact, string $photo_size = 'photo'): array + public static function formatEntry(array $contact): array { $itemurl = (($contact['addr'] != "") ? $contact['addr'] : $contact['url']); diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 6bf81ac7cb..abefd8a9d6 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -100,6 +100,7 @@ class Photo extends BaseApi $id = $account['id']; } + // Contact Id Fallback, to remove after version 2024.03 if (isset($this->parameters['contact_id'])) { $id = intval($this->parameters['contact_id']); } diff --git a/src/Module/Search/Acl.php b/src/Module/Search/Acl.php index d22baeaa10..1dc1030766 100644 --- a/src/Module/Search/Acl.php +++ b/src/Module/Search/Acl.php @@ -95,7 +95,7 @@ class Acl extends BaseModule $contacts = []; foreach ($result as $contact) { $contacts[] = [ - 'photo' => Contact::getMicro($contact, true), + 'photo' => $contact['micro'], 'name' => htmlspecialchars($contact['name']), 'nick' => $contact['addr'] ?: $contact['url'], 'network' => $contact['network'], @@ -219,17 +219,17 @@ class Acl extends BaseModule } $groups = []; - foreach ($contacts as $contact) { + foreach ($contacts as $account) { $entry = [ 'type' => self::TYPE_MENTION_CONTACT, - 'photo' => Contact::getMicro($contact, true), - 'name' => htmlspecialchars($contact['name']), - 'id' => intval($contact['id']), - 'network' => $contact['network'], - 'link' => $contact['url'], - 'nick' => htmlentities(($contact['attag'] ?? '') ?: $contact['nick']), - 'addr' => htmlentities(($contact['addr'] ?? '') ?: $contact['url']), - 'group' => $contact['contact-type'] == Contact::TYPE_COMMUNITY, + 'photo' => Contact::getMicro($account, true), + 'name' => htmlspecialchars($account['name']), + 'id' => intval($account['id']), + 'network' => $account['network'], + 'link' => $account['url'], + 'nick' => htmlentities(($account['attag'] ?? '') ?: $account['nick']), + 'addr' => htmlentities(($account['addr'] ?? '') ?: $account['url']), + 'group' => $account['contact-type'] == Contact::TYPE_COMMUNITY, ]; if ($entry['group']) { $groups[] = $entry; @@ -274,18 +274,18 @@ class Acl extends BaseModule $this->database->close($authors); foreach (array_diff($item_authors, $known_contacts) as $author) { - $contact = Contact::getByURL($author, false, ['micro', 'name', 'id', 'network', 'nick', 'addr', 'url', 'forum', 'avatar']); - if ($contact) { + $account = Contact::selectFirstAccount(['micro', 'name', 'id', 'network', 'nick', 'addr', 'url', 'forum', 'avatar', 'guid', 'updated'], ['url' => $author]); + if ($account) { $unknown_contacts[] = [ 'type' => self::TYPE_MENTION_CONTACT, - 'photo' => Contact::getMicro($contact, true), - 'name' => htmlspecialchars($contact['name']), - 'id' => intval($contact['id']), - 'network' => $contact['network'], - 'link' => $contact['url'], - 'nick' => htmlentities(($contact['nick'] ?? '') ?: $contact['addr']), - 'addr' => htmlentities(($contact['addr'] ?? '') ?: $contact['url']), - 'group' => $contact['forum'] + 'photo' => Contact::getMicro($account, true), + 'name' => htmlspecialchars($account['name']), + 'id' => intval($account['id']), + 'network' => $account['network'], + 'link' => $account['url'], + 'nick' => htmlentities(($account['nick'] ?? '') ?: $account['addr']), + 'addr' => htmlentities(($account['addr'] ?? '') ?: $account['url']), + 'group' => $account['forum'] ]; } } diff --git a/src/Navigation/Notifications/Factory/Introduction.php b/src/Navigation/Notifications/Factory/Introduction.php index b0b8e3c2ad..b0e27fade8 100644 --- a/src/Navigation/Notifications/Factory/Introduction.php +++ b/src/Navigation/Notifications/Factory/Introduction.php @@ -99,11 +99,12 @@ class Introduction extends BaseFactory try { $stmtNotifications = $this->dba->p( - "SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*, + "SELECT `intro`.`id` AS `intro_id`, `intro`.*, `contact`.*, `item-uri`.`guid` `suggest-contact`.`name` AS `fname`, `suggest-contact`.`url` AS `furl`, `suggest-contact`.`addr` AS `faddr`, `suggest-contact`.`photo` AS `fphoto`, `suggest-contact`.`request` AS `frequest` FROM `intro` LEFT JOIN `contact` ON `contact`.`id` = `intro`.`contact-id` + LEFT JOIN `item-uri` ON `item-uri`.`id` = `contact`.`uri-id`) LEFT JOIN `contact` AS `suggest-contact` ON `intro`.`suggest-cid` = `suggest-contact`.`id` WHERE `intro`.`uid` = ? $sql_extra LIMIT ?, ?", diff --git a/src/Network/Probe.php b/src/Network/Probe.php index fc5125f259..e657fb35f7 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -2258,7 +2258,7 @@ class Probe 'name' => $owner['name'], 'nick' => $owner['nick'], 'guid' => $approfile['diaspora:guid'] ?? '', 'url' => $owner['url'], 'addr' => $owner['addr'], 'alias' => $owner['alias'], 'photo' => User::getAvatarUrl($owner), - 'header' => $owner['header'] ? Contact::getHeaderUrlForId($owner['id'], $owner['updated']) : '', + 'header' => $owner['header'] ? Contact::getHeaderUrlForId($owner['guid'], $owner['updated']) : '', 'account-type' => $owner['contact-type'], 'community' => ($owner['contact-type'] == User::ACCOUNT_TYPE_COMMUNITY), 'keywords' => $owner['keywords'], 'location' => $owner['location'], 'about' => $owner['about'], 'xmpp' => $owner['xmpp'], 'matrix' => $owner['matrix'], diff --git a/src/Object/Api/Mastodon/Account.php b/src/Object/Api/Mastodon/Account.php index 4d0d40cec0..e268051a95 100644 --- a/src/Object/Api/Mastodon/Account.php +++ b/src/Object/Api/Mastodon/Account.php @@ -108,10 +108,10 @@ class Account extends BaseDataTransferObject $this->note = BBCode::convertForUriId($account['uri-id'], $account['about'], BBCode::EXTERNAL); $this->url = $account['url']; - $this->avatar = Contact::getAvatarUrlForId($account['id'] ?? 0 ?: $account['pid'], Proxy::SIZE_SMALL, $account['updated'], $account['guid'] ?? ''); - $this->avatar_static = Contact::getAvatarUrlForId($account['id'] ?? 0 ?: $account['pid'], Proxy::SIZE_SMALL, $account['updated'], $account['guid'] ?? '', true); - $this->header = Contact::getHeaderUrlForId($account['id'] ?? 0 ?: $account['pid'], '', $account['updated'], $account['guid'] ?? ''); - $this->header_static = Contact::getHeaderUrlForId($account['id'] ?? 0 ?: $account['pid'], '', $account['updated'], $account['guid'] ?? '', true); + $this->avatar = Contact::getAvatarUrlForId($account['guid'], $account['updated'], Proxy::SIZE_SMALL); + $this->avatar_static = Contact::getAvatarUrlForId($account['guid'], $account['updated'], Proxy::SIZE_SMALL, true); + $this->header = Contact::getHeaderUrlForId($account['guid'], $account['updated']); + $this->header_static = Contact::getHeaderUrlForId($account['guid'], $account['updated'], null, true); $this->followers_count = $account['ap-followers_count'] ?? $account['diaspora-interacted_count'] ?? 0; $this->following_count = $account['ap-following_count'] ?? $account['diaspora-interacting_count'] ?? 0; $this->statuses_count = $account['ap-statuses_count'] ?? $account['diaspora-post_count'] ?? 0; diff --git a/src/Object/Api/Twitter/User.php b/src/Object/Api/Twitter/User.php index 24cf56cad9..e949dc53e6 100644 --- a/src/Object/Api/Twitter/User.php +++ b/src/Object/Api/Twitter/User.php @@ -128,7 +128,7 @@ class User extends BaseDataTransferObject */ /** - * @param array $publicContact Full contact table record with uid = 0 + * @param array $publicAccount Full account-view table record * @param array $apcontact Optional full apcontact table record * @param array $userContact Optional full contact table record with uid != 0 * @param null $status @@ -136,18 +136,18 @@ class User extends BaseDataTransferObject * * @throws InternalServerErrorException */ - public function __construct(array $publicContact, array $apcontact = [], array $userContact = [], $status = null, bool $include_user_entities = true) + public function __construct(array $publicAccount, array $apcontact = [], array $userContact = [], $status = null, bool $include_user_entities = true) { $uid = $userContact['uid'] ?? 0; - $this->id = (int)$publicContact['id']; - $this->id_str = (string) $publicContact['id']; - $this->name = $publicContact['name'] ?: $publicContact['nick']; - $this->screen_name = $publicContact['nick'] ?: $publicContact['name']; - $this->location = $publicContact['location'] ?: - ContactSelector::networkToName($publicContact['network'], $publicContact['url'], $publicContact['protocol']); + $this->id = (int)$publicAccount['id']; + $this->id_str = (string) $publicAccount['id']; + $this->name = $publicAccount['name'] ?: $publicAccount['nick']; + $this->screen_name = $publicAccount['nick'] ?: $publicAccount['name']; + $this->location = $publicAccount['location'] ?: + ContactSelector::networkToName($publicAccount['network'], $publicAccount['url'], $publicAccount['protocol']); $this->derived = []; - $this->url = $publicContact['url']; + $this->url = $publicAccount['url']; // No entities needed since we don't perform any shortening in the URL or description $this->entities = [ 'url' => ['urls' => []], @@ -156,17 +156,17 @@ class User extends BaseDataTransferObject if (!$include_user_entities) { unset($this->entities); } - $this->description = (!empty($publicContact['about']) ? BBCode::toPlaintext($publicContact['about']) : ''); - $this->profile_image_url_https = Contact::getAvatarUrlForUrl($publicContact['url'], $uid, Proxy::SIZE_MICRO); + $this->description = (!empty($publicAccount['about']) ? BBCode::toPlaintext($publicAccount['about']) : ''); + $this->profile_image_url_https = Contact::getAvatarUrlForUrl($publicAccount['url'], $uid, Proxy::SIZE_MICRO); $this->protected = false; $this->followers_count = $apcontact['followers_count'] ?? 0; $this->friends_count = $apcontact['following_count'] ?? 0; $this->listed_count = 0; - $this->created_at = DateTimeFormat::utc($publicContact['created'], DateTimeFormat::API); + $this->created_at = DateTimeFormat::utc($publicAccount['created'], DateTimeFormat::API); $this->favourites_count = 0; $this->verified = $uid != 0; $this->statuses_count = $apcontact['statuses_count'] ?? 0; - $this->profile_banner_url = Contact::getHeaderUrlForId($publicContact['id'], '', $publicContact['updated']); + $this->profile_banner_url = Contact::getHeaderUrlForId($publicAccount['guid'], $publicAccount['updated']); $this->default_profile = false; $this->default_profile_image = false; @@ -181,9 +181,9 @@ class User extends BaseDataTransferObject unset($this->withheld_scope); // Deprecated - $this->profile_image_url = Contact::getAvatarUrlForUrl($publicContact['url'], $uid, Proxy::SIZE_MICRO); - $this->profile_image_url_profile_size = Contact::getAvatarUrlForUrl($publicContact['url'], $uid, Proxy::SIZE_THUMB); - $this->profile_image_url_large = Contact::getAvatarUrlForUrl($publicContact['url'], $uid, Proxy::SIZE_LARGE); + $this->profile_image_url = Contact::getAvatarUrlForUrl($publicAccount['url'], $uid, Proxy::SIZE_MICRO); + $this->profile_image_url_profile_size = Contact::getAvatarUrlForUrl($publicAccount['url'], $uid, Proxy::SIZE_THUMB); + $this->profile_image_url_large = Contact::getAvatarUrlForUrl($publicAccount['url'], $uid, Proxy::SIZE_LARGE); $this->utc_offset = 0; $this->time_zone = 'UTC'; $this->geo_enabled = false; @@ -199,7 +199,7 @@ class User extends BaseDataTransferObject // Friendica-specific $this->uid = (int)$uid; $this->cid = (int)($userContact['id'] ?? 0); - $this->pid = (int)$publicContact['id']; - $this->statusnet_profile_url = $publicContact['url']; + $this->pid = (int)$publicAccount['id']; + $this->statusnet_profile_url = $publicAccount['url']; } } diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 9aa25b3db5..1108a0e4d4 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -414,7 +414,7 @@ class Transmitter } if (!empty($owner['header'])) { - $data['image'] = ['type' => 'Image', 'url' => Contact::getHeaderUrlForId($owner['id'], '', $owner['updated'])]; + $data['image'] = ['type' => 'Image', 'url' => Contact::getHeaderUrlForId($owner['guid'], $owner['updated'])]; $resourceid = Photo::ridFromURI($owner['header']); if (!empty($resourceid)) { @@ -449,22 +449,26 @@ class Transmitter /** * Get a minimal actor array for the C2S API * - * @param integer $cid + * @param integer $cid Public contact id * @return array + * @throws \Exception */ private static function getActorArrayByCid(int $cid): array { - $contact = Contact::getById($cid); + $account = Contact::selectFirstAccount( + ['url', 'contact-type', 'alias', 'nick', 'name', 'guid', 'updated', 'manually-approve', 'unsearchable'], + ['id' => $cid] + ); $data = [ - 'id' => $contact['url'], - 'type' => $data['type'] = ActivityPub::ACCOUNT_TYPES[$contact['contact-type']], - 'url' => $contact['alias'], - 'preferredUsername' => $contact['nick'], - 'name' => $contact['name'], - 'icon' => ['type' => 'Image', 'url' => Contact::getAvatarUrlForId($cid, '', $contact['updated'])], - 'image' => ['type' => 'Image', 'url' => Contact::getHeaderUrlForId($cid, '', $contact['updated'])], - 'manuallyApprovesFollowers' => (bool)$contact['manually-approve'], - 'discoverable' => !$contact['unsearchable'], + 'id' => $account['url'], + 'type' => $data['type'] = ActivityPub::ACCOUNT_TYPES[$account['contact-type']], + 'url' => $account['alias'], + 'preferredUsername' => $account['nick'], + 'name' => $account['name'], + 'icon' => ['type' => 'Image', 'url' => Contact::getAvatarUrlForId($account['guid'], $account['updated'])], + 'image' => ['type' => 'Image', 'url' => Contact::getHeaderUrlForId($account['guid'], $account['updated'])], + 'manuallyApprovesFollowers' => (bool)$account['manually-approve'], + 'discoverable' => !$account['unsearchable'], ]; if (empty($data['url'])) { diff --git a/static/routes.config.php b/static/routes.config.php index 77d04f92c1..992e1f99f8 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -571,6 +571,7 @@ return [ '/{type}/{id:\d+}' => [Module\Photo::class, [R::GET]], '/{type:contact|header}/{guid}' => [Module\Photo::class, [R::GET]], '/{type}/{nickname_ext}' => [Module\Photo::class, [R::GET]], + // Contact Id Fallback, to remove after version 2024.03 '/{type:contact|header}/{customsize:\d+}/{contact_id:\d+}' => [Module\Photo::class, [R::GET]], '/{type:contact|header}/{customsize:\d+}/{guid}' => [Module\Photo::class, [R::GET]], '/{type}/{customsize:\d+}/{id:\d+}' => [Module\Photo::class, [R::GET]], diff --git a/view/theme/frio/theme.php b/view/theme/frio/theme.php index 58eb8268c3..86adde13d9 100644 --- a/view/theme/frio/theme.php +++ b/view/theme/frio/theme.php @@ -188,29 +188,29 @@ function frio_contact_photo_menu(&$args) * Some links will point to the local pages because the user would expect * local page (these pages are: search, community, help, apps, directory). * - * @param App $a The App class * @param array $nav_info The original nav info array: nav, banner, userinfo, sitelocation - * @throws Exception + * @throws ImagickException + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ function frio_remote_nav(array &$nav_info) { if (DI::mode()->has(App\Mode::MAINTENANCEDISABLED)) { // get the homelink from $_SESSION - $homelink = Profile::getMyURL(); + $homelink = DI::userSession()->getMyUrl(); if (!$homelink) { $homelink = DI::session()->get('visitor_home', ''); } // since $userinfo isn't available for the hook we write it to the nav array // this isn't optimal because the contact query will be done now twice - $fields = ['id', 'url', 'avatar', 'micro', 'name', 'nick', 'baseurl', 'updated']; + $fields = ['id', 'url', 'guid', 'avatar', 'micro', 'name', 'nick', 'baseurl', 'updated']; if (DI::userSession()->isAuthenticated()) { - $remoteUser = Contact::selectFirst($fields, ['uid' => DI::userSession()->getLocalUserId(), 'self' => true]); + $remoteUser = Contact::selectFirstAccountUser($fields, ['uid' => DI::userSession()->getLocalUserId(), 'self' => true]); } elseif (!DI::userSession()->getLocalUserId() && DI::userSession()->getRemoteUserId()) { - $remoteUser = Contact::getById(DI::userSession()->getRemoteUserId(), $fields); + $remoteUser = Contact::selectFirstAccountUser($fields, ['id' => DI::userSession()->getRemoteUserId()]); $nav_info['nav']['remote'] = DI::l10n()->t('Guest'); - } elseif (Profile::getMyURL()) { - $remoteUser = Contact::getByURL($homelink, null, $fields); + } elseif (DI::userSession()->getMyUrl()) { + $remoteUser = Contact::selectFirstAccount($fields, ['id' => Contact::getIdForURL($homelink)]); $nav_info['nav']['remote'] = DI::l10n()->t('Visitor'); } else { $remoteUser = null;