]> git.mxchange.org Git - friendica.git/blobdiff - src/Model/Contact.php
Add 'addon' folder as 'Friendica\Addon' namespace for autoload
[friendica.git] / src / Model / Contact.php
index 6d435c81c0b9e8ea431cb19416b10af1cc3ae11b..52bcc3b54b909d9c90bd5f52058f13b2f84c9c9b 100644 (file)
@@ -27,10 +27,6 @@ use Friendica\Util\DateTimeFormat;
 use Friendica\Util\Network;
 use Friendica\Util\Strings;
 
-require_once 'boot.php';
-require_once 'include/dba.php';
-require_once 'include/text.php';
-
 /**
  * @brief functions for interacting with a contact
  */
@@ -98,6 +94,48 @@ class Contact extends BaseObject
         * @}
         */
 
+       /**
+        * @brief Tests if the given contact is a follower
+        *
+        * @param int $cid Either public contact id or user's contact id
+        * @param int $uid User ID
+        *
+        * @return boolean is the contact id a follower?
+        */
+       public static function isFollower($cid, $uid)
+       {
+               if (self::isBlockedByUser($cid, $uid)) {
+                       return false;
+               }
+
+               $cdata = self::getPublicAndUserContacID($cid, $uid);
+               if (empty($cdata['user'])) {
+                       return false;
+               }
+
+               $condition = ['id' => $cdata['user'], 'rel' => [self::FOLLOWER, self::FRIEND]];
+               return DBA::exists('contact', $condition);
+       }
+
+       /**
+        * @brief Get the basepath for a given contact link
+        * @todo Add functionality to store this value in the contact table
+        *
+        * @param string $url The contact link
+        *
+        * @return string basepath
+        */
+       public static function getBasepath($url)
+       {
+               $data = Probe::uri($url);
+               if (!empty($data['baseurl'])) {
+                       return $data['baseurl'];
+               }
+
+               // When we can't probe the server, we use some ugly function that does some pattern matching
+               return PortableContact::detectServer($url);
+       }
+
        /**
         * @brief Returns the contact id for the user and the public contact id for a given contact id
         *
@@ -106,7 +144,7 @@ class Contact extends BaseObject
         *
         * @return array with public and user's contact id
         */
