]> git.mxchange.org Git - friendica.git/blobdiff - src/Model/Contact.php
Merge pull request #10478 from annando/notice
[friendica.git] / src / Model / Contact.php
index dc784827866c87ef964b5476f252d90f267a8a6a..0184861c3c2d8403750bb075d5c69a03781cd43c 100644 (file)
@@ -185,6 +185,8 @@ class Contact
                        $fields['gsid'] = GServer::getID($fields['baseurl'], true);
                }
 
+               $fields['uri-id'] = ItemURI::getIdByURI($fields['url']);
+
                if (empty($fields['created'])) {
                        $fields['created'] = DateTimeFormat::utcNow();
                }
@@ -630,7 +632,7 @@ class Contact
        {
                $fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey',
                        'xmpp', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl', 'unsearchable',
-                       'photo', 'thumb', 'micro', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco'];
+                       'photo', 'thumb', 'micro', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco', 'network'];
                $self = DBA::selectFirst('contact', $fields, ['uid' => $uid, 'self' => true]);
                if (!DBA::isResult($self)) {
                        return false;
@@ -655,7 +657,7 @@ class Contact
                        'avatar-date' => $self['avatar-date'], 'location' => Profile::formatLocation($profile),
                        'about' => $profile['about'], 'keywords' => $profile['pub_keywords'],
                        'contact-type' => $user['account-type'], 'prvkey' => $user['prvkey'],
-                       'pubkey' => $user['pubkey'], 'xmpp' => $profile['xmpp']];
+                       'pubkey' => $user['pubkey'], 'xmpp' => $profile['xmpp'], 'network' => Protocol::DFRN];
 
                // it seems as if ported accounts can have wrong values, so we make sure that now everything is fine.
                $fields['url'] = DI::baseUrl() . '/profile/' . $user['nickname'];
@@ -1070,12 +1072,12 @@ class Contact
                        return 0;
                }
 
