From f31e617f5d7a0908e82e8f62bf415635a02c57b1 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 30 Nov 2022 05:59:27 +0000 Subject: [PATCH 01/12] Contact suggestions are now cached --- database.sql | 16 ++++++- doc/database.md | 1 + doc/database/db_account-suggestion.md | 32 +++++++++++++ src/Factory/Api/Mastodon/Status.php | 22 +++++++-- src/Model/Contact/Relation.php | 62 +++++++++++++++++++++---- src/Module/Api/Mastodon/Suggestions.php | 2 +- src/Module/Contact/Suggestions.php | 2 +- src/Security/Authentication.php | 4 ++ src/Worker/Cron.php | 2 + src/Worker/UpdateAllSuggestions.php | 41 ++++++++++++++++ src/Worker/UpdateSuggestions.php | 35 ++++++++++++++ static/dbstructure.config.php | 14 +++++- view/theme/vier/theme.php | 2 +- 13 files changed, 218 insertions(+), 17 deletions(-) create mode 100644 doc/database/db_account-suggestion.md create mode 100644 src/Worker/UpdateAllSuggestions.php create mode 100644 src/Worker/UpdateSuggestions.php diff --git a/database.sql b/database.sql index 4e940b3197..cf07937725 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.12-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1495 +-- DB_UPDATE_VERSION 1496 -- ------------------------------------------ @@ -309,6 +309,20 @@ CREATE TABLE IF NOT EXISTS `2fa_trusted_browser` ( FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Two-factor authentication trusted browsers'; +-- +-- TABLE account-suggestion +-- +CREATE TABLE IF NOT EXISTS `account-suggestion` ( + `uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the account url', + `uid` mediumint unsigned NOT NULL COMMENT 'User ID', + `level` smallint unsigned COMMENT 'level of closeness', + `ignore` boolean NOT NULL DEFAULT '0' COMMENT 'If set, this account will not be suggested again', + PRIMARY KEY(`uid`,`uri-id`), + INDEX `uri-id_uid` (`uri-id`,`uid`), + FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Account suggestion'; + -- -- TABLE account-user -- diff --git a/doc/database.md b/doc/database.md index 4259749d2a..ec8d16b2cd 100644 --- a/doc/database.md +++ b/doc/database.md @@ -8,6 +8,7 @@ Database Tables | [2fa_app_specific_password](help/database/db_2fa_app_specific_password) | Two-factor app-specific _password | | [2fa_recovery_codes](help/database/db_2fa_recovery_codes) | Two-factor authentication recovery codes | | [2fa_trusted_browser](help/database/db_2fa_trusted_browser) | Two-factor authentication trusted browsers | +| [account-suggestion](help/database/db_account-suggestion) | Account suggestion | | [account-user](help/database/db_account-user) | Remote and local accounts | | [addon](help/database/db_addon) | registered addons | | [apcontact](help/database/db_apcontact) | ActivityPub compatible contacts - used in the ActivityPub implementation | diff --git a/doc/database/db_account-suggestion.md b/doc/database/db_account-suggestion.md new file mode 100644 index 0000000000..c86ae2f218 --- /dev/null +++ b/doc/database/db_account-suggestion.md @@ -0,0 +1,32 @@ +Table account-suggestion +=========== + +Account suggestion + +Fields +------ + +| Field | Description | Type | Null | Key | Default | Extra | +| ------ | ------------------------------------------------------------ | ------------------ | ---- | --- | ------- | ----- | +| uri-id | Id of the item-uri table entry that contains the account url | int unsigned | NO | PRI | NULL | | +| uid | User ID | mediumint unsigned | NO | PRI | NULL | | +| level | level of closeness | smallint unsigned | YES | | NULL | | +| ignore | If set, this account will not be suggested again | boolean | NO | | 0 | | + +Indexes +------------ + +| Name | Fields | +| ---------- | ----------- | +| PRIMARY | uid, uri-id | +| uri-id_uid | uri-id, uid | + +Foreign Keys +------------ + +| Field | Target Table | Target Field | +|-------|--------------|--------------| +| uri-id | [item-uri](help/database/db_item-uri) | id | +| uid | [user](help/database/db_user) | uid | + +Return to [database documentation](help/database) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 9d78e5892a..44f3fa02fa 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -167,9 +167,23 @@ class Status extends BaseFactory if (!empty($shared)) { $shared_uri_id = $shared['post']['uri-id']; - $mentions = array_merge($mentions, $this->mstdnMentionFactory->createFromUriId($shared_uri_id)->getArrayCopy()); - $tags = array_merge($tags, $this->mstdnTagFactory->createFromUriId($shared_uri_id)); - $attachments = array_merge($attachments, $this->mstdnAttachementFactory->createFromUriId($shared_uri_id)); + foreach ($this->mstdnMentionFactory->createFromUriId($shared_uri_id)->getArrayCopy() as $mention) { + if (!in_array($mention, $mentions)) { + $mentions[] = $mention; + } + } + + foreach ($this->mstdnTagFactory->createFromUriId($shared_uri_id) as $tag) { + if (!in_array($tag, $tags)) { + $tags[] = $tag; + } + } + + foreach ($this->mstdnAttachementFactory->createFromUriId($shared_uri_id) as $attachment) { + if (!in_array($attachment, $attachments)) { + $attachments[] = $attachment; + } + } if (empty($card->toArray())) { $card = $this->mstdnCardFactory->createFromUriId($shared_uri_id); @@ -190,7 +204,7 @@ class Status extends BaseFactory if ($is_reshare) { $reshare = $this->createFromUriId($uriId, $uid, false)->toArray(); } - +// $mentions = array_unique($mentions); return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $reshare, $poll); } diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index ae6859cdd9..5f2f07d397 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -260,6 +260,48 @@ class Relation return true; } + /** + * Update contact suggestions for a given user + * + * @param integer $uid + * @return void + */ + static public function updateSuggestions(int $uid) + { + if (DI::pConfig()->get($uid, 'suggestion', 'last_update') + 3600 > time()) { + 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 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 * @@ -285,11 +327,12 @@ class Relation (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 `id` = `cid`) - AND NOT `hidden` AND `network` IN (?, ?, ?, ?)", + 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, @@ -315,9 +358,10 @@ class Relation (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 `id` = `cid`) - AND NOT `hidden` AND `network` IN (?, ?, ?, ?)", + 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] ); @@ -335,9 +379,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 (?, ?, ?, ?)", + 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], + Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid], ['order' => ['last-item' => true], 'limit' => $totallimit] ); @@ -355,9 +400,10 @@ 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 `nurl` = `nurl`) - AND NOT `hidden` AND `uid` = ? AND `network` IN (?, ?, ?, ?)", + 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], + Protocol::ACTIVITYPUB, Protocol::DFRN, $diaspora, $ostatus, $uid], ['order' => ['last-item' => true], 'limit' => $totallimit] ); diff --git a/src/Module/Api/Mastodon/Suggestions.php b/src/Module/Api/Mastodon/Suggestions.php index 6eb2509269..f25b4cacfd 100644 --- a/src/Module/Api/Mastodon/Suggestions.php +++ b/src/Module/Api/Mastodon/Suggestions.php @@ -43,7 +43,7 @@ class Suggestions extends BaseApi 'limit' => 40, // Maximum number of results to return. Defaults to 40. ], $request); - $suggestions = Contact\Relation::getSuggestions($uid, 0, $request['limit']); + $suggestions = Contact\Relation::getCachedSuggestions($uid, 0, $request['limit']); $accounts = []; diff --git a/src/Module/Contact/Suggestions.php b/src/Module/Contact/Suggestions.php index 86e3f6cc8a..7a4816f498 100644 --- a/src/Module/Contact/Suggestions.php +++ b/src/Module/Contact/Suggestions.php @@ -57,7 +57,7 @@ class Suggestions extends \Friendica\BaseModule $this->page['aside'] .= Widget::findPeople(); $this->page['aside'] .= Widget::follow(); - $contacts = Contact\Relation::getSuggestions($this->session->getLocalUserId()); + $contacts = Contact\Relation::getCachedSuggestions($this->session->getLocalUserId()); if (!$contacts) { return $this->t('No suggestions available. If this is a new site, please try again in 24 hours.'); } diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index c38a2eb6dd..61ac4fae00 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -38,6 +38,7 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use LightOpenID; use Friendica\Core\L10n; +use Friendica\Core\Worker; use Psr\Log\LoggerInterface; /** @@ -356,6 +357,9 @@ class Authentication // Set the login date for all identities of the user $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['parent-uid' => $user_record['uid'], 'account_removed' => false]); + + // Update suggestions upon login + Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); } if ($login_initial) { diff --git a/src/Worker/Cron.php b/src/Worker/Cron.php index e0ef134a23..d450f4cd5b 100644 --- a/src/Worker/Cron.php +++ b/src/Worker/Cron.php @@ -130,6 +130,8 @@ class Cron Worker::add(Worker::PRIORITY_LOW, 'CheckDeletedContacts'); + Worker::add(Worker::PRIORITY_LOW, 'UpdateAllSuggestions'); + if (DI::config()->get('system', 'optimize_tables')) { Worker::add(Worker::PRIORITY_LOW, 'OptimizeTables'); } diff --git a/src/Worker/UpdateAllSuggestions.php b/src/Worker/UpdateAllSuggestions.php new file mode 100644 index 0000000000..b1c84b639e --- /dev/null +++ b/src/Worker/UpdateAllSuggestions.php @@ -0,0 +1,41 @@ +. + * + */ + +namespace Friendica\Worker; + +use Friendica\Database\DBA; +use Friendica\Model\Contact; +use Friendica\Util\DateTimeFormat; + +/** + * Update contact suggestions for all aktive users + */ +class UpdateAllSuggestions +{ + public static function execute() + { + $users = DBA::select('user', ['uid'], ["`login_date` > ?", DateTimeFormat::utc('now - 7 days')]); + while ($user = DBA::fetch($users)) { + Contact\Relation::updateSuggestions($user['uid']); + } + DBA::close($users); + } +} diff --git a/src/Worker/UpdateSuggestions.php b/src/Worker/UpdateSuggestions.php new file mode 100644 index 0000000000..c756ed10f5 --- /dev/null +++ b/src/Worker/UpdateSuggestions.php @@ -0,0 +1,35 @@ +. + * + */ + +namespace Friendica\Worker; + +use Friendica\Model\Contact; + +/** + * Update contact suggestions + */ +class UpdateSuggestions +{ + public static function execute(int $uid) + { + Contact\Relation::updateSuggestions($uid); + } +} diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 9ec2ae52ed..55c900916b 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1495); + define('DB_UPDATE_VERSION', 1496); } return [ @@ -371,6 +371,18 @@ return [ "uid" => ["uid"], ] ], + "account-suggestion" => [ + "comment" => "Account suggestion", + "fields" => [ + "uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table entry that contains the account url"], + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "primary" => "1", "foreign" => ["user" => "uid"], "comment" => "User ID"], + "level" => ["type" => "smallint unsigned", "comment" => "level of closeness"], + "ignore" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "If set, this account will not be suggested again"], ], + "indexes" => [ + "PRIMARY" => ["uid", "uri-id"], + "uri-id_uid" => ["uri-id", "uid"], + ] + ], "account-user" => [ "comment" => "Remote and local accounts", "fields" => [ diff --git a/view/theme/vier/theme.php b/view/theme/vier/theme.php index 006450edfc..062e4a105c 100644 --- a/view/theme/vier/theme.php +++ b/view/theme/vier/theme.php @@ -144,7 +144,7 @@ function vier_community_info() // comunity_profiles if ($show_profiles) { - $contacts = Contact\Relation::getSuggestions(DI::userSession()->getLocalUserId(), 0, 9); + $contacts = Contact\Relation::getCachedSuggestions(DI::userSession()->getLocalUserId(), 0, 9); $tpl = Renderer::getMarkupTemplate('ch_directory_item.tpl'); if (DBA::isResult($contacts)) { From 1ced4673fe4dfbfffc96ba394eb9e9ad06d56e2b Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 30 Nov 2022 13:35:57 +0000 Subject: [PATCH 02/12] Indention --- src/Factory/Api/Mastodon/Status.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 44f3fa02fa..7aa31077ba 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -169,13 +169,13 @@ class Status extends BaseFactory foreach ($this->mstdnMentionFactory->createFromUriId($shared_uri_id)->getArrayCopy() as $mention) { if (!in_array($mention, $mentions)) { - $mentions[] = $mention; + $mentions[] = $mention; } } foreach ($this->mstdnTagFactory->createFromUriId($shared_uri_id) as $tag) { if (!in_array($tag, $tags)) { - $tags[] = $tag; + $tags[] = $tag; } } From fbcc56d42dfcf5e628fe6c5fd7be3be598b53797 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 30 Nov 2022 14:33:55 +0000 Subject: [PATCH 03/12] Changes after code review --- src/Factory/Api/Mastodon/Status.php | 2 +- src/Model/Contact/Relation.php | 2 +- src/Worker/UpdateAllSuggestions.php | 2 +- src/Worker/UpdateSuggestions.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 7aa31077ba..dba74b1407 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -204,7 +204,7 @@ class Status extends BaseFactory if ($is_reshare) { $reshare = $this->createFromUriId($uriId, $uid, false)->toArray(); } -// $mentions = array_unique($mentions); + return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $reshare, $poll); } diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index 5f2f07d397..5a85ebebc5 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -266,7 +266,7 @@ class Relation * @param integer $uid * @return void */ - static public function updateSuggestions(int $uid) + static public function updateCachedSuggestions(int $uid) { if (DI::pConfig()->get($uid, 'suggestion', 'last_update') + 3600 > time()) { return; diff --git a/src/Worker/UpdateAllSuggestions.php b/src/Worker/UpdateAllSuggestions.php index b1c84b639e..5bc6476145 100644 --- a/src/Worker/UpdateAllSuggestions.php +++ b/src/Worker/UpdateAllSuggestions.php @@ -34,7 +34,7 @@ class UpdateAllSuggestions { $users = DBA::select('user', ['uid'], ["`login_date` > ?", DateTimeFormat::utc('now - 7 days')]); while ($user = DBA::fetch($users)) { - Contact\Relation::updateSuggestions($user['uid']); + Contact\Relation::updateCachedSuggestions($user['uid']); } DBA::close($users); } diff --git a/src/Worker/UpdateSuggestions.php b/src/Worker/UpdateSuggestions.php index c756ed10f5..509fee05a9 100644 --- a/src/Worker/UpdateSuggestions.php +++ b/src/Worker/UpdateSuggestions.php @@ -30,6 +30,6 @@ class UpdateSuggestions { public static function execute(int $uid) { - Contact\Relation::updateSuggestions($uid); + Contact\Relation::updateCachedSuggestions($uid); } } From f905220923c63ddf3cca28d0d88736533da1db74 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 30 Nov 2022 22:34:50 +0000 Subject: [PATCH 04/12] New field to show the day of the last activity --- database.sql | 1 + doc/database/db_user.md | 1 + src/Model/Contact/Relation.php | 13 ++++++++++++- src/Model/User.php | 16 ++++++++++++++++ src/Security/Authentication.php | 9 +++++++-- src/Security/OAuth.php | 11 +++++++++++ src/Worker/UpdateAllSuggestions.php | 2 +- static/dbstructure.config.php | 1 + 8 files changed, 50 insertions(+), 4 deletions(-) diff --git a/database.sql b/database.sql index cf07937725..f41defe428 100644 --- a/database.sql +++ b/database.sql @@ -59,6 +59,7 @@ CREATE TABLE IF NOT EXISTS `user` ( `language` varchar(32) NOT NULL DEFAULT 'en' COMMENT 'default language', `register_date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'timestamp of registration', `login_date` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'timestamp of last login', + `last-activity` date COMMENT 'Day of the last activity', `default-location` varchar(255) NOT NULL DEFAULT '' COMMENT 'Default for item.location', `allow_location` boolean NOT NULL DEFAULT '0' COMMENT '1 allows to display the location', `theme` varchar(255) NOT NULL DEFAULT '' COMMENT 'user theme preference', diff --git a/doc/database/db_user.md b/doc/database/db_user.md index 85fe895e98..7f58ce58f1 100644 --- a/doc/database/db_user.md +++ b/doc/database/db_user.md @@ -21,6 +21,7 @@ Fields | language | default language | varchar(32) | NO | | en | | | register_date | timestamp of registration | datetime | NO | | 0001-01-01 00:00:00 | | | login_date | timestamp of last login | datetime | NO | | 0001-01-01 00:00:00 | | +| last-activity | Day of the last activity | date | YES | | NULL | | | default-location | Default for item.location | varchar(255) | NO | | | | | allow_location | 1 allows to display the location | boolean | NO | | 0 | | | theme | user theme preference | varchar(255) | NO | | | | diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index 5a85ebebc5..bae59f48c5 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -260,6 +260,17 @@ class Relation return true; } + /** + * 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 * @@ -268,7 +279,7 @@ class Relation */ static public function updateCachedSuggestions(int $uid) { - if (DI::pConfig()->get($uid, 'suggestion', 'last_update') + 3600 > time()) { + if (!self::areSuggestionsOutdated($uid)) { return; } diff --git a/src/Model/User.php b/src/Model/User.php index 73c380561c..6d7efafb18 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -665,6 +665,22 @@ class User return $user; } + /** + * Update the day of the last activity of the given user + * + * @param integer $uid + * @return void + */ + public static function updateLastActivity(int $uid) + { + $user = User::getById($uid, ['last-activity']); + $current_day = date('Y-m-d'); + + if ($user['last-activity'] != $current_day) { + User::update(['last-activity' => $current_day], $uid); + } + } + /** * Generates a human-readable random password * diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index 61ac4fae00..62318bedbf 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -39,6 +39,7 @@ use Friendica\Util\Network; use LightOpenID; use Friendica\Core\L10n; use Friendica\Core\Worker; +use Friendica\Model\Contact; use Psr\Log\LoggerInterface; /** @@ -358,8 +359,12 @@ class Authentication $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['parent-uid' => $user_record['uid'], 'account_removed' => false]); - // Update suggestions upon login - Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); + User::updateLastActivity($user_record['uid']); + + // Regularly update suggestions + if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { + Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); + } } if ($login_initial) { diff --git a/src/Security/OAuth.php b/src/Security/OAuth.php index 3eaa022c50..27a3dfa11b 100644 --- a/src/Security/OAuth.php +++ b/src/Security/OAuth.php @@ -22,8 +22,11 @@ namespace Friendica\Security; use Friendica\Core\Logger; +use Friendica\Core\Worker; use Friendica\Database\Database; use Friendica\Database\DBA; +use Friendica\Model\Contact; +use Friendica\Model\User; use Friendica\Module\BaseApi; use Friendica\Util\DateTimeFormat; @@ -100,6 +103,14 @@ class OAuth return []; } Logger::debug('Token found', $token); + + User::updateLastActivity($token['uid']); + + // Regularly update suggestions + if (Contact\Relation::areSuggestionsOutdated($token['uid'])) { + Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $token['uid']); + } + return $token; } diff --git a/src/Worker/UpdateAllSuggestions.php b/src/Worker/UpdateAllSuggestions.php index 5bc6476145..478ba89a96 100644 --- a/src/Worker/UpdateAllSuggestions.php +++ b/src/Worker/UpdateAllSuggestions.php @@ -32,7 +32,7 @@ class UpdateAllSuggestions { public static function execute() { - $users = DBA::select('user', ['uid'], ["`login_date` > ?", DateTimeFormat::utc('now - 7 days')]); + $users = DBA::select('user', ['uid'], ["`last-activity` > ?", DateTimeFormat::utc('now - 3 days', 'Y-m-d')]); while ($user = DBA::fetch($users)) { Contact\Relation::updateCachedSuggestions($user['uid']); } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 55c900916b..2979ca80d0 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -115,6 +115,7 @@ return [ "language" => ["type" => "varchar(32)", "not null" => "1", "default" => "en", "comment" => "default language"], "register_date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "timestamp of registration"], "login_date" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "timestamp of last login"], + "last-activity" => ["type" => "date", "comment" => "Day of the last activity"], "default-location" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Default for item.location"], "allow_location" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 allows to display the location"], "theme" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "user theme preference"], From ed1a879b7b4921b4a486b6544c0a3e808e45c456 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 30 Nov 2022 22:36:58 +0000 Subject: [PATCH 05/12] Use "utcNow" --- src/Model/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/User.php b/src/Model/User.php index 6d7efafb18..eb8d22c58c 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -674,7 +674,7 @@ class User public static function updateLastActivity(int $uid) { $user = User::getById($uid, ['last-activity']); - $current_day = date('Y-m-d'); + $current_day = DateTimeFormat::utcNow('Y-m-d'); if ($user['last-activity'] != $current_day) { User::update(['last-activity' => $current_day], $uid); From c56e4222dcdac3a4e496a28b87f94e9d5adeb6a2 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 1 Dec 2022 05:50:34 +0000 Subject: [PATCH 06/12] Debug the failing test --- src/Security/Authentication.php | 8 ++++---- src/Security/OAuth.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index 62318bedbf..a9bf70d214 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -359,12 +359,12 @@ class Authentication $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['parent-uid' => $user_record['uid'], 'account_removed' => false]); - User::updateLastActivity($user_record['uid']); +// User::updateLastActivity($user_record['uid']); // Regularly update suggestions - if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { - Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); - } +// if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { +// Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); +// } } if ($login_initial) { diff --git a/src/Security/OAuth.php b/src/Security/OAuth.php index 27a3dfa11b..eb4f68b7fd 100644 --- a/src/Security/OAuth.php +++ b/src/Security/OAuth.php @@ -104,12 +104,12 @@ class OAuth } Logger::debug('Token found', $token); - User::updateLastActivity($token['uid']); +// User::updateLastActivity($token['uid']); // Regularly update suggestions - if (Contact\Relation::areSuggestionsOutdated($token['uid'])) { - Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $token['uid']); - } +// if (Contact\Relation::areSuggestionsOutdated($token['uid'])) { +// Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $token['uid']); +// } return $token; } From 910a76812a67b331c5c69a7da97f5a6b6eeabd67 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 1 Dec 2022 05:53:18 +0000 Subject: [PATCH 07/12] Reenable worker call --- src/Security/Authentication.php | 6 +++--- src/Security/OAuth.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index a9bf70d214..47407b1338 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -362,9 +362,9 @@ class Authentication // User::updateLastActivity($user_record['uid']); // Regularly update suggestions -// if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { -// Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); -// } + if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { + Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); + } } if ($login_initial) { diff --git a/src/Security/OAuth.php b/src/Security/OAuth.php index eb4f68b7fd..54b412735a 100644 --- a/src/Security/OAuth.php +++ b/src/Security/OAuth.php @@ -107,9 +107,9 @@ class OAuth // User::updateLastActivity($token['uid']); // Regularly update suggestions -// if (Contact\Relation::areSuggestionsOutdated($token['uid'])) { -// Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $token['uid']); -// } + if (Contact\Relation::areSuggestionsOutdated($token['uid'])) { + Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $token['uid']); + } return $token; } From 5201d87b3f068c7c7dee2ae4999a85272710ed20 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 1 Dec 2022 05:54:42 +0000 Subject: [PATCH 08/12] Reenable last acttivity update --- src/Security/Authentication.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index 47407b1338..62318bedbf 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -359,7 +359,7 @@ class Authentication $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['parent-uid' => $user_record['uid'], 'account_removed' => false]); -// User::updateLastActivity($user_record['uid']); + User::updateLastActivity($user_record['uid']); // Regularly update suggestions if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { From 431eb34a1cebd48b05bee371d85a19bb2a9c9e78 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 1 Dec 2022 05:57:29 +0000 Subject: [PATCH 09/12] Deactivate setting last activity --- src/Security/Authentication.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index 62318bedbf..47407b1338 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -359,7 +359,7 @@ class Authentication $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['parent-uid' => $user_record['uid'], 'account_removed' => false]); - User::updateLastActivity($user_record['uid']); +// User::updateLastActivity($user_record['uid']); // Regularly update suggestions if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { From 8e0196fec39b52b54a715ff0f32e80040313d511 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 1 Dec 2022 06:02:51 +0000 Subject: [PATCH 10/12] Update the last activity in OAuth --- src/Security/Authentication.php | 4 +--- src/Security/OAuth.php | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index 47407b1338..f550501ede 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -353,14 +353,12 @@ class Authentication $this->setXAccMgmtStatusHeader($user_record); if ($login_initial || $login_refresh) { - $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['uid' => $user_record['uid']]); + $this->dba->update('user', ['last-activity' => DateTimeFormat::utcNow('Y-m-d'), 'login_date' => DateTimeFormat::utcNow()], ['uid' => $user_record['uid']]); // Set the login date for all identities of the user $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['parent-uid' => $user_record['uid'], 'account_removed' => false]); -// User::updateLastActivity($user_record['uid']); - // Regularly update suggestions if (Contact\Relation::areSuggestionsOutdated($user_record['uid'])) { Worker::add(Worker::PRIORITY_MEDIUM, 'UpdateSuggestions', $user_record['uid']); diff --git a/src/Security/OAuth.php b/src/Security/OAuth.php index 54b412735a..27a3dfa11b 100644 --- a/src/Security/OAuth.php +++ b/src/Security/OAuth.php @@ -104,7 +104,7 @@ class OAuth } Logger::debug('Token found', $token); -// User::updateLastActivity($token['uid']); + User::updateLastActivity($token['uid']); // Regularly update suggestions if (Contact\Relation::areSuggestionsOutdated($token['uid'])) { From 146f874c2e2935ae82c563f71d174dadac5d20ce Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 1 Dec 2022 06:12:13 +0000 Subject: [PATCH 11/12] Avoid 'Undefined array key "last-activity"' --- src/Model/User.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Model/User.php b/src/Model/User.php index eb8d22c58c..40384b619b 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -674,6 +674,10 @@ class User public static function updateLastActivity(int $uid) { $user = User::getById($uid, ['last-activity']); + if (empty($user)) { + return; + } + $current_day = DateTimeFormat::utcNow('Y-m-d'); if ($user['last-activity'] != $current_day) { From 1d00947bcde4b75cec21c9bf813ef8f109bafc1b Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 1 Dec 2022 07:07:59 +0000 Subject: [PATCH 12/12] Don't fetch sugestions for the system user / catch error on contact timeline --- src/Model/Contact/Relation.php | 4 ++++ src/Module/Api/Mastodon/Accounts/Statuses.php | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index bae59f48c5..5616148fa0 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -323,6 +323,10 @@ class Relation */ 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 = []; diff --git a/src/Module/Api/Mastodon/Accounts/Statuses.php b/src/Module/Api/Mastodon/Accounts/Statuses.php index b244c56fb2..7de8699401 100644 --- a/src/Module/Api/Mastodon/Accounts/Statuses.php +++ b/src/Module/Api/Mastodon/Accounts/Statuses.php @@ -21,6 +21,7 @@ namespace Friendica\Module\Api\Mastodon\Accounts; +use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Database\DBA; @@ -113,7 +114,11 @@ class Statuses extends BaseApi $statuses = []; while ($item = Post::fetch($items)) { self::setBoundaries($item['uri-id']); - $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid); + try { + $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid); + } catch (\Throwable $th) { + Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); + } } DBA::close($items);