-       private static function getPublicAndUserContacID($cid, $uid)
+       public static function getPublicAndUserContacID($cid, $uid)
        {
                if (empty($uid) || empty($cid)) {
                        return [];
@@ -320,6 +358,7 @@ class Contact extends BaseObject
                                WHERE `gid` = ?
                                AND `contact`.`uid` = ?
                                AND NOT `contact`.`self`
+                               AND NOT `contact`.`deleted`
                                AND NOT `contact`.`blocked`
                                AND NOT `contact`.`pending`
                                ORDER BY `contact`.`name` ASC',
@@ -418,7 +457,8 @@ class Contact extends BaseObject
        public static function updateSelfFromUserID($uid, $update_avatar = false)
        {
                $fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'gender', 'avatar',
-                       'xmpp', 'contact-type', 'forum', 'prv', 'avatar-date', 'nurl'];
+                       'xmpp', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl',
+                       'photo', 'thumb', 'micro', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco'];
                $self = DBA::selectFirst('contact', $fields, ['uid' => $uid, 'self' => true]);
                if (!DBA::isResult($self)) {
                        return;
@@ -481,15 +521,15 @@ class Contact extends BaseObject
                $fields['nurl'] = Strings::normaliseLink($fields['url']);
                $fields['addr'] = $user['nickname'] . '@' . substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3);
                $fields['request'] = System::baseUrl() . '/dfrn_request/' . $user['nickname'];
-               $fields['notify'] = System::baseUrl() . '/dfrn_notify/'  . $user['nickname'];
-               $fields['poll'] = System::baseUrl() . '/dfrn_poll/'    . $user['nickname'];
+               $fields['notify'] = System::baseUrl() . '/dfrn_notify/' . $user['nickname'];
+               $fields['poll'] = System::baseUrl() . '/dfrn_poll/'. $user['nickname'];
                $fields['confirm'] = System::baseUrl() . '/dfrn_confirm/' . $user['nickname'];
-               $fields['poco'] = System::baseUrl() . '/poco/'         . $user['nickname'];
+               $fields['poco'] = System::baseUrl() . '/poco/' . $user['nickname'];
 
                $update = false;
 
                foreach ($fields as $field => $content) {
-                       if (isset($self[$field]) && $self[$field] != $content) {
+                       if ($self[$field] != $content) {
                                $update = true;
                        }
                }
@@ -539,6 +579,9 @@ class Contact extends BaseObject
         */
        public static function terminateFriendship(array $user, array $contact, $dissolve = false)
        {
+               if (empty($contact['network'])) {
+                       return;
+               }
                if (($contact['network'] == Protocol::DFRN) && $dissolve) {
                        DFRN::deliver($user, $contact, 'placeholder', true);
                } elseif (in_array($contact['network'], [Protocol::OSTATUS, Protocol::DFRN])) {
@@ -559,7 +602,7 @@ class Contact extends BaseObject
                } elseif ($contact['network'] == Protocol::DIASPORA) {
                        Diaspora::sendUnshare($user, $contact);
                } elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
-                       ActivityPub\Transmitter::sendContactUndo($contact['url'], $user['uid']);
+                       ActivityPub\Transmitter::sendContactUndo($contact['url'], $contact['id'], $user['uid']);
 
                        if ($dissolve) {
                                ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $user['uid']);
@@ -591,6 +634,8 @@ class Contact extends BaseObject
                        Logger::log('Empty contact: ' . json_encode($contact) . ' - ' . System::callstack(20), Logger::DEBUG);
                }
 
+               Logger::log('Contact '.$contact['id'].' is marked for archival', Logger::DEBUG);
+
                // Contact already archived or "self" contact? => nothing to do
                if ($contact['archive'] || $contact['self']) {
                        return;
@@ -639,6 +684,8 @@ class Contact extends BaseObject
                        return;
                }
 
+               Logger::log('Contact '.$contact['id'].' is marked as vital again', Logger::DEBUG);
+
                if (!isset($contact['url']) && !empty($contact['id'])) {
                        $fields = ['id', 'url', 'batch'];
                        $contact = DBA::selectFirst('contact', [], ['id' => $contact['id']]);
@@ -740,7 +787,7 @@ class Contact extends BaseObject
 
                        // "bd" always contains the upcoming birthday of a contact.
                        // "birthday" might contain the birthday including the year of birth.
-                       if ($profile["birthday"] > '0001-01-01') {
+                       if ($profile["birthday"] > DBA::NULL_DATE) {
                                $bd_timestamp = strtotime($profile["birthday"]);
                                $month = date("m", $bd_timestamp);
                                $day = date("d", $bd_timestamp);
@@ -757,7 +804,7 @@ class Contact extends BaseObject
                                        $profile["bd"] = ( ++$current_year) . "-" . $month . "-" . $day;
                                }
                        } else {
-                               $profile["bd"] = '0001-01-01';
+                               $profile["bd"] = DBA::NULL_DATE;
                        }
                } else {
                        $profile = $default;
@@ -794,7 +841,7 @@ class Contact extends BaseObject
                        $profile["location"] = "";
                        $profile["about"] = "";
                        $profile["gender"] = "";
-                       $profile["birthday"] = '0001-01-01';
+                       $profile["birthday"] = DBA::NULL_DATE;
                }
 
                $cache[$url][$uid] = $profile;
@@ -870,7 +917,7 @@ class Contact extends BaseObject
        public static function photoMenu(array $contact, $uid = 0)
        {
                // @todo Unused, to be removed
-               $a = get_app();
+               $a = \get_app();
 
                $contact_url = '';
                $pm_url = '';
@@ -991,6 +1038,7 @@ class Contact extends BaseObject
                           FROM `contact`
                           WHERE `uid` = %d
                           AND NOT `self`
+                          AND NOT `deleted`
                           AND NOT `blocked`
                           AND NOT `pending`
                           AND `id` NOT IN (
@@ -1061,7 +1109,7 @@ class Contact extends BaseObject
                        $update_contact = ($contact['avatar-date'] < DateTimeFormat::utc('now -7 days'));
 
                        // We force the update if the avatar is empty
-                       if (!x($contact, 'avatar')) {
+                       if (empty($contact['avatar'])) {
                                $update_contact = true;
                        }
                        if (!$update_contact || $no_update) {
@@ -1147,7 +1195,7 @@ class Contact extends BaseObject
 
                $url = $data["url"];
                if (!$contact_id) {
-                       DBA::insert('contact', [
+                       $fields = [
                                'uid'       => $uid,
                                'created'   => DateTimeFormat::utcNow(),
                                'url'       => $data["url"],
@@ -1176,10 +1224,13 @@ class Contact extends BaseObject
                                'writable'  => 1,
                                'blocked'   => 0,
                                'readonly'  => 0,
-                               'pending'   => 0]
-                       );
+                               'pending'   => 0];
 
-                       $s = DBA::select('contact', ['id'], ['nurl' => Strings::normaliseLink($data["url"]), 'uid' => $uid], ['order' => ['id'], 'limit' => 2]);
+                       $condition = ['nurl' => Strings::normaliseLink($data["url"]), 'uid' => $uid, 'deleted' => false];
+
+                       DBA::update('contact', $fields, $condition, true);
+
+                       $s = DBA::select('contact', ['id'], $condition, ['order' => ['id'], 'limit' => 2]);
                        $contacts = DBA::toArray($s);
                        if (!DBA::isResult($contacts)) {
                                return 0;
@@ -1204,8 +1255,10 @@ class Contact extends BaseObject
                        }
 
                        if (count($contacts) > 1 && $uid == 0 && $contact_id != 0 && $data["url"] != "") {
-                               DBA::delete('contact', ["`nurl` = ? AND `uid` = 0 AND `id` != ? AND NOT `self`",
-                                       Strings::normaliseLink($data["url"]), $contact_id]);
+                               $condition = ["`nurl` = ? AND `uid` = ? AND `id` != ? AND NOT `self`",
+                                       Strings::normaliseLink($data["url"]), 0, $contact_id];
+                               Logger::log('Deleting duplicate contact ' . json_encode($condition), Logger::DEBUG);
+                               DBA::delete('contact', $condition);
                        }
                }
 
@@ -1328,8 +1381,6 @@ class Contact extends BaseObject
        {
                $a = self::getApp();
 
-               require_once 'include/conversation.php';
-
                $cid = Self::getIdForURL($contact_url);
 
                $contact = DBA::selectFirst('contact', ['contact-type', 'network'], ['id' => $cid]);
@@ -1363,7 +1414,7 @@ class Contact extends BaseObject
 
                        $items = Item::inArray($r);
 
-                       $o = conversation($a, $items, $pager, 'contacts', $update);
+                       $o = conversation($a, $items, $pager, 'contacts', $update, false, 'commented', local_user());
                } else {
                        $r = Item::selectForUser(local_user(), [], $condition, $params);
 
@@ -1524,8 +1575,8 @@ class Contact extends BaseObject
 
                $ret = Probe::uri($contact["url"], $network);
 
-               // If Probe::uri fails the network code will be different
-               if (($ret["network"] != $contact["network"]) && !in_array($ret["network"], [Protocol::ACTIVITYPUB, $network])) {
+               // If Probe::uri fails the network code will be different (mostly "feed" or "unkn")
+               if (($ret["network"] != $contact["network"]) && !in_array($ret["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, $network])) {
                        return false;
                }
 
@@ -1589,7 +1640,7 @@ class Contact extends BaseObject
        {
                $result = ['cid' => -1, 'success' => false, 'message' => ''];
 
-               $a = get_app();
+               $a = \get_app();
 
                // remove ajax junk, e.g. Twitter
                $url = str_replace('/#!/', '/', $url);
@@ -1618,7 +1669,7 @@ class Contact extends BaseObject
                        return $result;
                }
 
-               if (x($arr['contact'], 'name')) {
+               if (!empty($arr['contact']['name'])) {
                        $ret = $arr['contact'];
                } else {
                        $ret = Probe::uri($url, $network, $uid, false);
@@ -1664,16 +1715,15 @@ class Contact extends BaseObject
                }
 
                // do we have enough information?
-
-               if (!((x($ret, 'name')) && (x($ret, 'poll')) && ((x($ret, 'url')) || (x($ret, 'addr'))))) {
+               if (empty($ret['name']) || empty($ret['poll']) || (empty($ret['url']) && empty($ret['addr']))) {
                        $result['message'] .= L10n::t('The profile address specified does not provide adequate information.') . EOL;
-                       if (!x($ret, 'poll')) {
+                       if (empty($ret['poll'])) {
                                $result['message'] .= L10n::t('No compatible communication protocols or feeds were discovered.') . EOL;
                        }
-                       if (!x($ret, 'name')) {
+                       if (empty($ret['name'])) {
                                $result['message'] .= L10n::t('An author or name was not found.') . EOL;
                        }
-                       if (!x($ret, 'url')) {
+                       if (empty($ret['url'])) {
                                $result['message'] .= L10n::t('No browser URL could be matched to this address.') . EOL;
                        }
                        if (strpos($url, '@') !== false) {
@@ -1698,6 +1748,8 @@ class Contact extends BaseObject
 
                $hidden = (($ret['network'] === Protocol::MAIL) ? 1 : 0);
 
+               $pending = in_array($ret['network'], [Protocol::ACTIVITYPUB]);
+
                if (in_array($ret['network'], [Protocol::MAIL, Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
                        $writeable = 1;
                }
@@ -1733,7 +1785,7 @@ class Contact extends BaseObject
                                'hidden'  => $hidden,
                                'blocked' => 0,
                                'readonly'=> 0,
-                               'pending' => 0,
+                               'pending' => $pending,
                                'subhub'  => $subhub
                        ]);
                }
@@ -1779,7 +1831,13 @@ class Contact extends BaseObject
                                $ret = Diaspora::sendShare($a->user, $contact);
                                Logger::log('share returns: ' . $ret);
                        } elseif ($contact['network'] == Protocol::ACTIVITYPUB) {
-                               $ret = ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $uid);
+                               $activity_id = ActivityPub\Transmitter::activityIDFromContact($contact_id);
+                               if (empty($activity_id)) {
+                                       // This really should never happen
+                                       return false;
+                               }
+
+                               $ret = ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $uid, $activity_id);
                                Logger::log('Follow returns: ' . $ret);
                        }
                }
@@ -1962,44 +2020,33 @@ class Contact extends BaseObject
         */
        public static function updateBirthdays()
        {
-               // This only handles foreign or alien networks where a birthday has been provided.
-               // In-network birthdays are handled within local_delivery
-
-               $r = q("SELECT * FROM `contact` WHERE `bd` != '' AND `bd` > '0001-01-01' AND SUBSTRING(`bd`, 1, 4) != `bdyear` ");
-               if (DBA::isResult($r)) {
-                       foreach ($r as $rr) {
-                               Logger::log('update_contact_birthday: ' . $rr['bd']);
-
-                               $nextbd = DateTimeFormat::utcNow('Y') . substr($rr['bd'], 4);
-
-                               /*
-                                * Add new birthday event for this person
-                                *
-                                * $bdtext is just a readable placeholder in case the event is shared
-                                * with others. We will replace it during presentation to our $importer
-                                * to contain a sparkle link and perhaps a photo.
-                                */
-
-                               // Check for duplicates
-                               $condition = ['uid' => $rr['uid'], 'cid' => $rr['id'],
-                                       'start' => DateTimeFormat::utc($nextbd), 'type' => 'birthday'];
-                               if (DBA::exists('event', $condition)) {
-                                       continue;
-                               }
-
-                               $bdtext = L10n::t('%s\'s birthday', $rr['name']);
-                               $bdtext2 = L10n::t('Happy Birthday %s', ' [url=' . $rr['url'] . ']' . $rr['name'] . '[/url]');
-
-                               q("INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`,`adjust`)
-                               VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d' ) ", intval($rr['uid']), intval($rr['id']),
-                                       DBA::escape(DateTimeFormat::utcNow()), DBA::escape(DateTimeFormat::utcNow()), DBA::escape(DateTimeFormat::utc($nextbd)),
-                                       DBA::escape(DateTimeFormat::utc($nextbd . ' + 1 day ')), DBA::escape($bdtext), DBA::escape($bdtext2), DBA::escape('birthday'),
-                                       intval(0)
-                               );
-
+               $condition = [
+                       '`bd` != ""
+                       AND `bd` > "0001-01-01"
+                       AND SUBSTRING(`bd`, 1, 4) != `bdyear`
+                       AND (`contact`.`rel` = ? OR `contact`.`rel` = ?)
+                       AND NOT `contact`.`pending`
+                       AND NOT `contact`.`hidden`
+                       AND NOT `contact`.`blocked`
+                       AND NOT `contact`.`archive`
+                       AND NOT `contact`.`deleted`',
+                       Contact::SHARING,
+                       Contact::FRIEND
+               ];
+
+               $contacts = DBA::select('contact', ['id', 'uid', 'name', 'url', 'bd'], $condition);
+
+               while ($contact = DBA::fetch($contacts)) {
+                       Logger::log('update_contact_birthday: ' . $contact['bd']);
+
+                       $nextbd = DateTimeFormat::utcNow('Y') . substr($contact['bd'], 4);
+
+                       if (Event::createBirthday($contact, $nextbd)) {
                                // update bdyear
-                               q("UPDATE `contact` SET `bdyear` = '%s', `bd` = '%s' WHERE `uid` = %d AND `id` = %d", DBA::escape(substr($nextbd, 0, 4)),
-                                       DBA::escape($nextbd), intval($rr['uid']), intval($rr['id'])
+                               DBA::update(
+                                       'contact',
+                                       ['bdyear' => substr($nextbd, 0, 4), 'bd' => $nextbd],
+                                       ['id' => $contact['id']]
                                );
                        }
                }
@@ -2042,6 +2089,10 @@ class Contact extends BaseObject
         */
        public static function magicLink($contact_url, $url = '')
        {
+               if (!local_user() && !remote_user()) {
+                       return $url ?: $contact_url; // Equivalent to: ($url != '') ? $url : $contact_url;
+               }
+
                $cid = self::getIdForURL($contact_url, 0, true);
                if (empty($cid)) {
                        return $url ?: $contact_url; // Equivalent to: ($url != '') ? $url : $contact_url;
@@ -2063,7 +2114,7 @@ class Contact extends BaseObject
                $contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'uid'], ['id' => $cid]);
 
                return self::magicLinkbyContact($contact, $url);
-        }
+       }
 
        /**
         * @brief Returns a magic link to authenticate remote visitors
@@ -2075,7 +2126,7 @@ class Contact extends BaseObject
         */
        public static function magicLinkbyContact($contact, $url = '')
        {
-               if ($contact['network'] != Protocol::DFRN) {
+               if ((!local_user() && !remote_user()) || ($contact['network'] != Protocol::DFRN)) {
                        return $url ?: $contact['url']; // Equivalent to ($url != '') ? $url : $contact['url'];
                }