Merge pull request #9314 from annando/suggestions
New function for contact suggestions
This commit is contained in:
		
				commit
				
					
						2bfd9851d3
					
				
			
		
					 6 changed files with 63 additions and 153 deletions
				
			
		| 
						 | 
				
			
			@ -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'
 | 
			
		||||
		]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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->evaluate('string(dfrn:url[1]/text())', $suggestion);
 | 
			
		||||
		$cid = Contact::getIdForURL($url);
 | 
			
		||||
		$note = $xpath->evaluate('string(dfrn:note[1]/text())', $suggestion);
 | 
			
		||||
 | 
			
		||||
		// 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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue