X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FContact%2FRelation.php;h=9b4ebeb1d1f5e8cd9533074c365774de09b38cda;hb=75ca10896c89199e4c3668cd701e55b3e250fa9f;hp=d1e51811ff8fce5a777a6b36ff6a68966ca73a0d;hpb=b45ba63dbf4ab9e5c2842907a0aa5123ab474771;p=friendica.git diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index d1e51811ff..9b4ebeb1d1 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -1,6 +1,6 @@ $interaction_date], ['cid' => $target, 'relation-cid' => $actor], true); + DBA::insert('contact-relation', ['last-interaction' => $interaction_date, 'cid' => $target, 'relation-cid' => $actor], Database::INSERT_UPDATE); + } + + /** + * Fetch the followers of a given user + * + * @param integer $uid User ID + * @return void + */ + public static function discoverByUser(int $uid) + { + $contact = Contact::selectFirst(['id', 'url', 'network'], ['uid' => $uid, 'self' => true]); + if (empty($contact)) { + Logger::warning('Self contact for user not found', ['uid' => $uid]); + return; + } + + $followers = self::getContacts($uid, [Contact::FOLLOWER, Contact::FRIEND]); + $followings = self::getContacts($uid, [Contact::SHARING, Contact::FRIEND]); + + self::updateFollowersFollowings($contact, $followers, $followings); } /** @@ -75,34 +100,62 @@ class Relation { $contact = Contact::getByURL($url); if (empty($contact)) { + Logger::info('Contact not found', ['url' => $url]); return; } if (!self::isDiscoverable($url, $contact)) { + Logger::info('Contact is not discoverable', ['url' => $url]); return; } - $apcontact = APContact::getByURL($url, false); + $uid = User::getIdForURL($url); + if (!empty($uid)) { + Logger::info('Fetch the followers/followings locally', ['url' => $url]); + $followers = self::getContacts($uid, [Contact::FOLLOWER, Contact::FRIEND]); + $followings = self::getContacts($uid, [Contact::SHARING, Contact::FRIEND]); + } elseif (!Contact::isLocal($url)) { + Logger::info('Fetch the followers/followings by polling the endpoints', ['url' => $url]); + $apcontact = APContact::getByURL($url, false); - if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) { - $followers = ActivityPub::fetchItems($apcontact['followers']); - } else { - $followers = []; - } + if (!empty($apcontact['followers']) && is_string($apcontact['followers'])) { + $followers = ActivityPub::fetchItems($apcontact['followers']); + } else { + $followers = []; + } - if (!empty($apcontact['following']) && is_string($apcontact['following'])) { - $followings = ActivityPub::fetchItems($apcontact['following']); + if (!empty($apcontact['following']) && is_string($apcontact['following'])) { + $followings = ActivityPub::fetchItems($apcontact['following']); + } else { + $followings = []; + } } else { + Logger::warning('Contact seems to be local but could not be found here', ['url' => $url]); + $followers = []; $followings = []; } + self::updateFollowersFollowings($contact, $followers, $followings); + } + + /** + * Update followers and followings for the given contact + * + * @param array $contact + * @param array $followers + * @param array $followings + * @return void + */ + private static function updateFollowersFollowings(array $contact, array $followers, array $followings) + { if (empty($followers) && empty($followings)) { - DBA::update('contact', ['last-discovery' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); - Logger::info('The contact does not offer discoverable data', ['id' => $contact['id'], 'url' => $url, 'network' => $contact['network']]); + Contact::update(['last-discovery' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); + Logger::info('The contact does not offer discoverable data', ['id' => $contact['id'], 'url' => $contact['url'], 'network' => $contact['network']]); return; } $target = $contact['id']; + $url = $contact['url']; if (!empty($followers)) { // Clear the follower list, since it will be recreated in the next step @@ -127,14 +180,14 @@ class Relation $actor = Contact::getIdForURL($contact); if (!empty($actor)) { if (in_array($contact, $followers)) { - $fields = ['cid' => $target, 'relation-cid' => $actor]; - DBA::update('contact-relation', ['follows' => true, 'follow-updated' => DateTimeFormat::utcNow()], $fields, true); + $fields = ['cid' => $target, 'relation-cid' => $actor, 'follows' => true, 'follow-updated' => DateTimeFormat::utcNow()]; + DBA::insert('contact-relation', $fields, Database::INSERT_UPDATE); $follower_counter++; } if (in_array($contact, $followings)) { - $fields = ['cid' => $actor, 'relation-cid' => $target]; - DBA::update('contact-relation', ['follows' => true, 'follow-updated' => DateTimeFormat::utcNow()], $fields, true); + $fields = ['cid' => $actor, 'relation-cid' => $target, 'follows' => true, 'follow-updated' => DateTimeFormat::utcNow()]; + DBA::insert('contact-relation', $fields, Database::INSERT_UPDATE); $following_counter++; } } @@ -145,11 +198,45 @@ class Relation DBA::delete('contact-relation', ['cid' => $target, 'follows' => false, 'last-interaction' => DBA::NULL_DATETIME]); } - DBA::update('contact', ['last-discovery' => DateTimeFormat::utcNow()], ['id' => $target]); + Contact::update(['last-discovery' => DateTimeFormat::utcNow()], ['id' => $target]); Logger::info('Contacts discovery finished', ['id' => $target, 'url' => $url, 'follower' => $follower_counter, 'following' => $following_counter]); return; } + /** + * Fetch contact url list from the given local user + * + * @param integer $uid + * @param array $rel + * @return array contact list + */ + private static function getContacts(int $uid, array $rel): array + { + $list = []; + $profile = Profile::getByUID($uid); + if (!empty($profile['hide-friends'])) { + return $list; + } + + $condition = [ + 'rel' => $rel, + 'uid' => $uid, + 'self' => false, + 'deleted' => false, + 'hidden' => false, + 'archive' => false, + 'pending' => false, + ]; + $condition = DBA::mergeConditions($condition, ["`url` IN (SELECT `url` FROM `apcontact`)"]); + $contacts = DBA::select('contact', ['url'], $condition); + while ($contact = DBA::fetch($contacts)) { + $list[] = $contact['url']; + } + DBA::close($contacts); + + return $list; + } + /** * Tests if a given contact url is discoverable * @@ -157,16 +244,20 @@ class Relation * @param array $contact Contact array * @return boolean True if contact is discoverable */ - public static function isDiscoverable(string $url, array $contact = []) + public static function isDiscoverable(string $url, array $contact = []): bool { $contact_discovery = DI::config()->get('system', 'contact_discovery'); + if (Contact::isLocal($url)) { + return true; + } + if ($contact_discovery == self::DISCOVERY_NONE) { return false; } if (empty($contact)) { - $contact = Contact::getByURL($url); + $contact = Contact::getByURL($url, false); } if (empty($contact)) { @@ -210,13 +301,72 @@ class Relation } /** - * @param int $uid user + * Check if the cached suggestion is outdated + * + * @param integer $uid + * @return boolean + */ + static public function areSuggestionsOutdated(int $uid): bool + { + return DI::pConfig()->get($uid, 'suggestion', 'last_update') + 3600 < time(); + } + + /** + * Update contact suggestions for a given user + * + * @param integer $uid + * @return void + */ + static public function updateCachedSuggestions(int $uid) + { + if (!self::areSuggestionsOutdated($uid)) { + return; + } + + DBA::delete('account-suggestion', ['uid' => $uid, 'ignore' => false]); + + foreach (self::getSuggestions($uid) as $contact) { + DBA::insert('account-suggestion', ['uri-id' => $contact['uri-id'], 'uid' => $uid, 'level' => 1], Database::INSERT_IGNORE); + } + + DI::pConfig()->set($uid, 'suggestion', 'last_update', time()); + } + + /** + * Returns a cached array of suggested contacts for given user id + * + * @param int $uid User id * @param int $start optional, default 0 * @param int $limit optional, default 80 * @return array */ - static public function getSuggestions(int $uid, int $start = 0, int $limit = 80) + static public function getCachedSuggestions(int $uid, int $start = 0, int $limit = 80): array { + $condition = ["`uid` = ? AND `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE NOT `ignore` AND `uid` = ?)", 0, $uid]; + $params = ['limit' => [$start, $limit]]; + $cached = DBA::selectToArray('contact', [], $condition, $params); + + if (!empty($cached)) { + return $cached; + } else { + return self::getSuggestions($uid, $start, $limit); + } + } + + /** + * Returns an array of suggested contacts for given user id + * + * @param int $uid User id + * @param int $start optional, default 0 + * @param int $limit optional, default 80 + * @return array + */ + static public function getSuggestions(int $uid, int $start = 0, int $limit = 80): array + { + if ($uid == 0) { + return []; + } + $cid = Contact::getPublicIdByUserId($uid); $totallimit = $start + $limit; $contacts = []; @@ -228,20 +378,26 @@ class Relation // 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 + $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] + (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))) AND `id` = `cid`) + AND NOT `hidden` AND `network` IN (?, ?, ?, ?) + AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)", + $cid, + 0, + $uid, Contact::FRIEND, Contact::SHARING, + Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid + ], [ + '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)]); @@ -256,10 +412,11 @@ class Relation ["`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 (?, ?, ?, ?)", + (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?))) AND `id` = `cid`) + AND NOT `hidden` AND `network` IN (?, ?, ?, ?) + AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)", $cid, 0, $uid, Contact::FRIEND, Contact::SHARING, - Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus], + Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid], ['order' => ['last-item' => true], 'limit' => $totallimit] ); @@ -277,9 +434,10 @@ class Relation // 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], + AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?) + AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)", + $uid, Contact::FOLLOWER, 0, + Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid], ['order' => ['last-item' => true], 'limit' => $totallimit] ); @@ -296,10 +454,11 @@ class Relation // 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], + ["NOT `nurl` IN (SELECT `nurl` FROM `contact` WHERE `uid` = ? AND `rel` IN (?, ?) AND `nurl` = `nurl`) + AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?) + AND NOT `uri-id` IN (SELECT `uri-id` FROM `account-suggestion` WHERE `uri-id` = `contact`.`uri-id` AND `uid` = ?)", + $uid, Contact::FRIEND, Contact::SHARING, 0, + Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid], ['order' => ['last-item' => true], 'limit' => $totallimit] ); @@ -321,12 +480,12 @@ class Relation * @return int * @throws Exception */ - public static function countFollows(int $cid, array $condition = []) + public static function countFollows(int $cid, array $condition = []): int { - $condition = DBA::mergeConditions($condition, - ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`)', - $cid] - ); + $condition = DBA::mergeConditions($condition, [ + '`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`)', + $cid, + ]); return DI::dba()->count('contact', $condition); } @@ -345,7 +504,7 @@ class Relation public static function listFollows(int $cid, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) { $condition = DBA::mergeConditions($condition, - ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`)', + ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`)', $cid] ); @@ -433,7 +592,7 @@ class Relation ); return DI::dba()->selectToArray('contact', [], $condition, - ['limit' => [$offset, $count], 'order' => [$shuffle ? 'name' : 'RAND()']] + ['limit' => [$offset, $count], 'order' => [$shuffle ? 'RAND()' : 'name']] ); } @@ -449,8 +608,8 @@ class Relation public static function countAll(int $cid, array $condition = []) { $condition = DBA::mergeConditions($condition, - ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`) - OR `id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ? AND `follows`)', + ['(`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`) + OR `id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ? AND `follows`))', $cid, $cid] ); @@ -471,13 +630,13 @@ class Relation public static function listAll(int $cid, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) { $condition = DBA::mergeConditions($condition, - ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`) - OR `id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ? AND `follows`)', + ['(`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`) + OR `id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ? AND `follows`))', $cid, $cid] ); return DI::dba()->selectToArray('contact', [], $condition, - ['limit' => [$offset, $count], 'order' => [$shuffle ? 'name' : 'RAND()']] + ['limit' => [$offset, $count], 'order' => [$shuffle ? 'RAND()' : 'name']] ); } @@ -512,7 +671,7 @@ class Relation * @param int $count * @param int $offset * @param bool $shuffle - * @return array + * @return array|bool Array on success, false on failure * @throws Exception */ public static function listCommon(int $sourceId, int $targetId, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) @@ -524,7 +683,7 @@ class Relation ); return DI::dba()->selectToArray('contact', [], $condition, - ['limit' => [$offset, $count], 'order' => [$shuffle ? 'name' : 'RAND()']] + ['limit' => [$offset, $count], 'order' => [$shuffle ? 'RAND()' : 'name']] ); } @@ -537,7 +696,7 @@ class Relation * @return int * @throws Exception */ - public static function countCommonFollows(int $sourceId, int $targetId, array $condition = []) + public static function countCommonFollows(int $sourceId, int $targetId, array $condition = []): int { $condition = DBA::mergeConditions($condition, ['`id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `follows`) @@ -557,7 +716,7 @@ class Relation * @param int $count * @param int $offset * @param bool $shuffle - * @return array + * @return array|bool Array on success, false on failure * @throws Exception */ public static function listCommonFollows(int $sourceId, int $targetId, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) @@ -569,7 +728,7 @@ class Relation ); return DI::dba()->selectToArray('contact', [], $condition, - ['limit' => [$offset, $count], 'order' => [$shuffle ? 'name' : 'RAND()']] + ['limit' => [$offset, $count], 'order' => [$shuffle ? 'RAND()' : 'name']] ); } @@ -582,7 +741,7 @@ class Relation * @return int * @throws Exception */ - public static function countCommonFollowers(int $sourceId, int $targetId, array $condition = []) + public static function countCommonFollowers(int $sourceId, int $targetId, array $condition = []): int { $condition = DBA::mergeConditions($condition, ["`id` IN (SELECT `cid` FROM `contact-relation` WHERE `relation-cid` = ? AND `follows`) @@ -602,7 +761,7 @@ class Relation * @param int $count * @param int $offset * @param bool $shuffle - * @return array + * @return array|bool Array on success, false on failure * @throws Exception */ public static function listCommonFollowers(int $sourceId, int $targetId, array $condition = [], int $count = 30, int $offset = 0, bool $shuffle = false) @@ -614,7 +773,82 @@ class Relation ); return DI::dba()->selectToArray('contact', [], $condition, - ['limit' => [$offset, $count], 'order' => [$shuffle ? 'name' : 'RAND()']] + ['limit' => [$offset, $count], 'order' => [$shuffle ? 'RAND()' : 'name']] ); } + + /** + * Calculate the interaction scores for the given user + * + * @param integer $uid + * @return void + */ + public static function calculateInteractionScore(int $uid) + { + $days = DI::config()->get('channel', 'interaction_score_days'); + $contact_id = Contact::getPublicIdByUserId($uid); + + Logger::debug('Calculation - start', ['uid' => $uid, 'cid' => $contact_id, 'days' => $days]); + + $follow = Verb::getID(Activity::FOLLOW); + $view = Verb::getID(Activity::VIEW); + $read = Verb::getID(Activity::READ); + + DBA::update('contact-relation', ['score' => 0, 'relation-score' => 0, 'thread-score' => 0, 'relation-thread-score' => 0], ['relation-cid' => $contact_id]); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate relation-score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity`, EXISTS(SELECT `pid` FROM `account-user-view` WHERE `pid` = `post`.`author-id` AND `uid` = ? AND `rel` IN (?, ?)) AS `follows` + FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $uid, Contact::SHARING, Contact::FRIEND, $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['relation-score' => $score, 'follows' => $interaction['follows']], ['relation-cid' => $contact_id, 'cid' => $interaction['author-id']]); + } + DBA::close($interactions); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate relation-thread-score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity`, EXISTS(SELECT `pid` FROM `account-user-view` WHERE `pid` = `post`.`author-id` AND `uid` = ? AND `rel` IN (?, ?)) AS `follows` + FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $uid, Contact::SHARING, Contact::FRIEND, $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['relation-thread-score' => $score, 'follows' => !empty($interaction['follows'])], ['relation-cid' => $contact_id, 'cid' => $interaction['author-id']]); + } + DBA::close($interactions); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['score' => $score], ['relation-cid' => $contact_id, 'cid' => $interaction['author-id']]); + } + DBA::close($interactions); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate thread-score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['thread-score' => $score], ['relation-cid' => $contact_id, 'cid' => $interaction['author-id']]); + } + DBA::close($interactions); + Logger::debug('Calculation - end', ['uid' => $uid]); + } }