From 196219383e2d7f8a81f0565c65f68f67c3068e3f Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 4 Sep 2023 22:22:25 +0000 Subject: [PATCH 1/9] "Channel" is split into three classes --- src/Content/Entity/Conversation/Channel.php | 48 +++++++++++ src/Model/Channel.php | 72 +++++++++++++++++ src/Module/Conversation/Channel.php | 90 +++++---------------- 3 files changed, 141 insertions(+), 69 deletions(-) create mode 100644 src/Content/Entity/Conversation/Channel.php create mode 100644 src/Model/Channel.php diff --git a/src/Content/Entity/Conversation/Channel.php b/src/Content/Entity/Conversation/Channel.php new file mode 100644 index 0000000000..0462755e03 --- /dev/null +++ b/src/Content/Entity/Conversation/Channel.php @@ -0,0 +1,48 @@ +. + * + */ + +namespace Friendica\Content\Entity\Conversation; + +/** + * @property-read string $code Channel code + * @property-read string $label Channel label + * @property-read string $description Channel description + * @property-read string $accessKey Access key + */ +final class Channel extends \Friendica\BaseEntity +{ + /** @var string */ + protected $code; + /** @var string */ + protected $label; + /** @var string */ + protected $description; + /** @var string */ + protected $accessKey; + + public function __construct(string $code, string $label, string $description, string $accessKey) + { + $this->code = $code; + $this->label = $label; + $this->description = $description; + $this->accessKey = $accessKey; + } +} diff --git a/src/Model/Channel.php b/src/Model/Channel.php new file mode 100644 index 0000000000..52634aaa30 --- /dev/null +++ b/src/Model/Channel.php @@ -0,0 +1,72 @@ +. + * + */ + + namespace Friendica\Model; + +use Friendica\Model\User; +use Friendica\Content\Entity\Conversation\Channel as ChannelEntity; +use Friendica\Core\L10n; +use Friendica\Database\Database; +use Psr\Log\LoggerInterface; + +final class Channel extends \Friendica\BaseModel +{ + const WHATSHOT = 'whatshot'; + const FORYOU = 'foryou'; + const FOLLOWERS = 'followers'; + const IMAGE = 'image'; + const VIDEO = 'video'; + const AUDIO = 'audio'; + const LANGUAGE = 'language'; + + /** @var L10n */ + protected $l10n; + + public function __construct(L10n $l10n, Database $database, LoggerInterface $logger, array $data = []) + { + parent::__construct($database, $logger, $data); + + $this->l10n = $l10n; + } + + /** + * List of available channels + * + * @param integer $uid + * @return array + */ + public function getForUser(int $uid): array + { + $language = User::getLanguageCode($uid); + $languages = $this->l10n->getAvailableLanguages(true); + + $tabs = [ + new ChannelEntity(self::FORYOU, $this->l10n->t('For you'), $this->l10n->t('Posts from contacts you interact with and who interact with you'), 'y'), + new ChannelEntity(self::WHATSHOT, $this->l10n->t('What\'s Hot'), $this->l10n->t('Posts with a lot of interactions'), 'h'), + new ChannelEntity(self::LANGUAGE, $languages[$language], $this->l10n->t('Posts in %s', $languages[$language]), 'g'), + new ChannelEntity(self::FOLLOWERS, $this->l10n->t('Followers'), $this->l10n->t('Posts from your followers that you don\'t follow'), 'f'), + new ChannelEntity(self::IMAGE, $this->l10n->t('Images'), $this->l10n->t('Posts with images'), 'i'), + new ChannelEntity(self::AUDIO, $this->l10n->t('Audio'), $this->l10n->t('Posts with audio'), 'd'), + new ChannelEntity(self::VIDEO, $this->l10n->t('Videos'), $this->l10n->t('Posts with videos'), 'v'), + ]; + return $tabs; + } +} diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index eacbb2201e..be9a2791a5 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -45,6 +45,7 @@ use Friendica\Module\Security\Login; use Friendica\Network\HTTPException; use Friendica\Core\Session\Model\UserSession; use Friendica\Database\Database; +use Friendica\Model\Channel as ChannelModel; use Friendica\Model\Item; use Friendica\Module\Response; use Friendica\Navigation\SystemMessages; @@ -87,12 +88,15 @@ class Channel extends BaseModule protected $pConfig; /** @var Database */ protected $database; + /** @var ChannelModel */ + protected $channel; - public function __construct(SystemMessages $systemMessages, Database $database, IManagePersonalConfigValues $pConfig, Mode $mode, Conversation $conversation, App\Page $page, IManageConfigValues $config, ICanCache $cache, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + public function __construct(ChannelModel $channel, SystemMessages $systemMessages, Database $database, IManagePersonalConfigValues $pConfig, Mode $mode, Conversation $conversation, App\Page $page, IManageConfigValues $config, ICanCache $cache, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + $this->channel = $channel; $this->systemMessages = $systemMessages; $this->database = $database; $this->pConfig = $pConfig; @@ -126,71 +130,16 @@ class Channel extends BaseModule if (empty($request['mode']) || ($request['mode'] != 'raw')) { $tabs = []; - $tabs[] = [ - 'label' => $this->l10n->t('For you'), - 'url' => 'channel/' . self::FORYOU, - 'sel' => self::$content == self::FORYOU ? 'active' : '', - 'title' => $this->l10n->t('Posts from contacts you interact with and who interact with you'), - 'id' => 'channel-foryou-tab', - 'accesskey' => 'y' - ]; - - $tabs[] = [ - 'label' => $this->l10n->t('What\'s Hot'), - 'url' => 'channel/' . self::WHATSHOT, - 'sel' => self::$content == self::WHATSHOT ? 'active' : '', - 'title' => $this->l10n->t('Posts with a lot of interactions'), - 'id' => 'channel-whatshot-tab', - 'accesskey' => 'h' - ]; - - $language = User::getLanguageCode($this->session->getLocalUserId()); - $languages = $this->l10n->getAvailableLanguages(true); - - $tabs[] = [ - 'label' => $languages[$language], - 'url' => 'channel/' . self::LANGUAGE, - 'sel' => self::$content == self::LANGUAGE ? 'active' : '', - 'title' => $this->l10n->t('Posts in %s', $languages[$language]), - 'id' => 'channel-language-tab', - 'accesskey' => 'g' - ]; - - $tabs[] = [ - 'label' => $this->l10n->t('Followers'), - 'url' => 'channel/' . self::FOLLOWERS, - 'sel' => self::$content == self::FOLLOWERS ? 'active' : '', - 'title' => $this->l10n->t('Posts from your followers that you don\'t follow'), - 'id' => 'channel-followers-tab', - 'accesskey' => 'f' - ]; - - $tabs[] = [ - 'label' => $this->l10n->t('Images'), - 'url' => 'channel/' . self::IMAGE, - 'sel' => self::$content == self::IMAGE ? 'active' : '', - 'title' => $this->l10n->t('Posts with images'), - 'id' => 'channel-image-tab', - 'accesskey' => 'i' - ]; - - $tabs[] = [ - 'label' => $this->l10n->t('Audio'), - 'url' => 'channel/' . self::AUDIO, - 'sel' => self::$content == self::AUDIO ? 'active' : '', - 'title' => $this->l10n->t('Posts with audio'), - 'id' => 'channel-audio-tab', - 'accesskey' => 'd' - ]; - - $tabs[] = [ - 'label' => $this->l10n->t('Videos'), - 'url' => 'channel/' . self::VIDEO, - 'sel' => self::$content == self::VIDEO ? 'active' : '', - 'title' => $this->l10n->t('Posts with videos'), - 'id' => 'channel-video-tab', - 'accesskey' => 'v' - ]; + foreach ($this->channel->getForUser($this->session->getLocalUserId()) as $tab) { + $tabs[] = [ + 'label' => $tab->label, + 'url' => 'channel/' . $tab->code, + 'sel' => self::$content == $tab->code ? 'active' : '', + 'title' => $tab->description, + 'id' => 'channel-' . $tab->code . '-tab', + 'accesskey' => $tab->accessKey, + ]; + } $tab_tpl = Renderer::getMarkupTemplate('common_tabs.tpl'); $o .= Renderer::replaceMacros($tab_tpl, ['$tabs' => $tabs]); @@ -431,7 +380,8 @@ class Channel extends BaseModule return 0; } - $this->cache->set($cache_key, $comments, Duration::HOUR); + $this->cache->set($cache_key, $comments, Duration::HALF_HOUR); + $this->logger->debug('Calculated median comments', ['divider' => $divider, 'median' => $comments]); return $comments; } @@ -450,7 +400,8 @@ class Channel extends BaseModule return 0; } - $this->cache->set($cache_key, $activities, Duration::HOUR); + $this->cache->set($cache_key, $activities, Duration::HALF_HOUR); + $this->logger->debug('Calculated median activities', ['divider' => $divider, 'median' => $activities]); return $activities; } @@ -469,7 +420,8 @@ class Channel extends BaseModule return 0; } - $this->cache->set($cache_key, $score, Duration::HOUR); + $this->cache->set($cache_key, $score, Duration::HALF_HOUR); + $this->logger->debug('Calculated median score', ['cid' => $cid, 'divider' => $divider, 'median' => $score]); return $score; } } From f7170343f7be32d7056e4e0bfbbe9729fe74b876 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 4 Sep 2023 22:31:06 +0000 Subject: [PATCH 2/9] Constants moved to model class --- src/Module/Conversation/Channel.php | 32 +++++++++++------------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index be9a2791a5..186413c3b7 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -54,14 +54,6 @@ use Psr\Log\LoggerInterface; class Channel extends BaseModule { - const WHATSHOT = 'whatshot'; - const FORYOU = 'foryou'; - const FOLLOWERS = 'followers'; - const IMAGE = 'image'; - const VIDEO = 'video'; - const AUDIO = 'audio'; - const LANGUAGE = 'language'; - protected static $content; protected static $accountTypeString; protected static $accountType; @@ -148,7 +140,7 @@ class Channel extends BaseModule $this->page['aside'] .= Widget::accountTypes('channel/' . self::$content, self::$accountTypeString); - if (!in_array(self::$content, [self::FOLLOWERS, self::FORYOU]) && $this->config->get('system', 'community_no_sharer')) { + if (!in_array(self::$content, [ChannelModel::FOLLOWERS, ChannelModel::FORYOU]) && $this->config->get('system', 'community_no_sharer')) { $path = self::$content; if (!empty($this->parameters['accounttype'])) { $path .= '/' . $this->parameters['accounttype']; @@ -225,10 +217,10 @@ class Channel extends BaseModule self::$content = $this->parameters['content'] ?? ''; if (!self::$content) { - self::$content = self::FORYOU; + self::$content = ChannelModel::FORYOU; } - if (!in_array(self::$content, [self::WHATSHOT, self::FORYOU, self::FOLLOWERS, self::IMAGE, self::VIDEO, self::AUDIO, self::LANGUAGE])) { + if (!in_array(self::$content, [ChannelModel::WHATSHOT, ChannelModel::FORYOU, ChannelModel::FOLLOWERS, ChannelModel::IMAGE, ChannelModel::VIDEO, ChannelModel::AUDIO, ChannelModel::LANGUAGE])) { throw new HTTPException\BadRequestException($this->l10n->t('Channel not available.')); } @@ -270,13 +262,13 @@ class Channel extends BaseModule */ protected function getItems(array $request) { - if (self::$content == self::WHATSHOT) { + if (self::$content == ChannelModel::WHATSHOT) { if (!is_null(self::$accountType)) { $condition = ["(`comments` >= ? OR `activities` >= ?) AND `contact-type` = ?", $this->getMedianComments(4), $this->getMedianActivities(4), self::$accountType]; } else { $condition = ["(`comments` >= ? OR `activities` >= ?) AND `contact-type` != ?", $this->getMedianComments(4), $this->getMedianActivities(4), Contact::TYPE_COMMUNITY]; } - } elseif (self::$content == self::FORYOU) { + } elseif (self::$content == ChannelModel::FORYOU) { $cid = Contact::getPublicIdByUserId($this->session->getLocalUserId()); $condition = ["(`owner-id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `thread-score` > ?) OR @@ -284,26 +276,26 @@ class Channel extends BaseModule ( `owner-id` IN (SELECT `pid` FROM `account-user-view` WHERE `uid` = ? AND `rel` IN (?, ?) AND `notify_new_posts`)))", $cid, $this->getMedianThreadScore($cid, 4), $this->getMedianComments(4), $this->getMedianActivities(4), $this->session->getLocalUserId(), Contact::FRIEND, Contact::SHARING, $this->session->getLocalUserId(), Contact::FRIEND, Contact::SHARING]; - } elseif (self::$content == self::FOLLOWERS) { + } elseif (self::$content == ChannelModel::FOLLOWERS) { $condition = ["`owner-id` IN (SELECT `pid` FROM `account-user-view` WHERE `uid` = ? AND `rel` = ?)", $this->session->getLocalUserId(), Contact::FOLLOWER]; - } elseif (self::$content == self::IMAGE) { + } elseif (self::$content == ChannelModel::IMAGE) { $condition = ["`media-type` & ?", 1]; - } elseif (self::$content == self::VIDEO) { + } elseif (self::$content == ChannelModel::VIDEO) { $condition = ["`media-type` & ?", 2]; - } elseif (self::$content == self::AUDIO) { + } elseif (self::$content == ChannelModel::AUDIO) { $condition = ["`media-type` & ?", 4]; - } elseif (self::$content == self::LANGUAGE) { + } elseif (self::$content == ChannelModel::LANGUAGE) { $condition = ["JSON_EXTRACT(JSON_KEYS(language), '$[0]') = ?", $this->l10n->convertCodeForLanguageDetection(User::getLanguageCode($this->session->getLocalUserId()))]; } - if (self::$content != self::LANGUAGE) { + if (self::$content != ChannelModel::LANGUAGE) { $condition = $this->addLanguageCondition($condition); } $condition[0] .= " AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` = `post-engagement`.`owner-id` AND (`ignored` OR `blocked` OR `collapsed`))"; $condition[] = $this->session->getLocalUserId(); - if ((self::$content != self::WHATSHOT) && !is_null(self::$accountType)) { + if ((self::$content != ChannelModel::WHATSHOT) && !is_null(self::$accountType)) { $condition[0] .= " AND `contact-type` = ?"; $condition[] = self::$accountType; } From 8b4309f1170e963ce462f78ba50a4d01fdc688bb Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 5 Sep 2023 05:08:19 +0000 Subject: [PATCH 3/9] Classes and constants moved --- .../Entity}/Channel.php | 10 +++++++- src/Model/Channel.php | 24 ++++++------------ src/Module/Conversation/Channel.php | 25 ++++++++++--------- 3 files changed, 30 insertions(+), 29 deletions(-) rename src/Content/{Entity/Conversation => Conversation/Entity}/Channel.php (85%) diff --git a/src/Content/Entity/Conversation/Channel.php b/src/Content/Conversation/Entity/Channel.php similarity index 85% rename from src/Content/Entity/Conversation/Channel.php rename to src/Content/Conversation/Entity/Channel.php index 0462755e03..8d1e899acf 100644 --- a/src/Content/Entity/Conversation/Channel.php +++ b/src/Content/Conversation/Entity/Channel.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Content\Entity\Conversation; +namespace Friendica\Content\Conversation\Entity; /** * @property-read string $code Channel code @@ -29,6 +29,14 @@ namespace Friendica\Content\Entity\Conversation; */ final class Channel extends \Friendica\BaseEntity { + const WHATSHOT = 'whatshot'; + const FORYOU = 'foryou'; + const FOLLOWERS = 'followers'; + const IMAGE = 'image'; + const VIDEO = 'video'; + const AUDIO = 'audio'; + const LANGUAGE = 'language'; + /** @var string */ protected $code; /** @var string */ diff --git a/src/Model/Channel.php b/src/Model/Channel.php index 52634aaa30..d6d4eaa55c 100644 --- a/src/Model/Channel.php +++ b/src/Model/Channel.php @@ -22,21 +22,13 @@ namespace Friendica\Model; use Friendica\Model\User; -use Friendica\Content\Entity\Conversation\Channel as ChannelEntity; +use Friendica\Content\Conversation\Entity\Channel as ChannelEntity; use Friendica\Core\L10n; use Friendica\Database\Database; use Psr\Log\LoggerInterface; final class Channel extends \Friendica\BaseModel { - const WHATSHOT = 'whatshot'; - const FORYOU = 'foryou'; - const FOLLOWERS = 'followers'; - const IMAGE = 'image'; - const VIDEO = 'video'; - const AUDIO = 'audio'; - const LANGUAGE = 'language'; - /** @var L10n */ protected $l10n; @@ -59,13 +51,13 @@ final class Channel extends \Friendica\BaseModel $languages = $this->l10n->getAvailableLanguages(true); $tabs = [ - new ChannelEntity(self::FORYOU, $this->l10n->t('For you'), $this->l10n->t('Posts from contacts you interact with and who interact with you'), 'y'), - new ChannelEntity(self::WHATSHOT, $this->l10n->t('What\'s Hot'), $this->l10n->t('Posts with a lot of interactions'), 'h'), - new ChannelEntity(self::LANGUAGE, $languages[$language], $this->l10n->t('Posts in %s', $languages[$language]), 'g'), - new ChannelEntity(self::FOLLOWERS, $this->l10n->t('Followers'), $this->l10n->t('Posts from your followers that you don\'t follow'), 'f'), - new ChannelEntity(self::IMAGE, $this->l10n->t('Images'), $this->l10n->t('Posts with images'), 'i'), - new ChannelEntity(self::AUDIO, $this->l10n->t('Audio'), $this->l10n->t('Posts with audio'), 'd'), - new ChannelEntity(self::VIDEO, $this->l10n->t('Videos'), $this->l10n->t('Posts with videos'), 'v'), + new ChannelEntity(ChannelEntity::FORYOU, $this->l10n->t('For you'), $this->l10n->t('Posts from contacts you interact with and who interact with you'), 'y'), + new ChannelEntity(ChannelEntity::WHATSHOT, $this->l10n->t('What\'s Hot'), $this->l10n->t('Posts with a lot of interactions'), 'h'), + new ChannelEntity(ChannelEntity::LANGUAGE, $languages[$language], $this->l10n->t('Posts in %s', $languages[$language]), 'g'), + new ChannelEntity(ChannelEntity::FOLLOWERS, $this->l10n->t('Followers'), $this->l10n->t('Posts from your followers that you don\'t follow'), 'f'), + new ChannelEntity(ChannelEntity::IMAGE, $this->l10n->t('Images'), $this->l10n->t('Posts with images'), 'i'), + new ChannelEntity(ChannelEntity::AUDIO, $this->l10n->t('Audio'), $this->l10n->t('Posts with audio'), 'd'), + new ChannelEntity(ChannelEntity::VIDEO, $this->l10n->t('Videos'), $this->l10n->t('Posts with videos'), 'v'), ]; return $tabs; } diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index 186413c3b7..3b85f7fb94 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -26,6 +26,7 @@ use Friendica\App\Mode; use Friendica\BaseModule; use Friendica\Content\BoundariesPager; use Friendica\Content\Conversation; +use Friendica\Content\Conversation\Entity\Channel as ChannelEntity; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Content\Text\HTML; @@ -140,7 +141,7 @@ class Channel extends BaseModule $this->page['aside'] .= Widget::accountTypes('channel/' . self::$content, self::$accountTypeString); - if (!in_array(self::$content, [ChannelModel::FOLLOWERS, ChannelModel::FORYOU]) && $this->config->get('system', 'community_no_sharer')) { + if (!in_array(self::$content, [ChannelEntity::FOLLOWERS, ChannelEntity::FORYOU]) && $this->config->get('system', 'community_no_sharer')) { $path = self::$content; if (!empty($this->parameters['accounttype'])) { $path .= '/' . $this->parameters['accounttype']; @@ -217,10 +218,10 @@ class Channel extends BaseModule self::$content = $this->parameters['content'] ?? ''; if (!self::$content) { - self::$content = ChannelModel::FORYOU; + self::$content = ChannelEntity::FORYOU; } - if (!in_array(self::$content, [ChannelModel::WHATSHOT, ChannelModel::FORYOU, ChannelModel::FOLLOWERS, ChannelModel::IMAGE, ChannelModel::VIDEO, ChannelModel::AUDIO, ChannelModel::LANGUAGE])) { + if (!in_array(self::$content, [ChannelEntity::WHATSHOT, ChannelEntity::FORYOU, ChannelEntity::FOLLOWERS, ChannelEntity::IMAGE, ChannelEntity::VIDEO, ChannelEntity::AUDIO, ChannelEntity::LANGUAGE])) { throw new HTTPException\BadRequestException($this->l10n->t('Channel not available.')); } @@ -262,13 +263,13 @@ class Channel extends BaseModule */ protected function getItems(array $request) { - if (self::$content == ChannelModel::WHATSHOT) { + if (self::$content == ChannelEntity::WHATSHOT) { if (!is_null(self::$accountType)) { $condition = ["(`comments` >= ? OR `activities` >= ?) AND `contact-type` = ?", $this->getMedianComments(4), $this->getMedianActivities(4), self::$accountType]; } else { $condition = ["(`comments` >= ? OR `activities` >= ?) AND `contact-type` != ?", $this->getMedianComments(4), $this->getMedianActivities(4), Contact::TYPE_COMMUNITY]; } - } elseif (self::$content == ChannelModel::FORYOU) { + } elseif (self::$content == ChannelEntity::FORYOU) { $cid = Contact::getPublicIdByUserId($this->session->getLocalUserId()); $condition = ["(`owner-id` IN (SELECT `relation-cid` FROM `contact-relation` WHERE `cid` = ? AND `thread-score` > ?) OR @@ -276,26 +277,26 @@ class Channel extends BaseModule ( `owner-id` IN (SELECT `pid` FROM `account-user-view` WHERE `uid` = ? AND `rel` IN (?, ?) AND `notify_new_posts`)))", $cid, $this->getMedianThreadScore($cid, 4), $this->getMedianComments(4), $this->getMedianActivities(4), $this->session->getLocalUserId(), Contact::FRIEND, Contact::SHARING, $this->session->getLocalUserId(), Contact::FRIEND, Contact::SHARING]; - } elseif (self::$content == ChannelModel::FOLLOWERS) { + } elseif (self::$content == ChannelEntity::FOLLOWERS) { $condition = ["`owner-id` IN (SELECT `pid` FROM `account-user-view` WHERE `uid` = ? AND `rel` = ?)", $this->session->getLocalUserId(), Contact::FOLLOWER]; - } elseif (self::$content == ChannelModel::IMAGE) { + } elseif (self::$content == ChannelEntity::IMAGE) { $condition = ["`media-type` & ?", 1]; - } elseif (self::$content == ChannelModel::VIDEO) { + } elseif (self::$content == ChannelEntity::VIDEO) { $condition = ["`media-type` & ?", 2]; - } elseif (self::$content == ChannelModel::AUDIO) { + } elseif (self::$content == ChannelEntity::AUDIO) { $condition = ["`media-type` & ?", 4]; - } elseif (self::$content == ChannelModel::LANGUAGE) { + } elseif (self::$content == ChannelEntity::LANGUAGE) { $condition = ["JSON_EXTRACT(JSON_KEYS(language), '$[0]') = ?", $this->l10n->convertCodeForLanguageDetection(User::getLanguageCode($this->session->getLocalUserId()))]; } - if (self::$content != ChannelModel::LANGUAGE) { + if (self::$content != ChannelEntity::LANGUAGE) { $condition = $this->addLanguageCondition($condition); } $condition[0] .= " AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` = `post-engagement`.`owner-id` AND (`ignored` OR `blocked` OR `collapsed`))"; $condition[] = $this->session->getLocalUserId(); - if ((self::$content != ChannelModel::WHATSHOT) && !is_null(self::$accountType)) { + if ((self::$content != ChannelEntity::WHATSHOT) && !is_null(self::$accountType)) { $condition[0] .= " AND `contact-type` = ?"; $condition[] = self::$accountType; } From 6b131a3985c89bc0c7274f0f7ebd0be0c8d8cfa4 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 5 Sep 2023 05:15:14 +0000 Subject: [PATCH 4/9] Model class moved to factory --- src/{Model => Content/Conversation/Factory}/Channel.php | 2 +- src/Module/Conversation/Channel.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/{Model => Content/Conversation/Factory}/Channel.php (97%) diff --git a/src/Model/Channel.php b/src/Content/Conversation/Factory/Channel.php similarity index 97% rename from src/Model/Channel.php rename to src/Content/Conversation/Factory/Channel.php index d6d4eaa55c..f95971d647 100644 --- a/src/Model/Channel.php +++ b/src/Content/Conversation/Factory/Channel.php @@ -19,7 +19,7 @@ * */ - namespace Friendica\Model; + namespace Friendica\Content\Conversation\Factory; use Friendica\Model\User; use Friendica\Content\Conversation\Entity\Channel as ChannelEntity; diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index 3b85f7fb94..41eff2999c 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -27,6 +27,7 @@ use Friendica\BaseModule; use Friendica\Content\BoundariesPager; use Friendica\Content\Conversation; use Friendica\Content\Conversation\Entity\Channel as ChannelEntity; +use Friendica\Content\Conversation\Factory\Channel as ChannelFactory; use Friendica\Content\Feature; use Friendica\Content\Nav; use Friendica\Content\Text\HTML; @@ -46,7 +47,6 @@ use Friendica\Module\Security\Login; use Friendica\Network\HTTPException; use Friendica\Core\Session\Model\UserSession; use Friendica\Database\Database; -use Friendica\Model\Channel as ChannelModel; use Friendica\Model\Item; use Friendica\Module\Response; use Friendica\Navigation\SystemMessages; @@ -81,11 +81,11 @@ class Channel extends BaseModule protected $pConfig; /** @var Database */ protected $database; - /** @var ChannelModel */ + /** @var ChannelFactory */ protected $channel; - public function __construct(ChannelModel $channel, SystemMessages $systemMessages, Database $database, IManagePersonalConfigValues $pConfig, Mode $mode, Conversation $conversation, App\Page $page, IManageConfigValues $config, ICanCache $cache, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + public function __construct(ChannelFactory $channel, SystemMessages $systemMessages, Database $database, IManagePersonalConfigValues $pConfig, Mode $mode, Conversation $conversation, App\Page $page, IManageConfigValues $config, ICanCache $cache, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); From b4e332ccdc13747e0a65b6919a19678d3972d6ed Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Sep 2023 17:35:17 +0000 Subject: [PATCH 5/9] Changes after rebase --- doc/Accesskeys.md | 1 + src/Content/Conversation/Entity/Channel.php | 15 ++++++++------- src/Content/Conversation/Factory/Channel.php | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/Accesskeys.md b/doc/Accesskeys.md index 885378231b..7f85f37ef1 100644 --- a/doc/Accesskeys.md +++ b/doc/Accesskeys.md @@ -33,6 +33,7 @@ General -------- * y - for you * f - followers +* r - sharers of sharers * h - what's hot * i - Images * v - Videos diff --git a/src/Content/Conversation/Entity/Channel.php b/src/Content/Conversation/Entity/Channel.php index 8d1e899acf..b8e0e2bb29 100644 --- a/src/Content/Conversation/Entity/Channel.php +++ b/src/Content/Conversation/Entity/Channel.php @@ -29,13 +29,14 @@ namespace Friendica\Content\Conversation\Entity; */ final class Channel extends \Friendica\BaseEntity { - const WHATSHOT = 'whatshot'; - const FORYOU = 'foryou'; - const FOLLOWERS = 'followers'; - const IMAGE = 'image'; - const VIDEO = 'video'; - const AUDIO = 'audio'; - const LANGUAGE = 'language'; + const WHATSHOT = 'whatshot'; + const FORYOU = 'foryou'; + const FOLLOWERS = 'followers'; + const SHARERSOFSHARERS = 'sharersofsharers'; + const IMAGE = 'image'; + const VIDEO = 'video'; + const AUDIO = 'audio'; + const LANGUAGE = 'language'; /** @var string */ protected $code; diff --git a/src/Content/Conversation/Factory/Channel.php b/src/Content/Conversation/Factory/Channel.php index f95971d647..702eab67ce 100644 --- a/src/Content/Conversation/Factory/Channel.php +++ b/src/Content/Conversation/Factory/Channel.php @@ -55,6 +55,7 @@ final class Channel extends \Friendica\BaseModel new ChannelEntity(ChannelEntity::WHATSHOT, $this->l10n->t('What\'s Hot'), $this->l10n->t('Posts with a lot of interactions'), 'h'), new ChannelEntity(ChannelEntity::LANGUAGE, $languages[$language], $this->l10n->t('Posts in %s', $languages[$language]), 'g'), new ChannelEntity(ChannelEntity::FOLLOWERS, $this->l10n->t('Followers'), $this->l10n->t('Posts from your followers that you don\'t follow'), 'f'), + new ChannelEntity(ChannelEntity::SHARERSOFSHARERS, $this->l10n->t('Sharers of sharers'), $this->l10n->t('Posts from accounts that are followed by accounts that you follow'), 'r'), new ChannelEntity(ChannelEntity::IMAGE, $this->l10n->t('Images'), $this->l10n->t('Posts with images'), 'i'), new ChannelEntity(ChannelEntity::AUDIO, $this->l10n->t('Audio'), $this->l10n->t('Posts with audio'), 'd'), new ChannelEntity(ChannelEntity::VIDEO, $this->l10n->t('Videos'), $this->l10n->t('Posts with videos'), 'v'), From 129f63cf1150c26d9d9979373161d21e94c7a92c Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Sep 2023 17:38:33 +0000 Subject: [PATCH 6/9] Use a factory --- src/Content/Conversation/Factory/Channel.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Content/Conversation/Factory/Channel.php b/src/Content/Conversation/Factory/Channel.php index 702eab67ce..4eda881bd4 100644 --- a/src/Content/Conversation/Factory/Channel.php +++ b/src/Content/Conversation/Factory/Channel.php @@ -19,26 +19,25 @@ * */ - namespace Friendica\Content\Conversation\Factory; +namespace Friendica\Content\Conversation\Factory; use Friendica\Model\User; use Friendica\Content\Conversation\Entity\Channel as ChannelEntity; use Friendica\Core\L10n; -use Friendica\Database\Database; use Psr\Log\LoggerInterface; -final class Channel extends \Friendica\BaseModel +final class Channel extends \Friendica\BaseFactory { /** @var L10n */ protected $l10n; - public function __construct(L10n $l10n, Database $database, LoggerInterface $logger, array $data = []) + public function __construct(L10n $l10n, LoggerInterface $logger) { - parent::__construct($database, $logger, $data); + parent::__construct($logger); $this->l10n = $l10n; } - + /** * List of available channels * From 97c519990b63f1e8f8807afc2b74f22ccebd99dc Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Sep 2023 17:41:46 +0000 Subject: [PATCH 7/9] Updated messages.po --- view/lang/C/messages.po | 128 ++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 85a2885af7..247a025e87 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2023.09-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-09-07 12:24+0000\n" +"POT-Creation-Date: 2023-09-07 17:41+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -792,8 +792,8 @@ msgstr "" msgid "All contacts" msgstr "" -#: src/BaseModule.php:433 src/Content/Widget.php:239 src/Core/ACL.php:195 -#: src/Module/Contact.php:415 src/Module/Conversation/Channel.php:162 +#: src/BaseModule.php:433 src/Content/Conversation/Factory/Channel.php:56 +#: src/Content/Widget.php:239 src/Core/ACL.php:195 src/Module/Contact.php:415 #: src/Module/PermissionTooltip.php:127 src/Module/PermissionTooltip.php:149 msgid "Followers" msgstr "" @@ -1512,6 +1512,63 @@ msgstr "" msgid "View in context" msgstr "" +#: src/Content/Conversation/Factory/Channel.php:53 +msgid "For you" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:53 +msgid "Posts from contacts you interact with and who interact with you" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:54 +msgid "What's Hot" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:54 +msgid "Posts with a lot of interactions" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:55 +#, php-format +msgid "Posts in %s" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:56 +msgid "Posts from your followers that you don't follow" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:57 +msgid "Sharers of sharers" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:57 +msgid "Posts from accounts that are followed by accounts that you follow" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:58 +msgid "Images" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:58 +msgid "Posts with images" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:59 +msgid "Audio" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:59 +msgid "Posts with audio" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:60 +msgid "Videos" +msgstr "" + +#: src/Content/Conversation/Factory/Channel.php:60 +msgid "Posts with videos" +msgstr "" + #: src/Content/Feature.php:96 msgid "General Features" msgstr "" @@ -6526,85 +6583,28 @@ msgstr "" msgid "Unable to unfollow this contact, please contact your administrator" msgstr "" -#: src/Module/Conversation/Channel.php:132 -msgid "For you" -msgstr "" - -#: src/Module/Conversation/Channel.php:135 -msgid "Posts from contacts you interact with and who interact with you" -msgstr "" - -#: src/Module/Conversation/Channel.php:141 -msgid "What's Hot" -msgstr "" - -#: src/Module/Conversation/Channel.php:144 -msgid "Posts with a lot of interactions" -msgstr "" - -#: src/Module/Conversation/Channel.php:156 -#, php-format -msgid "Posts in %s" -msgstr "" - #: src/Module/Conversation/Channel.php:165 -msgid "Posts from your followers that you don't follow" -msgstr "" - -#: src/Module/Conversation/Channel.php:171 -msgid "Sharers of sharers" -msgstr "" - -#: src/Module/Conversation/Channel.php:174 -msgid "Posts from accounts that are followed by accounts that you follow" -msgstr "" - -#: src/Module/Conversation/Channel.php:181 -msgid "Images" -msgstr "" - -#: src/Module/Conversation/Channel.php:184 -msgid "Posts with images" -msgstr "" - -#: src/Module/Conversation/Channel.php:190 -msgid "Audio" -msgstr "" - -#: src/Module/Conversation/Channel.php:193 -msgid "Posts with audio" -msgstr "" - -#: src/Module/Conversation/Channel.php:199 -msgid "Videos" -msgstr "" - -#: src/Module/Conversation/Channel.php:202 -msgid "Posts with videos" -msgstr "" - -#: src/Module/Conversation/Channel.php:234 #: src/Module/Conversation/Community.php:134 msgid "Own Contacts" msgstr "" -#: src/Module/Conversation/Channel.php:238 +#: src/Module/Conversation/Channel.php:169 #: src/Module/Conversation/Community.php:138 msgid "Include" msgstr "" -#: src/Module/Conversation/Channel.php:239 +#: src/Module/Conversation/Channel.php:170 #: src/Module/Conversation/Community.php:139 msgid "Hide" msgstr "" -#: src/Module/Conversation/Channel.php:255 +#: src/Module/Conversation/Channel.php:186 #: src/Module/Conversation/Community.php:157 src/Module/Search/Index.php:152 #: src/Module/Search/Index.php:194 msgid "No results." msgstr "" -#: src/Module/Conversation/Channel.php:295 +#: src/Module/Conversation/Channel.php:226 msgid "Channel not available." msgstr "" From 9cbd0c34a77beffc1d42d96673ad3da87d6ba5cf Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Sep 2023 05:06:27 +0000 Subject: [PATCH 8/9] Language specific median calculations / collection --- .../Conversation/Collection/Channels.php | 28 ++++++++++++++++ src/Content/Conversation/Factory/Channel.php | 5 +-- src/Module/Conversation/Channel.php | 33 ++++++++++++------- static/defaults.config.php | 4 +++ 4 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 src/Content/Conversation/Collection/Channels.php diff --git a/src/Content/Conversation/Collection/Channels.php b/src/Content/Conversation/Collection/Channels.php new file mode 100644 index 0000000000..a523cc7b2b --- /dev/null +++ b/src/Content/Conversation/Collection/Channels.php @@ -0,0 +1,28 @@ +. + * + */ + +namespace Friendica\Content\Conversation\Collection; + +use Friendica\BaseCollection; + +class Channels extends BaseCollection +{ +} diff --git a/src/Content/Conversation/Factory/Channel.php b/src/Content/Conversation/Factory/Channel.php index 4eda881bd4..c5d172225d 100644 --- a/src/Content/Conversation/Factory/Channel.php +++ b/src/Content/Conversation/Factory/Channel.php @@ -21,6 +21,7 @@ namespace Friendica\Content\Conversation\Factory; +use Friendica\Content\Conversation\Collection\Channels; use Friendica\Model\User; use Friendica\Content\Conversation\Entity\Channel as ChannelEntity; use Friendica\Core\L10n; @@ -44,7 +45,7 @@ final class Channel extends \Friendica\BaseFactory * @param integer $uid * @return array */ - public function getForUser(int $uid): array + public function getForUser(int $uid): Channels { $language = User::getLanguageCode($uid); $languages = $this->l10n->getAvailableLanguages(true); @@ -59,6 +60,6 @@ final class Channel extends \Friendica\BaseFactory new ChannelEntity(ChannelEntity::AUDIO, $this->l10n->t('Audio'), $this->l10n->t('Posts with audio'), 'd'), new ChannelEntity(ChannelEntity::VIDEO, $this->l10n->t('Videos'), $this->l10n->t('Posts with videos'), 'v'), ]; - return $tabs; + return new Channels($tabs); } } diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index f84039059a..e928fe50a5 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -284,11 +284,12 @@ class Channel extends BaseModule } elseif (self::$content == ChannelEntity::SHARERSOFSHARERS) { $cid = Contact::getPublicIdByUserId($this->session->getLocalUserId()); + // @todo Suggest posts from contacts that are followed most by our followers $condition = [ "`owner-id` IN (SELECT `cid` FROM `contact-relation` WHERE `follows` AND `last-interaction` > ? AND `relation-cid` IN (SELECT `cid` FROM `contact-relation` WHERE `follows` AND `relation-cid` = ? AND `relation-thread-score` >= ?) AND NOT `cid` IN (SELECT `cid` FROM `contact-relation` WHERE `follows` AND `relation-cid` = ?))", - DateTimeFormat::utc('now - 90 day'), $cid, $this->getMedianRelationThreadScore($cid, 4), $cid + DateTimeFormat::utc('now - ' . $this->config->get('channel', 'sharer_interaction_days') .' day'), $cid, $this->getMedianRelationThreadScore($cid, 4), $cid ]; } elseif (self::$content == ChannelEntity::IMAGE) { $condition = ["`media-type` & ?", 1]; @@ -371,41 +372,49 @@ class Channel extends BaseModule private function getMedianComments(int $divider): int { - $cache_key = 'Channel:getMedianComments:' . $divider; + $languages = $this->pConfig->get($this->session->getLocalUserId(), 'channel', 'languages', [User::getLanguageCode($this->session->getLocalUserId())]); + $cache_key = 'Channel:getMedianComments:' . $divider . ':' . implode(':', $languages); $comments = $this->cache->get($cache_key); if (!empty($comments)) { return $comments; } - $limit = $this->database->count('post-engagement', ["`contact-type` != ? AND `comments` > ?", Contact::TYPE_COMMUNITY, 0]) / $divider; - $post = $this->database->selectToArray('post-engagement', ['comments'], ["`contact-type` != ?", Contact::TYPE_COMMUNITY], ['order' => ['comments' => true], 'limit' => [$limit, 1]]); + $condition = ["`contact-type` != ? AND `comments` > ?", Contact::TYPE_COMMUNITY, 0]; + $condition = $this->addLanguageCondition($condition); + + $limit = $this->database->count('post-engagement', $condition) / $divider; + $post = $this->database->selectToArray('post-engagement', ['comments'], $condition, ['order' => ['comments' => true], 'limit' => [$limit, 1]]); $comments = $post[0]['comments'] ?? 0; if (empty($comments)) { return 0; } $this->cache->set($cache_key, $comments, Duration::HALF_HOUR); - $this->logger->debug('Calculated median comments', ['divider' => $divider, 'median' => $comments]); + $this->logger->debug('Calculated median comments', ['divider' => $divider, 'languages' => $languages, 'median' => $comments]); return $comments; } private function getMedianActivities(int $divider): int { - $cache_key = 'Channel:getMedianActivities:' . $divider; + $languages = $this->pConfig->get($this->session->getLocalUserId(), 'channel', 'languages', [User::getLanguageCode($this->session->getLocalUserId())]); + $cache_key = 'Channel:getMedianActivities:' . $divider . ':' . implode(':', $languages); $activities = $this->cache->get($cache_key); if (!empty($activities)) { return $activities; } - $limit = $this->database->count('post-engagement', ["`contact-type` != ? AND `activities` > ?", Contact::TYPE_COMMUNITY, 0]) / $divider; - $post = $this->database->selectToArray('post-engagement', ['activities'], ["`contact-type` != ?", Contact::TYPE_COMMUNITY], ['order' => ['activities' => true], 'limit' => [$limit, 1]]); + $condition = ["`contact-type` != ? AND `activities` > ?", Contact::TYPE_COMMUNITY, 0]; + $condition = $this->addLanguageCondition($condition); + + $limit = $this->database->count('post-engagement', $condition) / $divider; + $post = $this->database->selectToArray('post-engagement', ['activities'], $condition, ['order' => ['activities' => true], 'limit' => [$limit, 1]]); $activities = $post[0]['activities'] ?? 0; if (empty($activities)) { return 0; } $this->cache->set($cache_key, $activities, Duration::HALF_HOUR); - $this->logger->debug('Calculated median activities', ['divider' => $divider, 'median' => $activities]); + $this->logger->debug('Calculated median activities', ['divider' => $divider, 'languages' => $languages, 'median' => $activities]); return $activities; } @@ -417,8 +426,10 @@ class Channel extends BaseModule return $score; } - $limit = $this->database->count('contact-relation', ["`relation-cid` = ? AND `relation-thread-score` > ?", $cid, 0]) / $divider; - $relation = $this->database->selectToArray('contact-relation', ['relation-thread-score'], ['relation-cid' => $cid], ['order' => ['relation-thread-score' => true], 'limit' => [$limit, 1]]); + $condition = ["`relation-cid` = ? AND `relation-thread-score` > ?", $cid, 0]; + + $limit = $this->database->count('contact-relation', $condition) / $divider; + $relation = $this->database->selectToArray('contact-relation', ['relation-thread-score'], $condition, ['order' => ['relation-thread-score' => true], 'limit' => [$limit, 1]]); $score = $relation[0]['relation-thread-score'] ?? 0; if (empty($score)) { return 0; diff --git a/static/defaults.config.php b/static/defaults.config.php index 10324ed504..75c349de5b 100644 --- a/static/defaults.config.php +++ b/static/defaults.config.php @@ -804,5 +804,9 @@ return [ // interaction_score_days (Integer) // Number of days that are used to calculate the interaction score. 'interaction_score_days' => 30, + + // sharer_interaction_days (Integer) + // Number of days of the last interaction that are used to define which sharers are used for the "sharers of sharers" channel. + 'sharer_interaction_days' => 90, ], ]; From 692a633dc8461d71825a96896bf19404043f55b2 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Sep 2023 05:44:08 +0000 Subject: [PATCH 9/9] Remove references to the community page --- src/Module/Conversation/Channel.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Module/Conversation/Channel.php b/src/Module/Conversation/Channel.php index e928fe50a5..3717a4d25d 100644 --- a/src/Module/Conversation/Channel.php +++ b/src/Module/Conversation/Channel.php @@ -254,10 +254,7 @@ class Channel extends BaseModule } /** - * Computes the displayed items. - * - * Community pages have a restriction on how many successive posts by the same author can show on any given page, - * so we may have to retrieve more content beyond the first query + * Database query for the channel page * * @return array * @throws \Exception