-               $contact = self::getByURL($url, false, ['id', 'network'], $uid);
+               $contact = self::getByURL($url, false, ['id', 'network', 'uri-id'], $uid);
 
                if (!empty($contact)) {
                        $contact_id = $contact["id"];
 
-                       if (empty($update)) {
+                       if (empty($update) && (!empty($contact['uri-id']) || is_bool($update))) {
                                Logger::debug('Contact found', ['url' => $url, 'uid' => $uid, 'update' => $update, 'cid' => $contact_id]);
                                return $contact_id;
                        }
@@ -1497,67 +1499,46 @@ class Contact
         * @param bool  $no_update Don't perfom an update if no cached avatar was found
         * @return string photo path
         */
-       private static function getAvatarPath(array $contact, string $field, string $size, string $avatar, $no_update = false)
+       private static function getAvatarPath(array $contact, string $size, $no_update = false)
        {
-               if (!empty($contact)) {
-                       $contact = self::checkAvatarCacheByArray($contact, $no_update);
-                       if (!empty($contact[$field])) {
-                               $avatar = $contact[$field];
-                       }
-               }
-
-               if ($no_update && empty($avatar) && !empty($contact['avatar'])) {
-                       $avatar = $contact['avatar'];
-               }
-
-               if (empty($avatar)) {
-                       $avatar = self::getDefaultAvatar([], $size);
-               }
-
-               if (Proxy::isLocalImage($avatar)) {
-                       return $avatar;
-               } else {
-                       return Proxy::proxifyUrl($avatar, false, $size);
-               }
+               $contact = self::checkAvatarCacheByArray($contact, $no_update);
+               return self::getAvatarUrlForId($contact['id'], $size, $contact['updated'] ?? '');
        }
 
        /**
         * Return the photo path for a given contact array
         *
         * @param array  $contact   Contact array
-        * @param string $avatar    Avatar path that is displayed when no photo had been found
         * @param bool   $no_update Don't perfom an update if no cached avatar was found
         * @return string photo path
         */
-       public static function getPhoto(array $contact, string $avatar = '', bool $no_update = false)
+       public static function getPhoto(array $contact, bool $no_update = false)
        {
-               return self::getAvatarPath($contact, 'photo', Proxy::SIZE_SMALL, $avatar, $no_update);
+               return self::getAvatarPath($contact, Proxy::SIZE_SMALL, $no_update);
        }
 
        /**
         * Return the photo path (thumb size) for a given contact array
         *
         * @param array  $contact   Contact array
-        * @param string $avatar    Avatar path that is displayed when no photo had been found
         * @param bool   $no_update Don't perfom an update if no cached avatar was found
         * @return string photo path
         */
-       public static function getThumb(array $contact, string $avatar = '', bool $no_update = false)
+       public static function getThumb(array $contact, bool $no_update = false)
        {
-               return self::getAvatarPath($contact, 'thumb', Proxy::SIZE_THUMB, $avatar, $no_update);
+               return self::getAvatarPath($contact, Proxy::SIZE_THUMB, $no_update);
        }
 
        /**
         * Return the photo path (micro size) for a given contact array
         *
         * @param array  $contact   Contact array
-        * @param string $avatar    Avatar path that is displayed when no photo had been found
         * @param bool   $no_update Don't perfom an update if no cached avatar was found
         * @return string photo path
         */
-       public static function getMicro(array $contact, string $avatar = '', bool $no_update = false)
+       public static function getMicro(array $contact, bool $no_update = false)
        {
-               return self::getAvatarPath($contact, 'micro', Proxy::SIZE_MICRO, $avatar, $no_update);
+               return self::getAvatarPath($contact, Proxy::SIZE_MICRO, $no_update);
        }
 
        /**
@@ -1665,23 +1646,94 @@ class Contact
        /**
         * Get avatar link for given contact id
         *
-        * @param integer $cid contact id
+        * @param integer $cid     contact id
+        * @param string  $size    One of the ProxyUtils::SIZE_* constants
+        * @param string  $updated Contact update date
+        * @return string avatar link
+        */
+       public static function getAvatarUrlForId(int $cid, string $size = '', string $updated = ''):string
+       {
+               // We have to fetch the "updated" variable when it wasn't provided
+               // The parameter can be provided to improve performance
+               if (empty($updated)) {
+                       $contact = self::getById($cid, ['updated']);
+                       $updated = $contact['updated'] ?? '';
+               }
+
+               $url = DI::baseUrl() . '/photo/contact/';
+               switch ($size) {
+                       case Proxy::SIZE_MICRO:
+                               $url .= Proxy::PIXEL_MICRO . '/';
+                               break;
+                       case Proxy::SIZE_THUMB:
+                               $url .= Proxy::PIXEL_THUMB . '/';
+                               break;
+                       case Proxy::SIZE_SMALL:
+                               $url .= Proxy::PIXEL_SMALL . '/';
+                               break;
+                       case Proxy::SIZE_MEDIUM:
+                               $url .= Proxy::PIXEL_MEDIUM . '/';
+                               break;
+                       case Proxy::SIZE_LARGE:
+                               $url .= Proxy::PIXEL_LARGE . '/';
+                               break;
+               }
+               return $url . $cid . ($updated ? '?ts=' . strtotime($updated) : '');
+       }
+
+       /**
+        * Get avatar link for given contact URL
+        *
+        * @param string  $url  contact url
+        * @param integer $uid  user id
+        * @param string  $size One of the ProxyUtils::SIZE_* constants
         * @return string avatar link
         */
-       public static function getAvatarUrlForId(int $cid):string
+       public static function getAvatarUrlForUrl(string $url, int $uid, string $size = ''):string
        {
-               return DI::baseUrl() . '/photo/contact/' . $cid;
+               $condition = ["`nurl` = ? AND ((`uid` = ? AND `network` IN (?, ?)) OR `uid` = ?)",
+                       Strings::normaliseLink($url), $uid, Protocol::FEED, Protocol::MAIL, 0];
+               $contact = self::selectFirst(['id', 'updated'], $condition);
+               return self::getAvatarUrlForId($contact['id'] ?? 0, $size, $contact['updated'] ?? '');
        }
 
        /**
         * Get header link for given contact id
         *
-        * @param integer $cid contact id
+        * @param integer $cid     contact id
+        * @param string  $size    One of the ProxyUtils::SIZE_* constants
+        * @param string  $updated Contact update date
         * @return string header link
         */
-       public static function getHeaderUrlForId(int $cid):string
+       public static function getHeaderUrlForId(int $cid, string $size = '', string $updated = ''):string
        {
-               return DI::baseUrl() . '/photo/header/' . $cid;
+               // We have to fetch the "updated" variable when it wasn't provided
+               // The parameter can be provided to improve performance
+               if (empty($updated)) {
+                       $contact = self::getById($cid, ['updated']);
+                       $updated = $contact['updated'] ?? '';
+               }
+
+               $url = DI::baseUrl() . '/photo/header/';
+               switch ($size) {
+                       case Proxy::SIZE_MICRO:
+                               $url .= Proxy::PIXEL_MICRO . '/';
+                               break;
+                       case Proxy::SIZE_THUMB:
+                               $url .= Proxy::PIXEL_THUMB . '/';
+                               break;
+                       case Proxy::SIZE_SMALL:
+                               $url .= Proxy::PIXEL_SMALL . '/';
+                               break;
+                       case Proxy::SIZE_MEDIUM:
+                               $url .= Proxy::PIXEL_MEDIUM . '/';
+                               break;
+                       case Proxy::SIZE_LARGE:
+                               $url .= Proxy::PIXEL_LARGE . '/';
+                               break;
+               }
+
+               return $url . $cid . ($updated ? '?ts=' . strtotime($updated) : '');
        }
 
        /**
@@ -1836,7 +1888,7 @@ class Contact
        {
                if (Strings::normaliseLink($new_url) != Strings::normaliseLink($old_url)) {
                        Logger::notice('New URL differs from old URL', ['old' => $old_url, 'new' => $new_url]);
-                       // @todo It is to decide what to do when the URL is changed
+                       return;
                }
 
                if (!DBA::update('contact', $fields, ['id' => $id])) {
@@ -1971,7 +2023,7 @@ class Contact
                // These fields aren't updated by this routine:
                // 'xmpp', 'sensitive'
 
-               $fields = ['uid', 'avatar', 'header', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe',
+               $fields = ['uid', 'uri-id', 'avatar', 'header', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe',
                        'manually-approve', 'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco',
                        'network', 'alias', 'baseurl', 'gsid', 'forum', 'prv', 'contact-type', 'pubkey', 'last-item'];
                $contact = DBA::selectFirst('contact', $fields, ['id' => $id]);
@@ -1980,7 +2032,11 @@ class Contact
                }
 
                if (self::isLocal($ret['url'])) {
-                       Logger::info('Local contacts are not updated here.');
+                       if ($contact['uid'] == 0) {
+                               Logger::info('Local contacts are not updated here.');
+                       } else {
+                               self::updateFromPublicContact($id, $contact);
+                       }
                        return true;
                }
 
@@ -1996,6 +2052,9 @@ class Contact
                $uid = $contact['uid'];
                unset($contact['uid']);
 
+               $uriid = $contact['uri-id'];
+               unset($contact['uri-id']);
+
                $pubkey = $contact['pubkey'];
                unset($contact['pubkey']);
 
@@ -2019,6 +2078,14 @@ class Contact
                        return false;
                }
 
+               if (Strings::normaliseLink($ret['url']) != Strings::normaliseLink($contact['url'])) {
+                       $cid = self::getIdForURL($ret['url']);
+                       if (!empty($cid) && ($cid != $id)) {
+                               Logger::notice('URL of contact changed.', ['id' => $id, 'new_id' => $cid, 'old' => $contact['url'], 'new' => $ret['url']]);
+                               return self::updateFromProbeArray($cid, $ret);
+                       }
+               }
+
                if (isset($ret['hide']) && is_bool($ret['hide'])) {
                        $ret['unsearchable'] = $ret['hide'];
                }
@@ -2041,6 +2108,7 @@ class Contact
                }
 
                $update = false;
+               $guid = $ret['guid'] ?? '';
 
                // make sure to not overwrite existing values with blank entries except some technical fields
                $keep = ['batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'baseurl'];
@@ -2060,6 +2128,10 @@ class Contact
                        unset($ret['last-item']);
                }
 
+               if (empty($uriid)) {
+                       $update = true;
+               }
+
                if (!empty($ret['photo']) && ($ret['network'] != Protocol::FEED)) {
                        self::updateAvatar($id, $ret['photo'], $update);
                }
@@ -2082,9 +2154,15 @@ class Contact
                        return true;
                }
 
-               $ret['nurl'] = Strings::normaliseLink($ret['url']);
+               if (empty($guid)) {
+                       $ret['uri-id'] = ItemURI::getIdByURI($ret['url']);
+               } else {
+                       $ret['uri-id'] = ItemURI::insert(['uri' => $ret['url'], 'guid' => $guid]);
+               }
+
+               $ret['nurl']    = Strings::normaliseLink($ret['url']);
                $ret['updated'] = $updated;
-               $ret['failed'] = false;
+               $ret['failed']  = false;
 
                // Only fill the pubkey if it had been empty before. We have to prevent identity theft.
                if (empty($pubkey) && !empty($new_pubkey)) {
@@ -2115,6 +2193,26 @@ class Contact
                return true;
        }
 
+       private static function updateFromPublicContact(int $id, array $contact)
+       {
+               $public = self::getByURL($contact['url'], false);
+
+               $fields = [];
+
+               foreach ($contact as $field => $value) {
+                       if ($field == 'uid') {
+                               continue;
+                       }
+                       if ($public[$field] != $value) {
+                               $fields[$field] = $public[$field];
+                       }
+               }
+               if (!empty($fields)) {
+                       DBA::update('contact', $fields, ['id' => $id, 'self' => false]);
+                       Logger::info('Updating local contact', ['id' => $id]);
+               }
+       }
+
        /**
         * @param integer $url contact url
         * @return integer Contact id
@@ -2223,8 +2321,10 @@ class Contact
                }
 
                if (!empty($arr['contact']['name'])) {
+                       $probed = false;
                        $ret = $arr['contact'];
                } else {
+                       $probed = true;                 
                        $ret = Probe::uri($url, $network, $user['uid']);
                }
 
@@ -2368,6 +2468,10 @@ class Contact
                // pull feed and consume it, which should subscribe to the hub.
                if ($contact['network'] == Protocol::OSTATUS) {
                        Worker::add(PRIORITY_HIGH, 'OnePoll', $contact_id, 'force');
+               }
+
+               if ($probed) {
+                       self::updateFromProbeArray($contact_id, $ret);
                } else {
                        Worker::add(PRIORITY_HIGH, 'UpdateContact', $contact_id);
                }
@@ -2888,7 +2992,8 @@ class Contact
                $search .= '%';
 
                $results = DBA::p("SELECT * FROM `contact`
-                       WHERE NOT `unsearchable` AND `network` IN (?, ?, ?, ?) AND
+                       WHERE (NOT `unsearchable` OR `nurl` IN (SELECT `nurl` FROM `owner-view` where `publish` OR `net-publish`))
+                               AND `network` IN (?, ?, ?, ?) AND
                                NOT `failed` AND `uid` = ? AND
                                (`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?) $extra_sql
                                ORDER BY `nurl` DESC LIMIT 1000",