diff --git a/src/models/dao/links/NewsQueries.php b/src/models/dao/links/NewsQueries.php index a3556051..e3287f7f 100644 --- a/src/models/dao/links/NewsQueries.php +++ b/src/models/dao/links/NewsQueries.php @@ -14,51 +14,22 @@ trait NewsQueries { /** * Return public links listed in followed collections of the given user, - * ordered by publication date. Links with a matching url in bookmarks or - * read list are not returned. + * ordered by publication date. * * @return self[] */ - public static function listFromFollowedCollectionsForNews(string $user_id): array + public static function listFromFollowedCollections(string $user_id): array { - $where_placeholder = ''; $values = [ ':user_id' => $user_id, + ':until_strict' => \Minz\Time::ago(1, 'day')->format(Database\Column::DATETIME_FORMAT), + ':until_normal' => \Minz\Time::ago(1, 'week')->format(Database\Column::DATETIME_FORMAT), ]; - $where_placeholder .= <<<'SQL' - AND ( - (fc.time_filter = 'strict' AND lc.created_at >= :until_strict) OR - (fc.time_filter = 'normal' AND lc.created_at >= :until_normal) OR - (fc.time_filter = 'all' AND lc.created_at >= fc.created_at - INTERVAL '1 week') - ) - SQL; - $values[':until_strict'] = \Minz\Time::ago(1, 'day')->format(Database\Column::DATETIME_FORMAT); - $values[':until_normal'] = \Minz\Time::ago(1, 'week')->format(Database\Column::DATETIME_FORMAT); - $sql = <<= :until_strict) OR + (fc.time_filter = 'normal' AND lc.created_at >= :until_normal) OR + (fc.time_filter = 'all' AND lc.created_at >= fc.created_at - INTERVAL '1 week') + ) + + ORDER BY published_at DESC, l.id + SQL; + + $database = Database::get(); + $statement = $database->prepare($sql); + $statement->execute($values); + + return self::fromDatabaseRows($statement->fetchAll()); + } + + /** + * Return hashes of links that are in news, bookmarks, never or read lists. + * + * @return array + */ + public static function listHashesExcludedFromNews(string $user_id): array + { + $values = [ + ':user_id' => $user_id, + ]; - {$where_placeholder} + $sql = <<prepare($sql); $statement->execute($values); - return self::fromDatabaseRows($statement->fetchAll()); + return $statement->fetchAll(\PDO::FETCH_KEY_PAIR); } /** diff --git a/src/services/NewsPicker.php b/src/services/NewsPicker.php index 2743e6d6..d50b535e 100644 --- a/src/services/NewsPicker.php +++ b/src/services/NewsPicker.php @@ -44,24 +44,25 @@ public function __construct(models\User $user, array $options = []) */ public function pick(): array { - $links = models\Link::listFromFollowedCollectionsForNews($this->user->id); - $links = $this->mergeByUrl($links); - return array_slice($links, 0, $this->options['number_links']); - } + $excluded_hashes = models\Link::listHashesExcludedFromNews($this->user->id); + $links_from_followed = models\Link::listFromFollowedCollections($this->user->id); - /** - * Removes duplicated links urls. - * - * @param models\Link[] $links - * - * @return models\Link[] - */ - private function mergeByUrl(array $links): array - { - $by_url = []; - foreach ($links as $link) { - $by_url[$link->url] = $link; + $links = []; + + foreach ($links_from_followed as $link) { + $hash = $link->url_hash; + + if (isset($excluded_hashes[$hash])) { + continue; + } + + $links[$hash] = $link; + + if (count($links) >= $this->options['number_links']) { + break; + } } - return array_values($by_url); + + return array_values($links); } }