From fb50a43ac04f57105892e6fc7804915829300e90 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Sep 2020 21:33:40 +0000 Subject: [PATCH 1/2] New function for contact suggestions --- mod/ping.php | 8 +- src/Model/FContact.php | 67 ++++++-------- src/Model/Introduction.php | 21 ++--- src/Module/Notifications/Introductions.php | 25 +++--- src/Protocol/DFRN.php | 88 ++----------------- .../frio/templates/notifications/intros.tpl | 7 +- 6 files changed, 63 insertions(+), 153 deletions(-) diff --git a/mod/ping.php b/mod/ping.php index 7c8d6c846d..7e426d1d66 100644 --- a/mod/ping.php +++ b/mod/ping.php @@ -177,15 +177,15 @@ function ping_init(App $a) $intros1 = q( "SELECT `intro`.`id`, `intro`.`datetime`, `fcontact`.`name`, `fcontact`.`url`, `fcontact`.`photo` - FROM `intro` LEFT JOIN `fcontact` ON `intro`.`fid` = `fcontact`.`id` - WHERE `intro`.`uid` = %d AND `intro`.`blocked` = 0 AND `intro`.`ignore` = 0 AND `intro`.`fid` != 0", + FROM `intro` INNER JOIN `fcontact` ON `intro`.`fid` = `fcontact`.`id` + WHERE `intro`.`uid` = %d AND NOT `intro`.`blocked` AND NOT `intro`.`ignore` AND `intro`.`fid` != 0", intval(local_user()) ); $intros2 = q( "SELECT `intro`.`id`, `intro`.`datetime`, `contact`.`name`, `contact`.`url`, `contact`.`photo` - FROM `intro` LEFT JOIN `contact` ON `intro`.`contact-id` = `contact`.`id` - WHERE `intro`.`uid` = %d AND `intro`.`blocked` = 0 AND `intro`.`ignore` = 0 AND `intro`.`contact-id` != 0", + FROM `intro` INNER JOIN `contact` ON `intro`.`contact-id` = `contact`.`id` + WHERE `intro`.`uid` = %d AND NOT `intro`.`blocked` AND NOT `intro`.`ignore` AND `intro`.`contact-id` != 0 AND `intro`.`fid` = 0", intval(local_user()) ); diff --git a/src/Model/FContact.php b/src/Model/FContact.php index f611000934..2be8aa906c 100644 --- a/src/Model/FContact.php +++ b/src/Model/FContact.php @@ -43,12 +43,12 @@ class FContact * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getByURL($handle, $update = null) + public static function getByURL($handle, $update = null, $network = Protocol::DIASPORA) { - $person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'addr' => $handle]); + $person = DBA::selectFirst('fcontact', [], ['network' => $network, 'addr' => $handle]); if (!DBA::isResult($person)) { $urls = [$handle, str_replace('http://', 'https://', $handle), Strings::normaliseLink($handle)]; - $person = DBA::selectFirst('fcontact', [], ['network' => Protocol::DIASPORA, 'url' => $urls]); + $person = DBA::selectFirst('fcontact', [], ['network' => $network, 'url' => $urls]); } if (DBA::isResult($person)) { @@ -73,14 +73,14 @@ class FContact if ($update) { Logger::info('create or refresh', ['handle' => $handle]); - $r = Probe::uri($handle, Protocol::DIASPORA); + $r = Probe::uri($handle, $network); // Note that Friendica contacts will return a "Diaspora person" // if Diaspora connectivity is enabled on their server - if ($r && ($r["network"] === Protocol::DIASPORA)) { + if ($r && ($r["network"] === $network)) { self::updateFContact($r); - $person = self::getByURL($handle, false); + $person = self::getByURL($handle, false, $network); } } @@ -135,56 +135,45 @@ class FContact } /** - * Add suggestions for a given contact + * Suggest a given contact to a given user from a given contact * * @param integer $uid * @param integer $cid + * @param integer $from_cid * @return bool Was the adding successful? */ - public static function addSuggestion(int $uid, int $cid) + public static function addSuggestion(int $uid, int $cid, int $from_cid, string $note = '') { $owner = User::getOwnerDataById($uid); $contact = Contact::getById($cid); + $from_contact = Contact::getById($from_cid); if (DBA::exists('contact', ['nurl' => Strings::normaliseLink($contact['url']), 'uid' => $uid])) { return false; } + $fcontact = self::getByURL($contact['url'], null, $contact['network']); + if (empty($fcontact)) { + Logger::warning('FContact had not been found', ['fcontact' => $contact['url']]); + return false; + } + + $fid = $fcontact['id']; + + // Quit if we already have an introduction for this person + if (DBA::exists('intro', ['uid' => $uid, 'fid' => $fid])) { + return false; + } + $suggest = []; $suggest['uid'] = $uid; - $suggest['cid'] = $contact['id']; + $suggest['cid'] = $from_cid; $suggest['url'] = $contact['url']; $suggest['name'] = $contact['name']; $suggest['photo'] = $contact['photo']; $suggest['request'] = $contact['request']; $suggest['title'] = ''; - $suggest['body'] = ''; - - // Do we already have an fcontact record for this person? - $fid = 0; - $fcontact = DBA::selectFirst('fcontact', ['id'], ['url' => $suggest['url']]); - if (DBA::isResult($fcontact)) { - $fid = $fcontact['id']; - - $fields = ['name' => $suggest['name'], 'photo' => $suggest['photo'], 'request' => $suggest['request']]; - DBA::update('fcontact', $fields, ['id' => $fid]); - - // Quit if we already have an introduction for this person - if (DBA::exists('intro', ['uid' => $suggest['uid'], 'fid' => $fid])) { - return false; - } - } - - if (empty($fid)) { - $fields = ['name' => $suggest['name'], 'url' => $suggest['url'], - 'photo' => $suggest['photo'], 'request' => $suggest['request']]; - DBA::insert('fcontact', $fields); - $fid = DBA::lastInsertId(); - if (empty($fid)) { - Logger::warning('FContact had not been created', ['fcontact' => $fields]); - return false; - } - } + $suggest['body'] = $note; $hash = Strings::getRandomHex(); $fields = ['uid' => $suggest['uid'], 'fid' => $fid, 'contact-id' => $suggest['cid'], @@ -200,9 +189,9 @@ class FContact 'uid' => $owner['uid'], 'item' => $suggest, 'link' => DI::baseUrl().'/notifications/intros', - 'source_name' => $contact['name'], - 'source_link' => $contact['url'], - 'source_photo' => $contact['photo'], + 'source_name' => $from_contact['name'], + 'source_link' => $from_contact['url'], + 'source_photo' => $from_contact['photo'], 'verb' => Activity::REQ_FRIEND, 'otype' => 'intro' ]); diff --git a/src/Model/Introduction.php b/src/Model/Introduction.php index 8b939aa2a5..aab4a9a8e4 100644 --- a/src/Model/Introduction.php +++ b/src/Model/Introduction.php @@ -164,19 +164,16 @@ class Introduction extends BaseModel } $contact = Contact::selectFirst([], ['id' => $this->{'contact-id'}, 'uid' => $this->uid]); + if (!empty($contact)) { + if (!empty($contact['protocol'])) { + $protocol = $contact['protocol']; + } else { + $protocol = $contact['network']; + } - if (!$contact) { - throw new HTTPException\NotFoundException('Contact record not found.'); - } - - if (!empty($contact['protocol'])) { - $protocol = $contact['protocol']; - } else { - $protocol = $contact['network']; - } - - if ($protocol == Protocol::ACTIVITYPUB) { - ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $contact['uid']); + if ($protocol == Protocol::ACTIVITYPUB) { + ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $contact['uid']); + } } return $this->intro->delete($this); diff --git a/src/Module/Notifications/Introductions.php b/src/Module/Notifications/Introductions.php index eeb8ce02f7..bd0445b07a 100644 --- a/src/Module/Notifications/Introductions.php +++ b/src/Module/Notifications/Introductions.php @@ -27,6 +27,7 @@ use Friendica\Core\Protocol; use Friendica\Core\Renderer; use Friendica\Database\DBA; use Friendica\DI; +use Friendica\Model\User; use Friendica\Module\BaseNotifications; use Friendica\Object\Notification\Introduction; @@ -76,18 +77,13 @@ class Introductions extends BaseNotifications 'text' => (!$all ? DI::l10n()->t('Show Ignored Requests') : DI::l10n()->t('Hide Ignored Requests')), ]; + $owner = User::getOwnerDataById(local_user()); + // Loop through all introduction notifications.This creates an array with the output html for each // introduction /** @var Introduction $notification */ foreach ($notifications['notifications'] as $notification) { - $helptext = DI::l10n()->t('Shall your connection be bidirectional or not?'); - $helptext2 = DI::l10n()->t('Accepting %s as a friend allows %s to subscribe to your posts, and you will also receive updates from them in your news feed.', $notification->getName(), $notification->getName()); - $helptext3 = DI::l10n()->t('Accepting %s as a subscriber allows them to subscribe to your posts, but you will not receive updates from them in your news feed.', $notification->getName()); - - $friend = ['duplex', DI::l10n()->t('Friend'), '1', $helptext2, true]; - $follower = ['duplex', DI::l10n()->t('Subscriber'), '0', $helptext3, false]; - // There are two kind of introduction. Contacts suggested by other contacts and normal connection requests. // We have to distinguish between these two because they use different data. switch ($notification->getLabel()) { @@ -105,18 +101,14 @@ class Introductions extends BaseNotifications '$contact_id' => $notification->getContactId(), '$photo' => $notification->getPhoto(), '$fullname' => $notification->getName(), - '$lbl_connection_type' => $helptext, - '$friend' => $friend, - '$follower' => $follower, + '$dfrn_url' => $owner['url'], '$url' => $notification->getUrl(), '$zrl' => $notification->getZrl(), '$lbl_url' => DI::l10n()->t('Profile URL'), '$addr' => $notification->getAddr(), - '$hidden' => ['hidden', DI::l10n()->t('Hide this contact from others'), $notification->isHidden(), ''], - '$knowyou' => $notification->getKnowYou(), + '$action' => 'follow', '$approve' => DI::l10n()->t('Approve'), '$note' => $notification->getNote(), - '$request' => $notification->getRequest(), '$ignore' => DI::l10n()->t('Ignore'), '$discard' => DI::l10n()->t('Discard'), ]); @@ -132,6 +124,13 @@ class Introductions extends BaseNotifications $knowyou = ''; } + $helptext = DI::l10n()->t('Shall your connection be bidirectional or not?'); + $helptext2 = DI::l10n()->t('Accepting %s as a friend allows %s to subscribe to your posts, and you will also receive updates from them in your news feed.', $notification->getName(), $notification->getName()); + $helptext3 = DI::l10n()->t('Accepting %s as a subscriber allows them to subscribe to your posts, but you will not receive updates from them in your news feed.', $notification->getName()); + + $friend = ['duplex', DI::l10n()->t('Friend'), '1', $helptext2, true]; + $follower = ['duplex', DI::l10n()->t('Subscriber'), '0', $helptext3, false]; + $contact = DBA::selectFirst('contact', ['network', 'protocol'], ['id' => $notification->getContactId()]); if (($contact['network'] != Protocol::DFRN) || ($contact['protocol'] == Protocol::ACTIVITYPUB)) { diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 78843a3f16..cfbf12c784 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1793,91 +1793,13 @@ class DFRN */ private static function processSuggestion($xpath, $suggestion, $importer) { - Logger::log('Processing suggestions'); + Logger::notice('Processing suggestions'); - /// @TODO Rewrite this to one statement - $suggest = []; - $suggest['uid'] = $importer['importer_uid']; - $suggest['cid'] = $importer['id']; - $suggest['url'] = $xpath->query('dfrn:url/text()', $suggestion)->item(0)->nodeValue; - $suggest['name'] = $xpath->query('dfrn:name/text()', $suggestion)->item(0)->nodeValue; - $suggest['photo'] = $xpath->query('dfrn:photo/text()', $suggestion)->item(0)->nodeValue; - $suggest['request'] = $xpath->query('dfrn:request/text()', $suggestion)->item(0)->nodeValue; - $suggest['body'] = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue; + $url = $xpath->query('dfrn:url/text()', $suggestion)->item(0)->nodeValue; + $cid = Contact::getIdForURL($url); + $note = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue; - // Does our member already have a friend matching this description? - - /* - * The valid result means the friend we're about to send a friend - * suggestion already has them in their contact, which means no further - * action is required. - * - * @see https://github.com/friendica/friendica/pull/3254#discussion_r107315246 - */ - $condition = ['nurl' => Strings::normaliseLink($suggest['url']), 'uid' => $suggest['uid']]; - if (DBA::exists('contact', $condition)) { - return false; - } - // Do we already have an fcontact record for this person? - - $fid = 0; - $fcontact = DBA::selectFirst('fcontact', ['id'], ['url' => $suggest['url']]); - if (DBA::isResult($fcontact)) { - $fid = $fcontact['id']; - - // OK, we do. Do we already have an introduction for this person? - if (DBA::exists('intro', ['uid' => $suggest['uid'], 'fid' => $fid])) { - /* - * The valid result means the friend we're about to send a friend - * suggestion already has them in their contact, which means no further - * action is required. - * - * @see https://github.com/friendica/friendica/pull/3254#discussion_r107315246 - */ - return false; - } - } - - if (!$fid) { - $fields = ['name' => $suggest['name'], 'url' => $suggest['url'], - 'photo' => $suggest['photo'], 'request' => $suggest['request']]; - DBA::insert('fcontact', $fields); - $fid = DBA::lastInsertId(); - } - - /* - * If no record in fcontact is found, below INSERT statement will not - * link an introduction to it. - */ - if (empty($fid)) { - // Database record did not get created. Quietly give up. - exit(); - } - - $hash = Strings::getRandomHex(); - - $fields = ['uid' => $suggest['uid'], 'fid' => $fid, 'contact-id' => $suggest['cid'], - 'note' => $suggest['body'], 'hash' => $hash, 'datetime' => DateTimeFormat::utcNow(), 'blocked' => false]; - DBA::insert('intro', $fields); - - notification( - [ - 'type' => Type::SUGGEST, - 'notify_flags' => $importer['notify-flags'], - 'language' => $importer['language'], - 'to_name' => $importer['username'], - 'to_email' => $importer['email'], - 'uid' => $importer['importer_uid'], - 'item' => $suggest, - 'link' => DI::baseUrl().'/notifications/intros', - 'source_name' => $importer['name'], - 'source_link' => $importer['url'], - 'source_photo' => $importer['photo'], - 'verb' => Activity::REQ_FRIEND, - 'otype' => 'intro'] - ); - - return true; + return FContact::addSuggestion($importer['importer_uid'], $cid, $importer['id'], $note); } /** diff --git a/view/theme/frio/templates/notifications/intros.tpl b/view/theme/frio/templates/notifications/intros.tpl index 8271889aed..f46082915f 100644 --- a/view/theme/frio/templates/notifications/intros.tpl +++ b/view/theme/frio/templates/notifications/intros.tpl @@ -52,17 +52,20 @@

{{$fullname}}{{if $addr}} ({{$addr}}){{/if}}

+ {{if $type != "friend_suggestion"}} {{include file="field_checkbox.tpl" field=$hidden}}
{{include file="field_radio.tpl" field=$friend}} {{include file="field_radio.tpl" field=$follower}}
- - {{if $type != "friend_suggestion"}} + {{else}} + {{if $note}}
{{$note}}
{{/if}} + + {{/if}}
From 777ece84cfd8a32bfe457861d03af32da07d3983 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Tue, 29 Sep 2020 05:56:57 +0200 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Hypolite Petovan --- src/Protocol/DFRN.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index cfbf12c784..31e6173870 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1795,9 +1795,9 @@ class DFRN { Logger::notice('Processing suggestions'); - $url = $xpath->query('dfrn:url/text()', $suggestion)->item(0)->nodeValue; + $url = $xpath->evaluate('string(dfrn:url[1]/text())', $suggestion); $cid = Contact::getIdForURL($url); - $note = $xpath->query('dfrn:note/text()', $suggestion)->item(0)->nodeValue; + $note = $xpath->evaluate('string(dfrn:note[1]/text())', $suggestion); return FContact::addSuggestion($importer['importer_uid'], $cid, $importer['id'], $note); }