Merge pull request #12447 from MrPetovan/bug/12441-profile-contacts

Retrieve contact records for the page visitor in several modules
This commit is contained in:
Philipp 2022-12-19 17:14:43 +01:00 committed by GitHub
commit 20374ab5a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 229 additions and 126 deletions

View file

@ -1130,39 +1130,25 @@ class Contact
* Returns the data array for the photo menu of a given contact * Returns the data array for the photo menu of a given contact
* *
* @param array $contact contact * @param array $contact contact
* @param int $uid optional, default 0 * @param int $uid Visitor user id
* @return array * @return array
* @throws HTTPException\InternalServerErrorException * @throws HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
public static function photoMenu(array $contact, int $uid = 0): array public static function photoMenu(array $contact, int $uid): array
{ {
$pm_url = ''; // Anonymous visitor
if (!$uid) {
return ['profile' => [DI::l10n()->t('View Profile'), self::magicLinkByContact($contact), true]];
}
$pm_url = '';
$status_link = ''; $status_link = '';
$photos_link = ''; $photos_link = '';
if ($uid == 0) {
$uid = DI::userSession()->getLocalUserId();
}
if (empty($contact['uid']) || ($contact['uid'] != $uid)) {
if ($uid == 0) {
$profile_link = self::magicLinkByContact($contact);
$menu = ['profile' => [DI::l10n()->t('View Profile'), $profile_link, true]];
return $menu;
}
// Look for our own contact if the uid doesn't match and isn't public
$contact_own = DBA::selectFirst('contact', [], ['nurl' => $contact['nurl'], 'network' => $contact['network'], 'uid' => $uid]);
if (DBA::isResult($contact_own)) {
return self::photoMenu($contact_own, $uid);
}
}
$sparkle = false; $sparkle = false;
if (($contact['network'] === Protocol::DFRN) && !$contact['self'] && empty($contact['pending'])) { if (($contact['network'] === Protocol::DFRN) && !$contact['self'] && empty($contact['pending'])) {
$sparkle = true; $sparkle = true;
$profile_link = 'contact/redir/' . $contact['id']; $profile_link = 'contact/redir/' . $contact['id'];
} else { } else {
$profile_link = $contact['url']; $profile_link = $contact['url'];
@ -1173,8 +1159,8 @@ class Contact
} }
if ($sparkle) { if ($sparkle) {
$status_link = $profile_link . '/status'; $status_link = $profile_link . '/status';
$photos_link = $profile_link . '/photos'; $photos_link = $profile_link . '/photos';
$profile_link = $profile_link . '/profile'; $profile_link = $profile_link . '/profile';
} }
@ -1183,15 +1169,14 @@ class Contact
} }
$contact_url = 'contact/' . $contact['id']; $contact_url = 'contact/' . $contact['id'];
$posts_link = 'contact/' . $contact['id'] . '/conversations'; $posts_link = 'contact/' . $contact['id'] . '/conversations';
$follow_link = ''; $follow_link = '';
$unfollow_link = ''; $unfollow_link = '';
if (!$contact['self'] && Protocol::supportsFollow($contact['network'])) { if (!$contact['self'] && Protocol::supportsFollow($contact['network'])) {
if ($contact['uid'] && in_array($contact['rel'], [self::SHARING, self::FRIEND])) { if ($contact['uid'] && in_array($contact['rel'], [self::SHARING, self::FRIEND])) {
$unfollow_link = 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1'; $unfollow_link = 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1';
} elseif(!$contact['pending']) { } elseif (!$contact['pending']) {
$follow_link = 'contact/follow?url=' . urlencode($contact['url']) . '&auto=1'; $follow_link = 'contact/follow?url=' . urlencode($contact['url']) . '&auto=1';
} }
} }
@ -1202,27 +1187,27 @@ class Contact
*/ */
if (empty($contact['uid'])) { if (empty($contact['uid'])) {
$menu = [ $menu = [
'profile' => [DI::l10n()->t('View Profile') , $profile_link , true], 'profile' => [DI::l10n()->t('View Profile') , $profile_link , true ],
'network' => [DI::l10n()->t('Network Posts') , $posts_link , false], 'network' => [DI::l10n()->t('Network Posts') , $posts_link , false],
'edit' => [DI::l10n()->t('View Contact') , $contact_url , false], 'edit' => [DI::l10n()->t('View Contact') , $contact_url , false],
'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true], 'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true ],
'unfollow'=> [DI::l10n()->t('Unfollow') , $unfollow_link, true], 'unfollow' => [DI::l10n()->t('Unfollow') , $unfollow_link, true ],
]; ];
} else { } else {
$menu = [ $menu = [
'status' => [DI::l10n()->t('View Status') , $status_link , true], 'status' => [DI::l10n()->t('View Status') , $status_link , true ],
'profile' => [DI::l10n()->t('View Profile') , $profile_link , true], 'profile' => [DI::l10n()->t('View Profile') , $profile_link , true ],
'photos' => [DI::l10n()->t('View Photos') , $photos_link , true], 'photos' => [DI::l10n()->t('View Photos') , $photos_link , true ],
'network' => [DI::l10n()->t('Network Posts') , $posts_link , false], 'network' => [DI::l10n()->t('Network Posts') , $posts_link , false],
'edit' => [DI::l10n()->t('View Contact') , $contact_url , false], 'edit' => [DI::l10n()->t('View Contact') , $contact_url , false],
'pm' => [DI::l10n()->t('Send PM') , $pm_url , false], 'pm' => [DI::l10n()->t('Send PM') , $pm_url , false],
'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true], 'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true ],
'unfollow'=> [DI::l10n()->t('Unfollow') , $unfollow_link , true], 'unfollow' => [DI::l10n()->t('Unfollow') , $unfollow_link, true ],
]; ];
if (!empty($contact['pending'])) { if (!empty($contact['pending'])) {
try { try {
$intro = DI::intro()->selectForContact($contact['id']); $intro = DI::intro()->selectForContact($contact['id']);
$menu['follow'] = [DI::l10n()->t('Approve'), 'notifications/intros/' . $intro->id, true]; $menu['follow'] = [DI::l10n()->t('Approve'), 'notifications/intros/' . $intro->id, true];
} catch (IntroductionNotFoundException $exception) { } catch (IntroductionNotFoundException $exception) {
DI::logger()->error('Pending contact doesn\'t have an introduction.', ['exception' => $exception]); DI::logger()->error('Pending contact doesn\'t have an introduction.', ['exception' => $exception]);

View file

@ -35,6 +35,7 @@ use Friendica\DI;
use Friendica\Model; use Friendica\Model;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Module\Security\Login; use Friendica\Module\Security\Login;
use Friendica\Network\HTTPException\InternalServerErrorException;
use Friendica\Network\HTTPException\NotFoundException; use Friendica\Network\HTTPException\NotFoundException;
/** /**
@ -494,16 +495,18 @@ class Contact extends BaseModule
* *
* @param array $contact Contact array * @param array $contact Contact array
* @return array Template fields * @return array Template fields
* @throws InternalServerErrorException
* @throws \ImagickException
*/ */
public static function getContactTemplateVars(array $contact) public static function getContactTemplateVars(array $contact): array
{ {
$alt_text = ''; $alt_text = '';
if (!empty($contact['url']) && isset($contact['uid']) && ($contact['uid'] == 0) && DI::userSession()->getLocalUserId()) { if (!empty($contact['url']) && isset($contact['uid']) && ($contact['uid'] == 0) && DI::userSession()->getLocalUserId()) {
$personal = Model\Contact::getByURL($contact['url'], false, ['uid', 'rel', 'self'], DI::userSession()->getLocalUserId()); $personal = Model\Contact::getByURL($contact['url'], false, ['uid', 'rel', 'self'], DI::userSession()->getLocalUserId());
if (!empty($personal)) { if (!empty($personal)) {
$contact['uid'] = $personal['uid']; $contact['uid'] = $personal['uid'];
$contact['rel'] = $personal['rel']; $contact['rel'] = $personal['rel'];
$contact['self'] = $personal['self']; $contact['self'] = $personal['self'];
} }
} }
@ -545,15 +548,15 @@ class Contact extends BaseModule
if ($contact['self']) { if ($contact['self']) {
$alt_text = DI::l10n()->t('This is you'); $alt_text = DI::l10n()->t('This is you');
$url = $contact['url']; $url = $contact['url'];
$sparkle = ''; $sparkle = '';
} }
return [ return [
'id' => $contact['id'], 'id' => $contact['id'],
'url' => $url, 'url' => $url,
'img_hover' => DI::l10n()->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']), 'img_hover' => DI::l10n()->t('Visit %s\'s profile [%s]', $contact['name'], $contact['url']),
'photo_menu' => Model\Contact::photoMenu($contact), 'photo_menu' => Model\Contact::photoMenu($contact, DI::userSession()->getLocalUserId()),
'thumb' => Model\Contact::getThumb($contact, true), 'thumb' => Model\Contact::getThumb($contact, true),
'alt_text' => $alt_text, 'alt_text' => $alt_text,
'name' => $contact['name'], 'name' => $contact['name'],

View file

@ -21,54 +21,72 @@
namespace Friendica\Module\Contact; namespace Friendica\Module\Contact;
use Friendica\App;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Content\Widget; use Friendica\Content\Widget;
use Friendica\Core\L10n;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\DI; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Model; use Friendica\Model;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Module; use Friendica\Module;
use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
class Contacts extends BaseModule class Contacts extends BaseModule
{ {
/** @var IHandleUserSessions */
private $userSession;
/** @var App\Page */
private $page;
public function __construct(App\Page $page, IHandleUserSessions $userSession, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->userSession = $userSession;
$this->page = $page;
}
protected function content(array $request = []): string protected function content(array $request = []): string
{ {
if (!DI::userSession()->getLocalUserId()) { if (!$this->userSession->getLocalUserId()) {
throw new HTTPException\ForbiddenException(); throw new HTTPException\ForbiddenException();
} }
$cid = $this->parameters['id']; $cid = $this->parameters['id'];
$type = $this->parameters['type'] ?? 'all'; $type = $this->parameters['type'] ?? 'all';
$accounttype = $_GET['accounttype'] ?? ''; $accounttype = $request['accounttype'] ?? '';
$accounttypeid = User::getAccountTypeByString($accounttype); $accounttypeid = User::getAccountTypeByString($accounttype);
if (!$cid) { if (!$cid) {
throw new HTTPException\BadRequestException(DI::l10n()->t('Invalid contact.')); throw new HTTPException\BadRequestException($this->t('Invalid contact.'));
} }
$contact = Model\Contact::getById($cid, []); $contact = Model\Contact::getById($cid, []);
if (empty($contact)) { if (empty($contact)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('Contact not found.')); throw new HTTPException\NotFoundException($this->t('Contact not found.'));
} }
$localContactId = Model\Contact::getPublicIdByUserId(DI::userSession()->getLocalUserId()); $localContactId = Model\Contact::getPublicIdByUserId($this->userSession->getLocalUserId());
DI::page()['aside'] = Widget\VCard::getHTML($contact); $this->page['aside'] = Widget\VCard::getHTML($contact);
$condition = [ $condition = [
'blocked' => false, 'blocked' => false,
'self' => false, 'self' => false,
'hidden' => false, 'hidden' => false,
'failed' => false, 'failed' => false,
]; ];
if (isset($accounttypeid)) { if (isset($accounttypeid)) {
$condition['contact-type'] = $accounttypeid; $condition['contact-type'] = $accounttypeid;
} }
$noresult_label = DI::l10n()->t('No known contacts.'); $noresult_label = $this->t('No known contacts.');
switch ($type) { switch ($type) {
case 'followers': case 'followers':
@ -82,50 +100,61 @@ class Contacts extends BaseModule
break; break;
case 'common': case 'common':
$total = Model\Contact\Relation::countCommon($localContactId, $cid, $condition); $total = Model\Contact\Relation::countCommon($localContactId, $cid, $condition);
$noresult_label = DI::l10n()->t('No common contacts.'); $noresult_label = $this->t('No common contacts.');
break; break;
default: default:
$total = Model\Contact\Relation::countAll($cid, $condition); $total = Model\Contact\Relation::countAll($cid, $condition);
} }
$pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 30); $pager = new Pager($this->l10n, $this->args->getQueryString(), 30);
$desc = ''; $desc = '';
switch ($type) { switch ($type) {
case 'followers': case 'followers':
$friends = Model\Contact\Relation::listFollowers($cid, $condition, $pager->getItemsPerPage(), $pager->getStart()); $friends = Model\Contact\Relation::listFollowers($cid, $condition, $pager->getItemsPerPage(), $pager->getStart());
$title = DI::l10n()->tt('Follower (%s)', 'Followers (%s)', $total); $title = $this->tt('Follower (%s)', 'Followers (%s)', $total);
break; break;
case 'following': case 'following':
$friends = Model\Contact\Relation::listFollows($cid, $condition, $pager->getItemsPerPage(), $pager->getStart()); $friends = Model\Contact\Relation::listFollows($cid, $condition, $pager->getItemsPerPage(), $pager->getStart());
$title = DI::l10n()->tt('Following (%s)', 'Following (%s)', $total); $title = $this->tt('Following (%s)', 'Following (%s)', $total);
break; break;
case 'mutuals': case 'mutuals':
$friends = Model\Contact\Relation::listMutuals($cid, $condition, $pager->getItemsPerPage(), $pager->getStart()); $friends = Model\Contact\Relation::listMutuals($cid, $condition, $pager->getItemsPerPage(), $pager->getStart());
$title = DI::l10n()->tt('Mutual friend (%s)', 'Mutual friends (%s)', $total); $title = $this->tt('Mutual friend (%s)', 'Mutual friends (%s)', $total);
$desc = DI::l10n()->t( $desc = $this->t(
'These contacts both follow and are followed by <strong>%s</strong>.', 'These contacts both follow and are followed by <strong>%s</strong>.',
htmlentities($contact['name'], ENT_COMPAT, 'UTF-8') htmlentities($contact['name'], ENT_COMPAT, 'UTF-8')
); );
break; break;
case 'common': case 'common':
$friends = Model\Contact\Relation::listCommon($localContactId, $cid, $condition, $pager->getItemsPerPage(), $pager->getStart()); $friends = Model\Contact\Relation::listCommon($localContactId, $cid, $condition, $pager->getItemsPerPage(), $pager->getStart());
$title = DI::l10n()->tt('Common contact (%s)', 'Common contacts (%s)', $total); $title = $this->tt('Common contact (%s)', 'Common contacts (%s)', $total);
$desc = DI::l10n()->t( $desc = $this->t(
'Both <strong>%s</strong> and yourself have publicly interacted with these contacts (follow, comment or likes on public posts).', 'Both <strong>%s</strong> and yourself have publicly interacted with these contacts (follow, comment or likes on public posts).',
htmlentities($contact['name'], ENT_COMPAT, 'UTF-8') htmlentities($contact['name'], ENT_COMPAT, 'UTF-8')
); );
break; break;
default: default:
$friends = Model\Contact\Relation::listAll($cid, $condition, $pager->getItemsPerPage(), $pager->getStart()); $friends = Model\Contact\Relation::listAll($cid, $condition, $pager->getItemsPerPage(), $pager->getStart());
$title = DI::l10n()->tt('Contact (%s)', 'Contacts (%s)', $total); $title = $this->tt('Contact (%s)', 'Contacts (%s)', $total);
} }
$o = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_CONTACTS); $o = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_CONTACTS);
$tabs = self::getContactFilterTabs('contact/' . $cid, $type, true); $tabs = self::getContactFilterTabs('contact/' . $cid, $type, true);
$contacts = array_map([Module\Contact::class, 'getContactTemplateVars'], $friends); // Contact list is obtained from the visited contact, but the contact display is visitor dependent
$contacts = array_map(
function ($contact) {
$contact = Model\Contact::selectFirst(
[],
['uri-id' => $contact['uri-id'], 'uid' => [0, $this->userSession->getLocalUserId()]],
['order' => ['uid' => 'DESC']]
);
return Module\Contact::getContactTemplateVars($contact);
},
$friends
);
$tpl = Renderer::getMarkupTemplate('profile/contacts.tpl'); $tpl = Renderer::getMarkupTemplate('profile/contacts.tpl');
$o .= Renderer::replaceMacros($tpl, [ $o .= Renderer::replaceMacros($tpl, [
@ -139,7 +168,7 @@ class Contacts extends BaseModule
'$paginate' => $pager->renderFull($total), '$paginate' => $pager->renderFull($total),
]); ]);
DI::page()['aside'] .= Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype); $this->page['aside'] .= Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype);
return $o; return $o;
} }

View file

@ -21,26 +21,45 @@
namespace Friendica\Module\Contact; namespace Friendica\Module\Contact;
use Friendica\App;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Psr\Log\LoggerInterface;
/** /**
* Asynchronous HTML fragment provider for frio contact hovercards * Asynchronous HTML fragment provider for frio contact hovercards
*/ */
class Hovercard extends BaseModule class Hovercard extends BaseModule
{ {
/** @var IManageConfigValues */
private $config;
/** @var IHandleUserSessions */
private $userSession;
public function __construct(IHandleUserSessions $userSession, IManageConfigValues $config, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->config = $config;
$this->userSession = $userSession;
}
protected function rawContent(array $request = []) protected function rawContent(array $request = [])
{ {
$contact_url = $_REQUEST['url'] ?? ''; $contact_url = $request['url'] ?? '';
// Get out if the system doesn't have public access allowed // Get out if the system doesn't have public access allowed
if (DI::config()->get('system', 'block_public') && !DI::userSession()->isAuthenticated()) { if ($this->config->get('system', 'block_public') && !$this->userSession->isAuthenticated()) {
throw new HTTPException\ForbiddenException(); throw new HTTPException\ForbiddenException();
} }
@ -50,7 +69,7 @@ class Hovercard extends BaseModule
*/ */
if (strpos($contact_url, 'contact/') === 0 && preg_match('/(\d+)/', $contact_url, $matches)) { if (strpos($contact_url, 'contact/') === 0 && preg_match('/(\d+)/', $contact_url, $matches)) {
$remote_contact = Contact::selectFirst(['nurl'], ['id' => $matches[1]]); $remote_contact = Contact::selectFirst(['nurl'], ['id' => $matches[1]]);
$contact_url = $remote_contact['nurl'] ?? ''; $contact_url = $remote_contact['nurl'] ?? '';
} }
if (!$contact_url) { if (!$contact_url) {
@ -59,8 +78,8 @@ class Hovercard extends BaseModule
// Search for contact data // Search for contact data
// Look if the local user has got the contact // Look if the local user has got the contact
if (DI::userSession()->isAuthenticated()) { if ($this->userSession->isAuthenticated()) {
$contact = Contact::getByURLForUser($contact_url, DI::userSession()->getLocalUserId()); $contact = Contact::getByURLForUser($contact_url, $this->userSession->getLocalUserId());
} else { } else {
$contact = Contact::getByURL($contact_url, false); $contact = Contact::getByURL($contact_url, false);
} }
@ -70,15 +89,15 @@ class Hovercard extends BaseModule
} }
// Get the photo_menu - the menu if possible contact actions // Get the photo_menu - the menu if possible contact actions
if (DI::userSession()->isAuthenticated()) { if ($this->userSession->isAuthenticated()) {
$actions = Contact::photoMenu($contact); $actions = Contact::photoMenu($contact, $this->userSession->getLocalUserId());
} else { } else {
$actions = []; $actions = [];
} }
// Move the contact data to the profile array so we can deliver it to // Move the contact data to the profile array so we can deliver it to
$tpl = Renderer::getMarkupTemplate('hovercard.tpl'); $tpl = Renderer::getMarkupTemplate('hovercard.tpl');
$o = Renderer::replaceMacros($tpl, [ $o = Renderer::replaceMacros($tpl, [
'$profile' => [ '$profile' => [
'name' => $contact['name'], 'name' => $contact['name'],
'nick' => $contact['nick'], 'nick' => $contact['nick'],
@ -96,7 +115,6 @@ class Hovercard extends BaseModule
], ],
]); ]);
echo $o; System::httpExit($o);
System::exit();
} }
} }

View file

@ -21,51 +21,71 @@
namespace Friendica\Module\Profile; namespace Friendica\Module\Profile;
use Friendica\App;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Module; use Friendica\Module;
use Friendica\DI;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Module\BaseProfile; use Friendica\Module\BaseProfile;
use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
class Common extends BaseProfile class Common extends BaseProfile
{ {
/** @var IManageConfigValues */
private $config;
/** @var IHandleUserSessions */
private $userSession;
/** @var App */
private $app;
public function __construct(App $app, IHandleUserSessions $userSession, IManageConfigValues $config, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->config = $config;
$this->userSession = $userSession;
$this->app = $app;
}
protected function content(array $request = []): string protected function content(array $request = []): string
{ {
if (DI::config()->get('system', 'block_public') && !DI::userSession()->isAuthenticated()) { if ($this->config->get('system', 'block_public') && !$this->userSession->isAuthenticated()) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.')); throw new HTTPException\NotFoundException($this->t('User not found.'));
} }
$a = DI::app();
Nav::setSelected('home'); Nav::setSelected('home');
$nickname = $this->parameters['nickname']; $nickname = $this->parameters['nickname'];
$profile = Profile::load($a, $nickname); $profile = Profile::load($this->app, $nickname);
if (empty($profile)) { if (empty($profile)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.')); throw new HTTPException\NotFoundException($this->t('User not found.'));
} }
if (!empty($profile['hide-friends'])) { if (!empty($profile['hide-friends'])) {
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.')); throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
} }
$displayCommonTab = DI::userSession()->isAuthenticated() && $profile['uid'] != DI::userSession()->getLocalUserId(); $displayCommonTab = $this->userSession->isAuthenticated() && $profile['uid'] != $this->userSession->getLocalUserId();
if (!$displayCommonTab) { if (!$displayCommonTab) {
$a->redirect('profile/' . $nickname . '/contacts'); $this->baseUrl->redirect('profile/' . $nickname . '/contacts');
}; };
$o = self::getTabsHTML('contacts', false, $profile['nickname'], $profile['hide-friends']); $o = self::getTabsHTML('contacts', false, $profile['nickname'], $profile['hide-friends']);
$tabs = self::getContactFilterTabs('profile/' . $nickname, 'common', $displayCommonTab); $tabs = self::getContactFilterTabs('profile/' . $nickname, 'common', $displayCommonTab);
$sourceId = Contact::getIdForURL(Profile::getMyURL()); $sourceId = Contact::getIdForURL($this->userSession->getMyUrl());
$targetId = Contact::getPublicIdByUserId($profile['uid']); $targetId = Contact::getPublicIdByUserId($profile['uid']);
$condition = [ $condition = [
@ -76,14 +96,25 @@ class Common extends BaseProfile
$total = Contact\Relation::countCommon($sourceId, $targetId, $condition); $total = Contact\Relation::countCommon($sourceId, $targetId, $condition);
$pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 30); $pager = new Pager($this->l10n, $this->args->getQueryString(), 30);
$commonFollows = Contact\Relation::listCommon($sourceId, $targetId, $condition, $pager->getItemsPerPage(), $pager->getStart()); $commonFollows = Contact\Relation::listCommon($sourceId, $targetId, $condition, $pager->getItemsPerPage(), $pager->getStart());
$contacts = array_map([Module\Contact::class, 'getContactTemplateVars'], $commonFollows); // Contact list is obtained from the visited profile user, but the contact display is visitor dependent
$contacts = array_map(
function ($contact) {
$contact = Contact::selectFirst(
[],
['uri-id' => $contact['uri-id'], 'uid' => [0, $this->userSession->getLocalUserId()]],
['order' => ['uid' => 'DESC']]
);
return Module\Contact::getContactTemplateVars($contact);
},
$commonFollows
);
$title = DI::l10n()->tt('Common contact (%s)', 'Common contacts (%s)', $total); $title = $this->tt('Common contact (%s)', 'Common contacts (%s)', $total);
$desc = DI::l10n()->t( $desc = $this->t(
'Both <strong>%s</strong> and yourself have publicly interacted with these contacts (follow, comment or likes on public posts).', 'Both <strong>%s</strong> and yourself have publicly interacted with these contacts (follow, comment or likes on public posts).',
htmlentities($profile['name'], ENT_COMPAT, 'UTF-8') htmlentities($profile['name'], ENT_COMPAT, 'UTF-8')
); );
@ -94,7 +125,7 @@ class Common extends BaseProfile
'$desc' => $desc, '$desc' => $desc,
'$tabs' => $tabs, '$tabs' => $tabs,
'$noresult_label' => DI::l10n()->t('No common contacts.'), '$noresult_label' => $this->t('No common contacts.'),
'$contacts' => $contacts, '$contacts' => $contacts,
'$paginate' => $pager->renderFull($total), '$paginate' => $pager->renderFull($total),

View file

@ -21,45 +21,68 @@
namespace Friendica\Module\Profile; namespace Friendica\Module\Profile;
use Friendica\App;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Database\DBA; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\DI; use Friendica\Database\Database;
use Friendica\Model; use Friendica\Model;
use Friendica\Module; use Friendica\Module;
use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Util\Profiler;
use Psr\Log\LoggerInterface;
class Contacts extends Module\BaseProfile class Contacts extends Module\BaseProfile
{ {
/** @var IManageConfigValues */
private $config;
/** @var IHandleUserSessions */
private $userSession;
/** @var App */
private $app;
/** @var Database */
private $database;
public function __construct(Database $database, App $app, IHandleUserSessions $userSession, IManageConfigValues $config, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
{
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->config = $config;
$this->userSession = $userSession;
$this->app = $app;
$this->database = $database;
}
protected function content(array $request = []): string protected function content(array $request = []): string
{ {
if (DI::config()->get('system', 'block_public') && !DI::userSession()->isAuthenticated()) { if ($this->config->get('system', 'block_public') && !$this->userSession->isAuthenticated()) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.')); throw new HTTPException\NotFoundException($this->t('User not found.'));
} }
$a = DI::app();
$nickname = $this->parameters['nickname']; $nickname = $this->parameters['nickname'];
$type = $this->parameters['type'] ?? 'all'; $type = $this->parameters['type'] ?? 'all';
$profile = Model\Profile::load($a, $nickname); $profile = Model\Profile::load($this->app, $nickname);
if (empty($profile)) { if (empty($profile)) {
throw new HTTPException\NotFoundException(DI::l10n()->t('User not found.')); throw new HTTPException\NotFoundException($this->t('User not found.'));
} }
$is_owner = $profile['uid'] == DI::userSession()->getLocalUserId(); $is_owner = $profile['uid'] == $this->userSession->getLocalUserId();
if ($profile['hide-friends'] && !$is_owner) { if ($profile['hide-friends'] && !$is_owner) {
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.')); throw new HTTPException\ForbiddenException($this->t('Permission denied.'));
} }
Nav::setSelected('home'); Nav::setSelected('home');
$o = self::getTabsHTML('contacts', $is_owner, $profile['nickname'], $profile['hide-friends']); $o = self::getTabsHTML('contacts', $is_owner, $profile['nickname'], $profile['hide-friends']);
$tabs = self::getContactFilterTabs('profile/' . $nickname, $type, DI::userSession()->isAuthenticated() && $profile['uid'] != DI::userSession()->getLocalUserId()); $tabs = self::getContactFilterTabs('profile/' . $nickname, $type, $this->userSession->isAuthenticated() && $profile['uid'] != $this->userSession->getLocalUserId());
$condition = [ $condition = [
'uid' => $profile['uid'], 'uid' => $profile['uid'],
@ -73,50 +96,64 @@ class Contacts extends Module\BaseProfile
]; ];
switch ($type) { switch ($type) {
case 'followers': $condition['rel'] = [Model\Contact::FOLLOWER, Model\Contact::FRIEND]; break; case 'followers':
case 'following': $condition['rel'] = [Model\Contact::SHARING, Model\Contact::FRIEND]; break; $condition['rel'] = [Model\Contact::FOLLOWER, Model\Contact::FRIEND];
case 'mutuals': $condition['rel'] = Model\Contact::FRIEND; break; break;
case 'following':
$condition['rel'] = [Model\Contact::SHARING, Model\Contact::FRIEND];
break;
case 'mutuals':
$condition['rel'] = Model\Contact::FRIEND;
break;
} }
$total = DBA::count('contact', $condition); $total = $this->database->count('contact', $condition);
$pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 30); $pager = new Pager($this->l10n, $this->args->getQueryString(), 30);
$params = ['order' => ['name' => false], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]]; $params = ['order' => ['name' => false], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]];
// Contact list is obtained from the visited profile user, but the contact display is visitor dependent
$contacts = array_map( $contacts = array_map(
[Module\Contact::class, 'getContactTemplateVars'], function ($contact) {
Model\Contact::selectToArray([], $condition, $params) $contact = Model\Contact::selectFirst(
[],
['uri-id' => $contact['uri-id'], 'uid' => [0, $this->userSession->getLocalUserId()]],
['order' => ['uid' => 'DESC']]
);
return Module\Contact::getContactTemplateVars($contact);
},
Model\Contact::selectToArray(['uri-id'], $condition, $params)
); );
$desc = ''; $desc = '';
switch ($type) { switch ($type) {
case 'followers': case 'followers':
$title = DI::l10n()->tt('Follower (%s)', 'Followers (%s)', $total); $title = $this->tt('Follower (%s)', 'Followers (%s)', $total);
break; break;
case 'following': case 'following':
$title = DI::l10n()->tt('Following (%s)', 'Following (%s)', $total); $title = $this->tt('Following (%s)', 'Following (%s)', $total);
break; break;
case 'mutuals': case 'mutuals':
$title = DI::l10n()->tt('Mutual friend (%s)', 'Mutual friends (%s)', $total); $title = $this->tt('Mutual friend (%s)', 'Mutual friends (%s)', $total);
$desc = DI::l10n()->t( $desc = $this->t(
'These contacts both follow and are followed by <strong>%s</strong>.', 'These contacts both follow and are followed by <strong>%s</strong>.',
htmlentities($profile['name'], ENT_COMPAT, 'UTF-8') htmlentities($profile['name'], ENT_COMPAT, 'UTF-8')
); );
break; break;
case 'all': case 'all':
default: default:
$title = DI::l10n()->tt('Contact (%s)', 'Contacts (%s)', $total); $title = $this->tt('Contact (%s)', 'Contacts (%s)', $total);
break; break;
} }
$tpl = Renderer::getMarkupTemplate('profile/contacts.tpl'); $tpl = Renderer::getMarkupTemplate('profile/contacts.tpl');
$o .= Renderer::replaceMacros($tpl, [ $o .= Renderer::replaceMacros($tpl, [
'$title' => $title, '$title' => $title,
'$desc' => $desc, '$desc' => $desc,
'$tabs' => $tabs, '$tabs' => $tabs,
'$noresult_label' => DI::l10n()->t('No contacts.'), '$noresult_label' => $this->t('No contacts.'),
'$contacts' => $contacts, '$contacts' => $contacts,
'$paginate' => $pager->renderFull($total), '$paginate' => $pager->renderFull($total),