diff --git a/mod/viewcontacts.php b/mod/viewcontacts.php deleted file mode 100644 index 14919820dd..0000000000 --- a/mod/viewcontacts.php +++ /dev/null @@ -1,120 +0,0 @@ -argc < 2) { - throw new \Friendica\Network\HTTPException\ForbiddenException(L10n::t('Access denied.')); - } - - Nav::setSelected('home'); - - $user = DBA::selectFirst('user', [], ['nickname' => $a->argv[1], 'blocked' => false]); - if (!DBA::isResult($user)) { - throw new \Friendica\Network\HTTPException\NotFoundException(); - } - - $a->data['user'] = $user; - $a->profile_uid = $user['uid']; - - Profile::load($a, $a->argv[1]); -} - -function viewcontacts_content(App $a) -{ - if (Config::get('system', 'block_public') && !local_user() && !remote_user()) { - notice(L10n::t('Public access denied.') . EOL); - return; - } - - $is_owner = $a->profile['profile_uid'] == local_user(); - - // tabs - $o = Profile::getTabs($a, $is_owner, $a->data['user']['nickname']); - - if (!count($a->profile) || $a->profile['hide-friends']) { - notice(L10n::t('Permission denied.') . EOL); - return $o; - } - - $condition = [ - 'uid' => $a->profile['uid'], - 'blocked' => false, - 'pending' => false, - 'hidden' => false, - 'archive' => false, - 'network' => [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS] - ]; - - $total = DBA::count('contact', $condition); - - $pager = new Pager($a->query_string); - - $params = ['order' => ['name' => false], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]]; - - $contacts_stmt = DBA::select('contact', [], $condition, $params); - - if (!DBA::isResult($contacts_stmt)) { - info(L10n::t('No contacts.') . EOL); - return $o; - } - - $contacts = []; - - while ($contact = DBA::fetch($contacts_stmt)) { - /// @TODO This triggers an E_NOTICE if 'self' is not there - if ($contact['self']) { - continue; - } - - $contact_details = Contact::getDetailsByURL($contact['url'], $a->profile['uid'], $contact); - - $contacts[] = [ - 'id' => $contact['id'], - 'img_hover' => L10n::t('Visit %s\'s profile [%s]', $contact_details['name'], $contact['url']), - 'photo_menu' => Contact::photoMenu($contact), - 'thumb' => ProxyUtils::proxifyUrl($contact_details['thumb'], false, ProxyUtils::SIZE_THUMB), - 'name' => substr($contact_details['name'], 0, 20), - 'username' => $contact_details['name'], - 'details' => $contact_details['location'], - 'tags' => $contact_details['keywords'], - 'about' => $contact_details['about'], - 'account_type' => Contact::getAccountType($contact_details), - 'url' => Contact::magicLink($contact['url']), - 'sparkle' => '', - 'itemurl' => (($contact_details['addr'] != "") ? $contact_details['addr'] : $contact['url']), - 'network' => ContactSelector::networkToName($contact['network'], $contact['url']), - ]; - } - - DBA::close($contacts_stmt); - - $tpl = Renderer::getMarkupTemplate("viewcontact_template.tpl"); - $o .= Renderer::replaceMacros($tpl, [ - '$title' => L10n::t('Contacts'), - '$contacts' => $contacts, - '$paginate' => $pager->renderFull($total), - ]); - - return $o; -} diff --git a/src/App/Router.php b/src/App/Router.php index be81c143d1..f7ee24730d 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -187,6 +187,7 @@ class Router $this->routeCollector->addRoute(['GET'], '/probe', Module\Debug\Probe::class); $this->routeCollector->addGroup('/profile', function (RouteCollector $collector) { $collector->addRoute(['GET'], '/{nickname}', Module\Profile::class); + $collector->addRoute(['GET'], '/{nickname}/contacts[/{type}]', Module\Profile\Contacts::class); $collector->addRoute(['GET'], '/{profile:\d+}/view', Module\Profile::class); }); $this->routeCollector->addGroup('/proxy', function (RouteCollector $collector) { diff --git a/src/Content/Widget/ContactBlock.php b/src/Content/Widget/ContactBlock.php index f4fdea2fb4..bc33b9c9c9 100644 --- a/src/Content/Widget/ContactBlock.php +++ b/src/Content/Widget/ContactBlock.php @@ -52,7 +52,7 @@ class ContactBlock 'pending' => false, 'hidden' => false, 'archive' => false, - 'network' => [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA], + 'network' => [Protocol::DFRN, Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::FEED], ]); $contacts_title = L10n::t('No contacts'); diff --git a/src/Model/Profile.php b/src/Model/Profile.php index a854b1c9e0..38f5c03623 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -894,7 +894,7 @@ class Profile [ 'label' => L10n::t('Status'), 'url' => $url, - 'sel' => !$tab && $a->argv[0] == 'profile' ? 'active' : '', + 'sel' => !$tab && $a->argv[0] == 'profile' && (empty($a->argv[2]) || $a->argv[2] !== 'contacts') ? 'active' : '', 'title' => L10n::t('Status Messages and Posts'), 'id' => 'status-tab', 'accesskey' => 'm', @@ -969,11 +969,11 @@ class Profile ]; } - if (!$is_owner && empty($a->profile['hide-friends'])) { + if ($is_owner || empty($a->profile['hide-friends'])) { $tabs[] = [ 'label' => L10n::t('Contacts'), - 'url' => System::baseUrl() . '/viewcontacts/' . $nickname, - 'sel' => !$tab && $a->argv[0] == 'viewcontacts' ? 'active' : '', + 'url' => System::baseUrl() . '/profile/' . $nickname . '/contacts', + 'sel' => !$tab && !empty($a->argv[2]) && $a->argv[2] == 'contacts' ? 'active' : '', 'title' => L10n::t('Contacts'), 'id' => 'viewcontacts-tab', 'accesskey' => 'k', diff --git a/src/Module/Profile/Contacts.php b/src/Module/Profile/Contacts.php new file mode 100644 index 0000000000..340c9ef19c --- /dev/null +++ b/src/Module/Profile/Contacts.php @@ -0,0 +1,137 @@ +argv[1]; + $type = defaults($a->argv, 3, 'all'); + + Nav::setSelected('home'); + + $user = DBA::selectFirst('user', [], ['nickname' => $nickname, 'blocked' => false]); + if (!DBA::isResult($user)) { + throw new \Friendica\Network\HTTPException\NotFoundException(L10n::t('User not found.')); + } + + $a->data['user'] = $user; + $a->profile_uid = $user['uid']; + + Profile::load($a, $nickname); + + $is_owner = $a->profile['profile_uid'] == local_user(); + + // tabs + $o = Profile::getTabs($a, $is_owner, $nickname); + + if (!count($a->profile) || $a->profile['hide-friends']) { + notice(L10n::t('Permission denied.') . EOL); + return $o; + } + + $condition = [ + 'uid' => $a->profile['uid'], + 'blocked' => false, + 'pending' => false, + 'hidden' => false, + 'archive' => false, + 'network' => [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, Protocol::FEED] + ]; + + switch ($type) { + case 'followers': $condition['rel'] = [1, 3]; break; + case 'following': $condition['rel'] = [2, 3]; break; + case 'mutuals': $condition['rel'] = 3; break; + } + + $total = DBA::count('contact', $condition); + + $pager = new Pager($a->query_string); + + $params = ['order' => ['name' => false], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]]; + + $contacts_stmt = DBA::select('contact', [], $condition, $params); + + if (!DBA::isResult($contacts_stmt)) { + info(L10n::t('No contacts.') . EOL); + return $o; + } + + $contacts = []; + + while ($contact = DBA::fetch($contacts_stmt)) { + /// @TODO This triggers an E_NOTICE if 'self' is not there + if ($contact['self']) { + continue; + } + + $contact_details = Contact::getDetailsByURL($contact['url'], $a->profile['uid'], $contact); + + $contacts[] = [ + 'id' => $contact['id'], + 'img_hover' => L10n::t('Visit %s\'s profile [%s]', $contact_details['name'], $contact['url']), + 'photo_menu' => Contact::photoMenu($contact), + 'thumb' => ProxyUtils::proxifyUrl($contact_details['thumb'], false, ProxyUtils::SIZE_THUMB), + 'name' => substr($contact_details['name'], 0, 20), + 'username' => $contact_details['name'], + 'details' => $contact_details['location'], + 'tags' => $contact_details['keywords'], + 'about' => $contact_details['about'], + 'account_type' => Contact::getAccountType($contact_details), + 'url' => Contact::magicLink($contact['url']), + 'sparkle' => '', + 'itemurl' => $contact_details['addr'] ? : $contact['url'], + 'network' => ContactSelector::networkToName($contact['network'], $contact['url']), + ]; + } + + DBA::close($contacts_stmt); + + switch ($type) { + case 'followers': $title = L10n::tt('Follower (%s)', 'Followers (%s)', $total); break; + case 'following': $title = L10n::tt('Following (%s)', 'Following (%s)', $total); break; + case 'mutuals': $title = L10n::tt('Mutual friend (%s)', 'Mutual friends (%s)', $total); break; + + case 'all': default: $title = L10n::tt('Contact (%s)', 'Contacts (%s)', $total); break; + } + + $tpl = Renderer::getMarkupTemplate('profile/contacts.tpl'); + $o .= Renderer::replaceMacros($tpl, [ + '$title' => $title, + '$nickname' => $nickname, + '$type' => $type, + + '$all_label' => L10n::t('All contacts'), + '$followers_label' => L10n::t('Followers'), + '$following_label' => L10n::t('Following'), + '$mutuals_label' => L10n::t('Mutual friends'), + + '$contacts' => $contacts, + '$paginate' => $pager->renderFull($total), + ]); + + return $o; + } +} diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index dec5c4c80b..c7747e8cfc 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -1515,7 +1515,7 @@ class OStatus $author->appendChild($urls); } - XML::addElement($doc, $author, "followers", "", ["url" => System::baseUrl()."/viewcontacts/".$owner["nick"]]); + XML::addElement($doc, $author, "followers", "", ["url" => System::baseUrl() . "/profile/" . $owner["nick"] . "/contacts/followers"]); XML::addElement($doc, $author, "statusnet:profile_info", "", ["local_id" => $owner["uid"]]); if ($profile["publish"]) { diff --git a/view/templates/profile/contacts.tpl b/view/templates/profile/contacts.tpl new file mode 100644 index 0000000000..4e78a7a7f8 --- /dev/null +++ b/view/templates/profile/contacts.tpl @@ -0,0 +1,20 @@ +
+ {{include file="section_title.tpl"}} + + + +
+{{foreach $contacts as $contact}} + {{include file="contact_template.tpl"}} +{{/foreach}} +
+
+
+ + {{$paginate nofilter}} +
diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index f586d6e04d..7e66570ad5 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -680,10 +680,6 @@ input#dfrn-url { clear: both; } - -#viewcontacts { - margin-top: 15px; -} #profile-edit-default-desc { color: #FF0000; border: 1px solid #FF8888; diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index 4a72628352..2a5706c859 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -2317,7 +2317,7 @@ ul.dropdown-menu li:hover { .manage-content-wrapper, .notes-content-wrapper, .message-content-wrapper, .apps-content-wrapper, #adminpage, .delegate-content-wrapper, .uexport-content-wrapper, -.viewcontacts-content-wrapper, .dfrn_request-content-wrapper, +.dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, .fsuggest-content-wrapper { @@ -3547,7 +3547,7 @@ section .profile-match-wrapper { right: 10px; } - .generic-page-wrapper, .profile_photo-content-wrapper, .videos-content-wrapper, .suggest-content-wrapper, .common-content-wrapper, .help-content-wrapper, .allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper, .directory-content-wrapper, .manage-content-wrapper, .notes-content-wrapper, .message-content-wrapper, .apps-content-wrapper, #adminpage, .delegate-content-wrapper, .uexport-content-wrapper, .viewcontacts-content-wrapper, .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, .fsuggest-content-wrapper { + .generic-page-wrapper, .profile_photo-content-wrapper, .videos-content-wrapper, .suggest-content-wrapper, .common-content-wrapper, .help-content-wrapper, .allfriends-content-wrapper, .match-content-wrapper, .dirfind-content-wrapper, .directory-content-wrapper, .manage-content-wrapper, .notes-content-wrapper, .message-content-wrapper, .apps-content-wrapper, #adminpage, .delegate-content-wrapper, .uexport-content-wrapper, .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, .nogroup-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, .fsuggest-content-wrapper { border-radius: 0; padding: 10px; } diff --git a/view/theme/frio/templates/profile/contacts.tpl b/view/theme/frio/templates/profile/contacts.tpl new file mode 100644 index 0000000000..69d34d05ab --- /dev/null +++ b/view/theme/frio/templates/profile/contacts.tpl @@ -0,0 +1,20 @@ +
+ {{include file="section_title.tpl"}} + + + + +
+
+ + {{$paginate nofilter}} +
diff --git a/view/theme/smoothly/style.css b/view/theme/smoothly/style.css index 9bbf00c780..fec5d2bda5 100644 --- a/view/theme/smoothly/style.css +++ b/view/theme/smoothly/style.css @@ -2834,10 +2834,6 @@ margin-left: 0px; clear: both; } -#viewcontacts { - margin-top: 15px; -} - .contact-entry-wrapper .contact-entry-photo-wrapper { float: left; margin-right: 10px;