X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=src%2FModel%2FContact.php;h=934c628d8e276204caf4319d0378af1afc9a1fb8;hb=3a4be3d5f468d5bedb56199becdaba87fd543f94;hp=61b4c9d05a9855d07c92b59bd5a4f249cfca4c8d;hpb=dcf6926a08f9b5791dbf3a3d0ba5bdd40631bed0;p=friendica.git diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 61b4c9d05a..934c628d8e 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -21,6 +21,8 @@ namespace Friendica\Model; +use DOMDocument; +use DOMXPath; use Friendica\App\BaseURL; use Friendica\Content\Pager; use Friendica\Core\Hook; @@ -88,7 +90,7 @@ class Contact /** * Account types * - * TYPE_UNKNOWN - the account has been imported from gcontact where this is the default type value + * TYPE_UNKNOWN - unknown type * * TYPE_PERSON - the account belongs to a person * Associated page types: PAGE_NORMAL, PAGE_SOAPBOX, PAGE_FREELOVE @@ -304,7 +306,7 @@ class Contact */ public static function isFollower($cid, $uid) { - if (self::isBlockedByUser($cid, $uid)) { + if (Contact\User::isBlocked($cid, $uid)) { return false; } @@ -350,7 +352,7 @@ class Contact */ public static function isSharing($cid, $uid) { - if (self::isBlockedByUser($cid, $uid)) { + if (Contact\User::isBlocked($cid, $uid)) { return false; } @@ -535,179 +537,6 @@ class Contact } } - /** - * Block contact id for user id - * - * @param int $cid Either public contact id or user's contact id - * @param int $uid User ID - * @param boolean $blocked Is the contact blocked or unblocked? - * @throws \Exception - */ - public static function setBlockedForUser($cid, $uid, $blocked) - { - $cdata = self::getPublicAndUserContacID($cid, $uid); - if (empty($cdata)) { - return; - } - - if ($cdata['user'] != 0) { - DBA::update('contact', ['blocked' => $blocked], ['id' => $cdata['user'], 'pending' => false]); - } - - DBA::update('user-contact', ['blocked' => $blocked], ['cid' => $cdata['public'], 'uid' => $uid], true); - } - - /** - * Returns "block" state for contact id and user id - * - * @param int $cid Either public contact id or user's contact id - * @param int $uid User ID - * - * @return boolean is the contact id blocked for the given user? - * @throws \Exception - */ - public static function isBlockedByUser($cid, $uid) - { - $cdata = self::getPublicAndUserContacID($cid, $uid); - if (empty($cdata)) { - return; - } - - $public_blocked = false; - - if (!empty($cdata['public'])) { - $public_contact = DBA::selectFirst('user-contact', ['blocked'], ['cid' => $cdata['public'], 'uid' => $uid]); - if (DBA::isResult($public_contact)) { - $public_blocked = $public_contact['blocked']; - } - } - - $user_blocked = $public_blocked; - - if (!empty($cdata['user'])) { - $user_contact = DBA::selectFirst('contact', ['blocked'], ['id' => $cdata['user'], 'pending' => false]); - if (DBA::isResult($user_contact)) { - $user_blocked = $user_contact['blocked']; - } - } - - if ($user_blocked != $public_blocked) { - DBA::update('user-contact', ['blocked' => $user_blocked], ['cid' => $cdata['public'], 'uid' => $uid], true); - } - - return $user_blocked; - } - - /** - * Ignore contact id for user id - * - * @param int $cid Either public contact id or user's contact id - * @param int $uid User ID - * @param boolean $ignored Is the contact ignored or unignored? - * @throws \Exception - */ - public static function setIgnoredForUser($cid, $uid, $ignored) - { - $cdata = self::getPublicAndUserContacID($cid, $uid); - if (empty($cdata)) { - return; - } - - if ($cdata['user'] != 0) { - DBA::update('contact', ['readonly' => $ignored], ['id' => $cdata['user'], 'pending' => false]); - } - - DBA::update('user-contact', ['ignored' => $ignored], ['cid' => $cdata['public'], 'uid' => $uid], true); - } - - /** - * Returns "ignore" state for contact id and user id - * - * @param int $cid Either public contact id or user's contact id - * @param int $uid User ID - * - * @return boolean is the contact id ignored for the given user? - * @throws \Exception - */ - public static function isIgnoredByUser($cid, $uid) - { - $cdata = self::getPublicAndUserContacID($cid, $uid); - if (empty($cdata)) { - return; - } - - $public_ignored = false; - - if (!empty($cdata['public'])) { - $public_contact = DBA::selectFirst('user-contact', ['ignored'], ['cid' => $cdata['public'], 'uid' => $uid]); - if (DBA::isResult($public_contact)) { - $public_ignored = $public_contact['ignored']; - } - } - - $user_ignored = $public_ignored; - - if (!empty($cdata['user'])) { - $user_contact = DBA::selectFirst('contact', ['readonly'], ['id' => $cdata['user'], 'pending' => false]); - if (DBA::isResult($user_contact)) { - $user_ignored = $user_contact['readonly']; - } - } - - if ($user_ignored != $public_ignored) { - DBA::update('user-contact', ['ignored' => $user_ignored], ['cid' => $cdata['public'], 'uid' => $uid], true); - } - - return $user_ignored; - } - - /** - * Set "collapsed" for contact id and user id - * - * @param int $cid Either public contact id or user's contact id - * @param int $uid User ID - * @param boolean $collapsed are the contact's posts collapsed or uncollapsed? - * @throws \Exception - */ - public static function setCollapsedForUser($cid, $uid, $collapsed) - { - $cdata = self::getPublicAndUserContacID($cid, $uid); - if (empty($cdata)) { - return; - } - - DBA::update('user-contact', ['collapsed' => $collapsed], ['cid' => $cdata['public'], 'uid' => $uid], true); - } - - /** - * Returns "collapsed" state for contact id and user id - * - * @param int $cid Either public contact id or user's contact id - * @param int $uid User ID - * - * @return boolean is the contact id blocked for the given user? - * @throws HTTPException\InternalServerErrorException - * @throws \ImagickException - */ - public static function isCollapsedByUser($cid, $uid) - { - $cdata = self::getPublicAndUserContacID($cid, $uid); - if (empty($cdata)) { - return; - } - - $collapsed = false; - - if (!empty($cdata['public'])) { - $public_contact = DBA::selectFirst('user-contact', ['collapsed'], ['cid' => $cdata['public'], 'uid' => $uid]); - if (DBA::isResult($public_contact)) { - $collapsed = $public_contact['collapsed']; - } - } - - return $collapsed; - } - /** * Returns a list of contacts belonging in a group * @@ -1021,7 +850,6 @@ class Contact */ DBA::update('contact', ['archive' => true], ['id' => $contact['id']]); DBA::update('contact', ['archive' => true], ['nurl' => Strings::normaliseLink($contact['url']), 'self' => false]); - GContact::updateFromPublicContactURL($contact['url']); } } } @@ -1066,7 +894,6 @@ class Contact $fields = ['failed' => false, 'term-date' => DBA::NULL_DATETIME, 'archive' => false]; DBA::update('contact', $fields, ['id' => $contact['id']]); DBA::update('contact', $fields, ['nurl' => Strings::normaliseLink($contact['url']), 'self' => false]); - GContact::updateFromPublicContactURL($contact['url']); } /** @@ -1269,12 +1096,8 @@ class Contact $fields = ['url', 'addr', 'alias', 'notify', 'name', 'nick', 'photo', 'keywords', 'location', 'about', 'network']; - $data = DBA::selectFirst('gcontact', $fields, ['nurl' => Strings::normaliseLink($url)]); - - if (!DBA::isResult($data)) { - $condition = ['alias' => [$url, Strings::normaliseLink($url), $ssl_url]]; - $data = DBA::selectFirst('contact', $fields, $condition); - } + $condition = ['alias' => [$url, Strings::normaliseLink($url), $ssl_url]]; + $data = DBA::selectFirst('contact', $fields, $condition); if (DBA::isResult($data)) { $data["pubkey"] = ''; @@ -1395,11 +1218,11 @@ class Contact } // Take the default values when probing failed - if (!empty($default) && !in_array($data["network"], array_merge(Protocol::NATIVE_SUPPORT, [Protocol::PUMPIO]))) { + if (!empty($default) && (empty($data['network']) || !in_array($data["network"], array_merge(Protocol::NATIVE_SUPPORT, [Protocol::PUMPIO])))) { $data = array_merge($data, $default); } - if (empty($data) || ($data['network'] == Protocol::PHANTOM)) { + if (empty($data['network']) || ($data['network'] == Protocol::PHANTOM)) { Logger::info('No valid network found', ['url' => $url, 'data' => $data, 'callstack' => System::callstack(20)]); return 0; } @@ -1412,6 +1235,9 @@ class Contact $data['gsid'] = GServer::getID($data['baseurl']); } + $data['last-item'] = Probe::getLastUpdate($data); + Logger::info('Fetched last item', ['url' => $data['url'], 'last-item' => $data['last-item']]); + if (!$contact_id && !empty($data['alias']) && ($data['alias'] != $data['url']) && !$in_loop) { $contact_id = self::getIdForURL($data["alias"], $uid, false, $default, true); } @@ -1441,6 +1267,7 @@ class Contact 'poco' => $data['poco'] ?? '', 'baseurl' => $data['baseurl'] ?? '', 'gsid' => $data['gsid'] ?? null, + 'last-item' => $data['last-item'] ?: DBA::NULL_DATETIME, 'name-date' => DateTimeFormat::utcNow(), 'uri-date' => DateTimeFormat::utcNow(), 'avatar-date' => DateTimeFormat::utcNow(), @@ -1485,7 +1312,7 @@ class Contact self::updateFromProbe($contact_id, '', false); } } else { - $fields = ['url', 'nurl', 'addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'avatar-date', 'baseurl', 'gsid']; + $fields = ['url', 'nurl', 'addr', 'alias', 'name', 'nick', 'keywords', 'location', 'about', 'avatar-date', 'baseurl', 'gsid', 'last-item']; $contact = DBA::selectFirst('contact', $fields, ['id' => $contact_id]); // This condition should always be true @@ -1506,6 +1333,10 @@ class Contact $updated[$field] = ($data[$field] ?? '') ?: $contact[$field]; } + if ($contact['last-item'] < $data['last-item']) { + $updated['last-item'] = $data['last-item']; + } + if (($updated['addr'] != $contact['addr']) || (!empty($data['alias']) && ($data['alias'] != $contact['alias']))) { $updated['uri-date'] = DateTimeFormat::utcNow(); } @@ -1706,7 +1537,6 @@ class Contact // There are several fields that indicate that the contact or user is a forum // "page-flags" is a field in the user table, // "forum" and "prv" are used in the contact table. They stand for User::PAGE_FLAGS_COMMUNITY and User::PAGE_FLAGS_PRVGROUP. - // "community" is used in the gcontact table and is true if the contact is User::PAGE_FLAGS_COMMUNITY or User::PAGE_FLAGS_PRVGROUP. if ((isset($contact['page-flags']) && (intval($contact['page-flags']) == User::PAGE_FLAGS_COMMUNITY)) || (isset($contact['page-flags']) && (intval($contact['page-flags']) == User::PAGE_FLAGS_PRVGROUP)) || (isset($contact['forum']) && intval($contact['forum'])) @@ -1994,9 +1824,6 @@ class Contact return; } - // Update the corresponding gcontact entry - GContact::updateFromPublicContactID($id); - // Archive or unarchive the contact. We only need to do this for the public contact. // The archive/unarchive function will update the personal contacts by themselves. $contact = DBA::selectFirst('contact', [], ['id' => $id]); @@ -2132,7 +1959,7 @@ class Contact return false; } - if (ContactRelation::isDiscoverable($ret['url'])) { + if (Contact\Relation::isDiscoverable($ret['url'])) { Worker::add(PRIORITY_LOW, 'ContactDiscovery', $ret['url']); } @@ -2155,11 +1982,6 @@ class Contact $new_pubkey = $ret['pubkey']; - // Update the gcontact entry - if ($uid == 0) { - GContact::updateFromPublicContactID($id); - } - $update = false; // make sure to not overwrite existing values with blank entries except some technical fields @@ -2601,7 +2423,7 @@ class Contact // Contact is blocked at user-level if (!empty($contact['id']) && !empty($importer['id']) && - self::isBlockedByUser($contact['id'], $importer['id'])) { + Contact\User::isBlocked($contact['id'], $importer['id'])) { return false; } @@ -2966,106 +2788,49 @@ class Contact } /** - * @param int $uid user - * @param int $start optional, default 0 - * @param int $limit optional, default 80 - * @return array + * Add public contacts from an array + * + * @param array $urls + * @return array result "count", "added" and "updated" */ - static public function getSuggestions(int $uid, int $start = 0, int $limit = 80) + public static function addByUrls(array $urls) { - $cid = self::getPublicIdByUserId($uid); - $totallimit = $start + $limit; - $contacts = []; - - Logger::info('Collecting suggestions', ['uid' => $uid, 'cid' => $cid, 'start' => $start, 'limit' => $limit]); - - $diaspora = DI::config()->get('system', 'diaspora_enabled') ? Protocol::DIASPORA : Protocol::ACTIVITYPUB; - $ostatus = !DI::config()->get('system', 'ostatus_disabled') ? Protocol::OSTATUS : Protocol::ACTIVITYPUB; - - // The query returns contacts where contacts interacted with whom the given user follows. - // Contacts who already are in the user's contact table are ignored. - $results = DBA::select('contact', [], - ["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` IN - (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ?) - AND NOT `cid` IN (SELECT `id` FROM `contact` WHERE `uid` = ? AND `nurl` IN - (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?)))) - AND NOT `hidden` AND `network` IN (?, ?, ?, ?)", - $cid, 0, $uid, Contact::FRIEND, Contact::SHARING, - Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus], - ['order' => ['last-item' => true], 'limit' => $totallimit] - ); - - while ($contact = DBA::fetch($results)) { - $contacts[$contact['id']] = $contact; - } - DBA::close($results); - - Logger::info('Contacts of contacts who are followed by the given user', ['uid' => $uid, 'cid' => $cid, 'count' => count($contacts)]); - - if (count($contacts) >= $totallimit) { - return array_slice($contacts, $start, $limit); - } - - // The query returns contacts where contacts interacted with whom also interacted with the given user. - // Contacts who already are in the user's contact table are ignored. - $results = DBA::select('contact', [], - ["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` IN - (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ?) - AND NOT `cid` IN (SELECT `id` FROM `contact` WHERE `uid` = ? AND `nurl` IN - (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?)))) - AND NOT `hidden` AND `network` IN (?, ?, ?, ?)", - $cid, 0, $uid, Contact::FRIEND, Contact::SHARING, - Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus], - ['order' => ['last-item' => true], 'limit' => $totallimit] - ); + $added = 0; + $updated = 0; + $count = 0; - while ($contact = DBA::fetch($results)) { - $contacts[$contact['id']] = $contact; - } - DBA::close($results); - - Logger::info('Contacts of contacts who are following the given user', ['uid' => $uid, 'cid' => $cid, 'count' => count($contacts)]); - - if (count($contacts) >= $totallimit) { - return array_slice($contacts, $start, $limit); - } - - // The query returns contacts that follow the given user but aren't followed by that user. - $results = DBA::select('contact', [], - ["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` = ?) - AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?)", - $uid, Contact::FOLLOWER, 0, - Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus], - ['order' => ['last-item' => true], 'limit' => $totallimit] - ); - - while ($contact = DBA::fetch($results)) { - $contacts[$contact['id']] = $contact; + foreach ($urls as $url) { + $contact = Contact::getByURL($url, false, ['id']); + if (empty($contact['id'])) { + Worker::add(PRIORITY_LOW, 'AddContact', 0, $url); + ++$added; + } else { + Worker::add(PRIORITY_LOW, 'UpdateContact', $contact['id']); + ++$updated; + } + ++$count; } - DBA::close($results); - Logger::info('Followers that are not followed by the given user', ['uid' => $uid, 'cid' => $cid, 'count' => count($contacts)]); - - if (count($contacts) >= $totallimit) { - return array_slice($contacts, $start, $limit); - } + return ['count' => $count, 'added' => $added, 'updated' => $updated]; + } - // The query returns any contact that isn't followed by that user. - $results = DBA::select('contact', [], - ["NOT `nurl` IN (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?)) - AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?)", - $uid, Contact::FRIEND, Contact::SHARING, 0, - Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus], - ['order' => ['last-item' => true], 'limit' => $totallimit] - ); + /** + * Returns a random, global contact of the current node + * + * @return string The profile URL + * @throws Exception + */ + public static function getRandomUrl() + { + $r = DBA::selectFirst('contact', ['url'], [ + "`uid` = ? AND `network` = ? AND NOT `failed` AND `last-item` > ?", + 0, Protocol::DFRN, DateTimeFormat::utc('now - 1 month'), + ], ['order' => ['RAND()']]); - while ($contact = DBA::fetch($results)) { - $contacts[$contact['id']] = $contact; + if (DBA::isResult($r)) { + return $r['url']; } - DBA::close($results); - - Logger::info('Any contact', ['uid' => $uid, 'cid' => $cid, 'count' => count($contacts)]); - return array_slice($contacts, $start, $limit); + return ''; } }