X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FContact.php;h=f0be45772246457eaa122e204d735fc2e0c70d70;hb=f059e56e0f82e64024da7dcbb1ecac20ad84c1b5;hp=f095543ebdd725f560d426f0f423191aed7674c8;hpb=8d7846142ddb2f500a615e5f68cd68cbae5a0702;p=friendica.git diff --git a/src/Model/Contact.php b/src/Model/Contact.php index f095543ebd..f0be457722 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1,6 +1,6 @@ $id]); } + /** + * Fetch the first contact with the provided uri-id. + * + * @param integer $uri_id uri-id of the contact + * @param array $fields Array of selected fields, empty for all + * @return array|boolean Contact record if it exists, false otherwise + * @throws \Exception + */ + public static function getByUriId($uri_id, $fields = []) + { + return DBA::selectFirst('contact', $fields, ['uri-id' => $uri_id], ['order' => ['uid']]); + } + /** * Fetches a contact by a given url * @@ -701,9 +685,9 @@ class Contact */ public static function updateSelfFromUserID($uid, $update_avatar = false) { - $fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey', + $fields = ['id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey', 'manually-approve', 'xmpp', 'matrix', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl', 'unsearchable', - 'photo', 'thumb', 'micro', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco', 'network']; + 'photo', 'thumb', 'micro', 'header', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco', 'network']; $self = DBA::selectFirst('contact', $fields, ['uid' => $uid, 'self' => true]); if (!DBA::isResult($self)) { return false; @@ -769,9 +753,11 @@ class Contact } $fields['avatar'] = User::getAvatarUrl($user); + $fields['header'] = User::getBannerUrl($user); $fields['forum'] = $user['page-flags'] == User::PAGE_FLAGS_COMMUNITY; $fields['prv'] = $user['page-flags'] == User::PAGE_FLAGS_PRVGROUP; $fields['unsearchable'] = !$profile['net-publish']; + $fields['manually-approve'] = in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL, User::PAGE_FLAGS_PRVGROUP]); $update = false; @@ -823,41 +809,44 @@ class Contact self::update(['archive' => true, 'network' => Protocol::PHANTOM, 'deleted' => true], ['id' => $id]); // Delete it in the background - Worker::add(PRIORITY_MEDIUM, 'RemoveContact', $id); + Worker::add(PRIORITY_MEDIUM, 'Contact\Remove', $id); } /** - * Sends an unfriend message. Removes the contact for two-way unfriending or sharing only protocols (feed an mail) + * Unfollow the remote contact * - * @param array $user User unfriending - * @param array $contact Contact (uid != 0) unfriended - * @param boolean $two_way Revoke eventual inbound follow as well - * @return bool|null true if successful, false if not, null if no remote action was performed + * @param array $contact Target user-specific contact (uid != 0) array * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function terminateFriendship(array $user, array $contact): ?bool + public static function unfollow(array $contact): void { - $result = Protocol::terminateFriendship($user, $contact); + if (empty($contact['network'])) { + throw new \InvalidArgumentException('Empty network in contact array'); + } - if ($contact['rel'] == Contact::SHARING || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) { - self::remove($contact['id']); - } else { - self::update(['rel' => Contact::FOLLOWER], ['id' => $contact['id']]); + if (empty($contact['uid'])) { + throw new \InvalidArgumentException('Unexpected public contact record'); } - return $result; + if (in_array($contact['rel'], [self::SHARING, self::FRIEND])) { + $cdata = Contact::getPublicAndUserContactID($contact['id'], $contact['uid']); + Worker::add(PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']); + } + + self::removeSharer($contact); } /** * Revoke follow privileges of the remote user contact * - * @param array $contact Contact unfriended - * @return bool|null Whether the remote operation is successful or null if no remote operation was performed + * The local relationship is updated immediately, the eventual remote server is messaged in the background. + * + * @param array $contact User-specific contact array (uid != 0) to revoke the follow from * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function revokeFollow(array $contact): ?bool + public static function revokeFollow(array $contact): void { if (empty($contact['network'])) { throw new \InvalidArgumentException('Empty network in contact array'); @@ -867,19 +856,42 @@ class Contact throw new \InvalidArgumentException('Unexpected public contact record'); } - $result = Protocol::revokeFollow($contact); + if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND])) { + $cdata = Contact::getPublicAndUserContactID($contact['id'], $contact['uid']); + Worker::add(PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']); + } - // A null value here means the remote network doesn't support explicit follow revocation, we can still - // break the locally recorded relationship - if ($result !== false) { - if ($contact['rel'] == self::FRIEND) { - self::update(['rel' => self::SHARING], ['id' => $contact['id']]); - } else { - self::remove($contact['id']); - } + self::removeFollower($contact); + } + + /** + * Completely severs a relationship with a contact + * + * @param array $contact User-specific contact (uid != 0) array + * @throws HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + public static function terminateFriendship(array $contact) + { + if (empty($contact['network'])) { + throw new \InvalidArgumentException('Empty network in contact array'); } - return $result; + if (empty($contact['uid'])) { + throw new \InvalidArgumentException('Unexpected public contact record'); + } + + $cdata = Contact::getPublicAndUserContactID($contact['id'], $contact['uid']); + + if (in_array($contact['rel'], [self::SHARING, self::FRIEND])) { + Worker::add(PRIORITY_HIGH, 'Contact\Unfollow', $cdata['public'], $contact['uid']); + } + + if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND])) { + Worker::add(PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']); + } + + self::remove($contact['id']); } @@ -1085,9 +1097,11 @@ class Contact ]; if (!empty($contact['pending'])) { - $intro = DBA::selectFirst('intro', ['id'], ['contact-id' => $contact['id']]); - if (DBA::isResult($intro)) { - $menu['follow'] = [DI::l10n()->t('Approve'), 'notifications/intros/' . $intro['id'], true]; + try { + $intro = DI::intro()->selectForContact($contact['id']); + $menu['follow'] = [DI::l10n()->t('Approve'), 'notifications/intros/' . $intro->id, true]; + } catch (IntroductionNotFoundException $exception) { + DI::logger()->error('Pending contact doesn\'t have an introduction.', ['exception' => $exception]); } } } @@ -1255,6 +1269,10 @@ class Contact Logger::info('Contact will be updated', ['url' => $url, 'uid' => $uid, 'update' => $update, 'cid' => $contact_id]); } + if ($data['network'] == Protocol::DIASPORA) { + FContact::updateFromProbeArray($data); + } + self::updateFromProbeArray($contact_id, $data); // Don't return a number for a deleted account @@ -1466,34 +1484,11 @@ class Contact * * The function can be called with either the user or the contact array * - * @param array $contact contact or user array + * @param int $type type of contact or account * @return string */ - public static function getAccountType(array $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. - 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'])) - || (isset($contact['prv']) && intval($contact['prv'])) - || (isset($contact['community']) && intval($contact['community'])) - ) { - $type = self::TYPE_COMMUNITY; - } else { - $type = self::TYPE_PERSON; - } - - // The "contact-type" (contact table) and "account-type" (user table) are more general then the chaos from above. - if (isset($contact["contact-type"])) { - $type = $contact["contact-type"]; - } - - if (isset($contact["account-type"])) { - $type = $contact["account-type"]; - } - + public static function getAccountType(int $type) + { switch ($type) { case self::TYPE_ORGANISATION: $account_type = DI::l10n()->t("Organisation"); @@ -1550,18 +1545,22 @@ class Contact */ public static function checkAvatarCache(int $cid) { - $contact = DBA::selectFirst('contact', ['url', 'avatar', 'photo', 'thumb', 'micro'], ['id' => $cid, 'uid' => 0, 'self' => false]); + $contact = DBA::selectFirst('contact', ['url', 'network', 'avatar', 'photo', 'thumb', 'micro'], ['id' => $cid, 'uid' => 0, 'self' => false]); if (!DBA::isResult($contact)) { return; } - if (empty($contact['avatar']) || (!empty($contact['photo']) && !empty($contact['thumb']) && !empty($contact['micro']))) { + if (in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) || DI::config()->get('system', 'cache_contact_avatar')) { + if (!empty($contact['avatar']) && (empty($contact['photo']) || empty($contact['thumb']) || empty($contact['micro']))) { + Logger::info('Adding avatar cache', ['id' => $cid, 'contact' => $contact]); + self::updateAvatar($cid, $contact['avatar'], true); + return; + } + } elseif (!empty($contact['photo']) || !empty($contact['thumb']) || !empty($contact['micro'])) { + Logger::info('Removing avatar cache', ['id' => $cid, 'contact' => $contact]); + self::updateAvatar($cid, $contact['avatar'], true); return; } - - Logger::info('Adding avatar cache', ['id' => $cid, 'contact' => $contact]); - - self::updateAvatar($cid, $contact['avatar'], true); } /** @@ -1665,6 +1664,59 @@ class Contact return $contact; } + /** + * Fetch the default header for the given contact + * + * @param array $contact contact array + * @return string avatar URL + */ + public static function getDefaultHeader(array $contact): string + { + if (!empty($contact['header'])) { + return $contact['header']; + } + + if (!empty($contact['gsid'])) { + // Use default banners for certain platforms + $gserver = DBA::selectFirst('gserver', ['platform'], ['id' => $contact['gsid']]); + $platform = strtolower($gserver['platform'] ?? ''); + } else { + $platform = ''; + } + + switch ($platform) { + case 'friendica': + case 'friendika': + /** + * Picture credits + * @author Lostinlight + * @license CC0 https://creativecommons.org/share-your-work/public-domain/cc0/ + * @link https://gitlab.com/lostinlight/per_aspera_ad_astra/-/blob/master/friendica-404/friendica-promo-bubbles.jpg + */ + $header = DI::baseUrl() . '/images/friendica-banner.jpg'; + break; + case 'diaspora': + /** + * Picture credits + * @author John Liu + * @license CC BY 2.0 https://creativecommons.org/licenses/by/2.0/ + * @link https://www.flickr.com/photos/8047705@N02/5572197407 + */ + $header = DI::baseUrl() . '/images/diaspora-banner.jpg'; + break; + default: + /** + * Use a random picture. + * The service provides random pictures from Unsplash. + * @license https://unsplash.com/license + */ + $header = 'https://picsum.photos/seed/' . hash('ripemd128', $contact['url']) . '/960/300'; + break; + } + + return $header; + } + /** * Fetch the default avatar for the given contact and size * @@ -1865,54 +1917,68 @@ class Contact $avatar = self::getDefaultAvatar($contact, Proxy::SIZE_SMALL); } - if ($default_avatar && Proxy::isLocalImage($avatar)) { - $fields = ['avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(), - 'photo' => $avatar, - 'thumb' => self::getDefaultAvatar($contact, Proxy::SIZE_THUMB), - 'micro' => self::getDefaultAvatar($contact, Proxy::SIZE_MICRO)]; - Logger::debug('Use default avatar', ['id' => $cid, 'uid' => $uid]); + $cache_avatar = DI::config()->get('system', 'cache_contact_avatar'); + + // Local contact avatars don't need to be cached + if ($cache_avatar && Network::isLocalLink($contact['url'])) { + $cache_avatar = !DBA::exists('contact', ['nurl' => $contact['nurl'], 'self' => true]); } - // Use the data from the self account - if (empty($fields)) { - $local_uid = User::getIdForURL($contact['url']); - if (!empty($local_uid)) { - $fields = self::selectFirst(['avatar', 'avatar-date', 'photo', 'thumb', 'micro'], ['self' => true, 'uid' => $local_uid]); - Logger::debug('Use owner data', ['id' => $cid, 'uid' => $uid, 'owner-uid' => $local_uid]); + if (in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) || $cache_avatar) { + if ($default_avatar && Proxy::isLocalImage($avatar)) { + $fields = ['avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(), + 'photo' => $avatar, + 'thumb' => self::getDefaultAvatar($contact, Proxy::SIZE_THUMB), + 'micro' => self::getDefaultAvatar($contact, Proxy::SIZE_MICRO)]; + Logger::debug('Use default avatar', ['id' => $cid, 'uid' => $uid]); } - } - if (empty($fields)) { - $update = ($contact['avatar'] != $avatar) || $force; - - if (!$update) { - $data = [ - $contact['photo'] ?? '', - $contact['thumb'] ?? '', - $contact['micro'] ?? '', - ]; - - foreach ($data as $image_uri) { - $image_rid = Photo::ridFromURI($image_uri); - if ($image_rid && !Photo::exists(['resource-id' => $image_rid, 'uid' => $uid])) { - Logger::debug('Regenerating avatar', ['contact uid' => $uid, 'cid' => $cid, 'missing photo' => $image_rid, 'avatar' => $contact['avatar']]); - $update = true; - } + // Use the data from the self account + if (empty($fields)) { + $local_uid = User::getIdForURL($contact['url']); + if (!empty($local_uid)) { + $fields = self::selectFirst(['avatar', 'avatar-date', 'photo', 'thumb', 'micro'], ['self' => true, 'uid' => $local_uid]); + Logger::debug('Use owner data', ['id' => $cid, 'uid' => $uid, 'owner-uid' => $local_uid]); } } - if ($update) { - $photos = Photo::importProfilePhoto($avatar, $uid, $cid, true); - if ($photos) { - $fields = ['avatar' => $avatar, 'photo' => $photos[0], 'thumb' => $photos[1], 'micro' => $photos[2], 'avatar-date' => DateTimeFormat::utcNow()]; - $update = !empty($fields); - Logger::debug('Created new cached avatars', ['id' => $cid, 'uid' => $uid, 'owner-uid' => $local_uid]); - } else { - $update = false; + if (empty($fields)) { + $update = ($contact['avatar'] != $avatar) || $force; + + if (!$update) { + $data = [ + $contact['photo'] ?? '', + $contact['thumb'] ?? '', + $contact['micro'] ?? '', + ]; + + foreach ($data as $image_uri) { + $image_rid = Photo::ridFromURI($image_uri); + if ($image_rid && !Photo::exists(['resource-id' => $image_rid, 'uid' => $uid])) { + Logger::debug('Regenerating avatar', ['contact uid' => $uid, 'cid' => $cid, 'missing photo' => $image_rid, 'avatar' => $contact['avatar']]); + $update = true; + } + } + } + + if ($update) { + $photos = Photo::importProfilePhoto($avatar, $uid, $cid, true); + if ($photos) { + $fields = ['avatar' => $avatar, 'photo' => $photos[0], 'thumb' => $photos[1], 'micro' => $photos[2], 'avatar-date' => DateTimeFormat::utcNow()]; + $update = !empty($fields); + Logger::debug('Created new cached avatars', ['id' => $cid, 'uid' => $uid, 'owner-uid' => $local_uid]); + } else { + $update = false; + } } + } else { + $update = ($fields['photo'] . $fields['thumb'] . $fields['micro'] != $contact['photo'] . $contact['thumb'] . $contact['micro']) || $force; } } else { - $update = ($fields['photo'] . $fields['thumb'] . $fields['micro'] != $contact['photo'] . $contact['thumb'] . $contact['micro']) || $force; + Photo::delete(['uid' => $uid, 'contact-id' => $cid, 'photo-type' => Photo::CONTACT_AVATAR]); + $fields = ['avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(), + 'photo' => '', 'thumb' => '', 'micro' => '']; + $update = ($avatar != $contact['avatar'] . $contact['photo'] . $contact['thumb'] . $contact['micro']) || $force; } if (!$update) { @@ -2079,6 +2145,11 @@ class Contact } $ret = Probe::uri($contact['url'], $network, $contact['uid']); + + if ($ret['network'] == Protocol::DIASPORA) { + FContact::updateFromProbeArray($ret); + } + return self::updateFromProbeArray($id, $ret); } @@ -2395,7 +2466,7 @@ class Contact } if (($network != '') && ($ret['network'] != $network)) { - Logger::log('Expected network ' . $network . ' does not match actual network ' . $ret['network']); + Logger::notice('Expected network ' . $network . ' does not match actual network ' . $ret['network']); return $result; } @@ -2462,7 +2533,7 @@ class Contact if (DBA::isResult($contact)) { // update contact - $new_relation = (($contact['rel'] == self::FOLLOWER) ? self::FRIEND : self::SHARING); + $new_relation = (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND]) ? self::FRIEND : self::SHARING); $fields = ['rel' => $new_relation, 'subhub' => $subhub, 'readonly' => false]; self::update($fields, ['id' => $contact['id']]); @@ -2508,7 +2579,7 @@ class Contact $contact_id = $contact['id']; $result['cid'] = $contact_id; - Group::addMember(User::getDefaultGroup($uid, $contact["network"]), $contact_id); + Group::addMember(User::getDefaultGroup($uid), $contact_id); // Update the avatar self::updateAvatar($contact_id, $ret['photo']); @@ -2524,125 +2595,11 @@ class Contact Worker::add(PRIORITY_HIGH, 'UpdateContact', $contact_id); } - $owner = User::getOwnerDataById($uid); - - if (DBA::isResult($owner)) { - if (in_array($protocol, [Protocol::OSTATUS, Protocol::DFRN])) { - // create a follow slap - $item = []; - $item['verb'] = Activity::FOLLOW; - $item['gravity'] = GRAVITY_ACTIVITY; - $item['follow'] = $contact["url"]; - $item['body'] = ''; - $item['title'] = ''; - $item['guid'] = ''; - $item['uri-id'] = 0; + $result['success'] = Protocol::follow($uid, $contact, $protocol); - $slap = OStatus::salmon($item, $owner); - - if (!empty($contact['notify'])) { - Salmon::slapper($owner, $contact['notify'], $slap); - } - } elseif ($protocol == Protocol::DIASPORA) { - $ret = Diaspora::sendShare($owner, $contact); - Logger::log('share returns: ' . $ret); - } elseif ($protocol == Protocol::ACTIVITYPUB) { - $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); - } - } - - $result['success'] = true; return $result; } - /** - * Updated contact's SSL policy - * - * @param array $contact Contact array - * @param string $new_policy New policy, valid: self,full - * - * @return array Contact array with updated values - * @throws \Exception - */ - public static function updateSslPolicy(array $contact, $new_policy) - { - $ssl_changed = false; - if ((intval($new_policy) == BaseURL::SSL_POLICY_SELFSIGN || $new_policy === 'self') && strstr($contact['url'], 'https:')) { - $ssl_changed = true; - $contact['url'] = str_replace('https:', 'http:', $contact['url']); - $contact['request'] = str_replace('https:', 'http:', $contact['request']); - $contact['notify'] = str_replace('https:', 'http:', $contact['notify']); - $contact['poll'] = str_replace('https:', 'http:', $contact['poll']); - $contact['confirm'] = str_replace('https:', 'http:', $contact['confirm']); - $contact['poco'] = str_replace('https:', 'http:', $contact['poco']); - } - - if ((intval($new_policy) == BaseURL::SSL_POLICY_FULL || $new_policy === 'full') && strstr($contact['url'], 'http:')) { - $ssl_changed = true; - $contact['url'] = str_replace('http:', 'https:', $contact['url']); - $contact['request'] = str_replace('http:', 'https:', $contact['request']); - $contact['notify'] = str_replace('http:', 'https:', $contact['notify']); - $contact['poll'] = str_replace('http:', 'https:', $contact['poll']); - $contact['confirm'] = str_replace('http:', 'https:', $contact['confirm']); - $contact['poco'] = str_replace('http:', 'https:', $contact['poco']); - } - - if ($ssl_changed) { - $fields = ['url' => $contact['url'], 'request' => $contact['request'], - 'notify' => $contact['notify'], 'poll' => $contact['poll'], - 'confirm' => $contact['confirm'], 'poco' => $contact['poco']]; - self::update($fields, ['id' => $contact['id']]); - } - - return $contact; - } - - /** - * Follow a contact - * - * @param int $cid Public contact id - * @param int $uid User ID - * - * @return bool "true" if following had been successful - */ - public static function follow(int $cid, int $uid) - { - $contact = self::getById($cid, ['url']); - - $result = self::createFromProbeForUser($uid, $contact['url']); - - return $result['cid']; - } - - /** - * Unfollow a contact - * - * @param int $cid Public contact id - * @param int $uid User ID - * - * @return bool "true" if unfollowing had been successful - */ - public static function unfollow(int $cid, int $uid) - { - $cdata = self::getPublicAndUserContactID($cid, $uid); - if (empty($cdata['user'])) { - return false; - } - - $contact = self::getById($cdata['user']); - - self::removeSharer([], $contact); - - return true; - } - /** * @param array $importer Owner (local user) data * @param array $contact Existing owner-specific contact data we want to expand the relationship with. Optional. @@ -2714,7 +2671,7 @@ class Contact } else { // send email notification to owner? if (DBA::exists('contact', ['nurl' => Strings::normaliseLink($url), 'uid' => $importer['uid'], 'pending' => true])) { - Logger::log('ignoring duplicated connection request from pending contact ' . $url); + Logger::notice('ignoring duplicated connection request from pending contact ' . $url); return null; } @@ -2748,20 +2705,21 @@ class Contact $user = DBA::selectFirst('user', $fields, ['uid' => $importer['uid']]); if (DBA::isResult($user) && !in_array($user['page-flags'], [User::PAGE_FLAGS_SOAPBOX, User::PAGE_FLAGS_FREELOVE, User::PAGE_FLAGS_COMMUNITY])) { // create notification - $hash = Strings::getRandomHex(); - if (is_array($contact_record)) { - DBA::insert('intro', ['uid' => $importer['uid'], 'contact-id' => $contact_record['id'], - 'blocked' => false, 'knowyou' => false, 'note' => $note, - 'hash' => $hash, 'datetime' => DateTimeFormat::utcNow()]); + $intro = DI::introFactory()->createNew( + $importer['uid'], + $contact_record['id'], + $note + ); + DI::intro()->save($intro); } - Group::addMember(User::getDefaultGroup($importer['uid'], $contact_record["network"]), $contact_record['id']); + Group::addMember(User::getDefaultGroup($importer['uid']), $contact_record['id']); if (($user['notify-flags'] & Notification\Type::INTRO) && in_array($user['page-flags'], [User::PAGE_FLAGS_NORMAL])) { - notification([ + DI::notify()->createFromArray([ 'type' => Notification\Type::INTRO, 'otype' => Notification\ObjectType::INTRO, 'verb' => ($sharing ? Activity::FRIEND : Activity::FOLLOW), @@ -2790,10 +2748,17 @@ class Contact return null; } + /** + * Update the local relationship when a local user loses a follower + * + * @param array $contact User-specific contact (uid != 0) array + * @throws HTTPException\InternalServerErrorException + * @throws \ImagickException + */ public static function removeFollower(array $contact) { if (in_array($contact['rel'] ?? [], [self::FRIEND, self::SHARING])) { - DBA::update('contact', ['rel' => self::SHARING], ['id' => $contact['id']]); + self::update(['rel' => self::SHARING], ['id' => $contact['id']]); } elseif (!empty($contact['id'])) { self::remove($contact['id']); } else { @@ -2801,12 +2766,19 @@ class Contact } } - public static function removeSharer($importer, $contact) + /** + * Update the local relationship when a local user unfollow a contact. + * Removes the contact for sharing-only protocols (feed and mail). + * + * @param array $contact User-specific contact (uid != 0) array + * @throws HTTPException\InternalServerErrorException + */ + public static function removeSharer(array $contact) { - if (($contact['rel'] == self::FRIEND) || ($contact['rel'] == self::FOLLOWER)) { - self::update(['rel' => self::FOLLOWER], ['id' => $contact['id']]); - } else { + if ($contact['rel'] == self::SHARING || in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) { self::remove($contact['id']); + } else { + self::update(['rel' => self::FOLLOWER], ['id' => $contact['id']]); } } @@ -2833,7 +2805,7 @@ class Contact $contacts = DBA::select('contact', ['id', 'uid', 'name', 'url', 'bd'], $condition); while ($contact = DBA::fetch($contacts)) { - Logger::log('update_contact_birthday: ' . $contact['bd']); + Logger::notice('update_contact_birthday: ' . $contact['bd']); $nextbd = DateTimeFormat::utcNow('Y') . substr($contact['bd'], 4); @@ -2971,7 +2943,7 @@ class Contact */ public static function isForum($contactid) { - $fields = ['forum', 'prv']; + $fields = ['contact-type']; $condition = ['id' => $contactid]; $contact = DBA::selectFirst('contact', $fields, $condition); if (!DBA::isResult($contact)) { @@ -2979,7 +2951,7 @@ class Contact } // Is it a forum? - return ($contact['forum'] || $contact['prv']); + return ($contact['contact-type'] == self::TYPE_COMMUNITY); } /**