From dabf5576d35b51ee684b3fdd5541ce225dbbb6d2 Mon Sep 17 00:00:00 2001 From: Hugo Sales Date: Fri, 24 Dec 2021 09:27:24 +0000 Subject: [PATCH] [CONTROLLER][Feeds] Implement query for home feed: note-from:subscribed --- components/Attachment/Attachment.php | 3 +- components/Feed/Feed.php | 56 +++++++++++++++++----------- components/Language/Language.php | 8 ++-- components/Search/Util/Parser.php | 5 ++- components/Tag/Tag.php | 2 +- src/Controller/Feeds.php | 3 +- 6 files changed, 48 insertions(+), 29 deletions(-) diff --git a/components/Attachment/Attachment.php b/components/Attachment/Attachment.php index e8a7982090..3688183419 100644 --- a/components/Attachment/Attachment.php +++ b/components/Attachment/Attachment.php @@ -25,6 +25,7 @@ use App\Core\Cache; use App\Core\Event; use App\Core\Modules\Component; use App\Core\Router\RouteLoader; +use App\Entity\Actor; use App\Entity\Note; use App\Util\Formatting; use Component\Attachment\Controller as C; @@ -74,7 +75,7 @@ class Attachment extends Component /** * Populate $note_expr with the criteria for looking for notes with attachments */ - public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool + public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr) { $include_term = str_contains($term, ':') ? explode(':', $term)[1] : $term; if (Formatting::startsWith($term, ['note-types:', 'notes-incude:', 'note-filter:'])) { diff --git a/components/Feed/Feed.php b/components/Feed/Feed.php index ad1c044ab1..55ec18c128 100644 --- a/components/Feed/Feed.php +++ b/components/Feed/Feed.php @@ -27,18 +27,21 @@ use App\Core\DB\DB; use App\Core\Event; use App\Core\Modules\Component; use App\Entity\Actor; +use App\Entity\Subscription; use App\Util\Formatting; use Component\Search\Util\Parser; use Doctrine\Common\Collections\ExpressionBuilder; +use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\QueryBuilder; class Feed extends Component { - public static function query(string $query, int $page, ?string $language = null): array + public static function query(string $query, int $page, ?string $language = null, ?Actor $actor = null): array { $note_criteria = null; $actor_criteria = null; if (!empty($query = trim($query))) { - [$note_criteria, $actor_criteria] = Parser::parse($query, $language); + [$note_criteria, $actor_criteria] = Parser::parse($query, $language, $actor); } $note_qb = DB::createQueryBuilder(); $actor_qb = DB::createQueryBuilder(); @@ -62,34 +65,45 @@ class Feed extends Component return ['notes' => $notes ?? null, 'actors' => $actors ?? null]; } + public function onSearchQueryAddJoins(QueryBuilder &$note_qb, QueryBuilder &$actor_qb) + { + $note_qb->leftJoin(Subscription::class, 'subscription', Expr\Join::WITH, 'note.actor_id = subscription.subscribed'); + return Event::next; + } + /** * Convert $term to $note_expr and $actor_expr, search criteria. Handles searching for text * notes, for different types of actors and for the content of text notes */ - public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool + public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr) { if (str_contains($term, ':')) { $term = explode(':', $term); if (Formatting::startsWith($term[0], 'note-')) { switch ($term[0]) { - case 'note-local': - $note_expr = $eb->eq('note.is_local', filter_var($term[1], \FILTER_VALIDATE_BOOLEAN)); - break; - case 'note-types': - case 'notes-include': - case 'note-filter': - if (\is_null($note_expr)) { - $note_expr = []; - } - if (array_intersect(explode(',', $term[1]), ['text', 'words']) !== []) { - $note_expr[] = $eb->neq('note.content', null); - } else { - $note_expr[] = $eb->eq('note.content', null); - } - break; - case 'note-conversation': - $note_expr = $eb->eq('note.conversation_id', (int)trim($term[1])); - break; + case 'note-local': + $note_expr = $eb->eq('note.is_local', filter_var($term[1], \FILTER_VALIDATE_BOOLEAN)); + break; + case 'note-types': + case 'notes-include': + case 'note-filter': + if (\is_null($note_expr)) { + $note_expr = []; + } + if (array_intersect(explode(',', $term[1]), ['text', 'words']) !== []) { + $note_expr[] = $eb->neq('note.content', null); + } else { + $note_expr[] = $eb->eq('note.content', null); + } + break; + case 'note-conversation': + $note_expr = $eb->eq('note.conversation_id', (int) trim($term[1])); + break; + case 'note-from': + if ($term[1] === 'subscribed') { + $note_expr = $eb->eq('subscription.subscriber', $actor->getId()); + } + break; } } elseif (Formatting::startsWith($term, 'actor-')) { switch ($term[0]) { diff --git a/components/Language/Language.php b/components/Language/Language.php index c6e83d1cfa..edbe4f109d 100644 --- a/components/Language/Language.php +++ b/components/Language/Language.php @@ -31,10 +31,10 @@ use App\Util\Formatting; use App\Util\Functional as GSF; use Component\Language\Controller as C; use Doctrine\Common\Collections\ExpressionBuilder; -use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use Functional as F; +use Symfony\Component\HttpFoundation\Request; class Language extends Component { @@ -46,7 +46,9 @@ class Language extends Component public function onFilterNoteList(?Actor $actor, array &$notes, Request $request) { - if (\is_null($actor)) return Event::next; + if (\is_null($actor)) { + return Event::next; + } $notes = F\select( $notes, fn (Note $n) => \in_array($n->getLanguageId(), ActorLanguage::getActorRelatedLanguagesIds($actor)), @@ -58,7 +60,7 @@ class Language extends Component /** * Populate $note_expr or $actor_expr with an expression to match a language */ - public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool + public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr) { $search_term = str_contains($term, ':') ? explode(':', $term)[1] : $term; diff --git a/components/Search/Util/Parser.php b/components/Search/Util/Parser.php index b835e0912c..48a8cbb540 100644 --- a/components/Search/Util/Parser.php +++ b/components/Search/Util/Parser.php @@ -24,6 +24,7 @@ declare(strict_types = 1); namespace Component\Search\Util; use App\Core\Event; +use App\Entity\Actor; use App\Util\Exception\ServerException; use Doctrine\Common\Collections\Criteria; @@ -52,7 +53,7 @@ abstract class Parser * * @return Criteria[] */ - public static function parse(string $input, ?string $language = null, int $level = 0): array + public static function parse(string $input, ?string $language = null, ?Actor $actor = null, int $level = 0): array { if ($level === 0) { $input = trim(preg_replace(['/\s+/', '/\s+AND\s+/', '/\s+OR\s+/'], [' ', '&', '|'], $input), ' |&'); @@ -77,7 +78,7 @@ abstract class Parser $term = mb_substr($input, $left, $end ? null : $right - $left); $note_res = null; $actor_res = null; - Event::handle('SearchCreateExpression', [$eb, $term, $language, &$note_res, &$actor_res]); + Event::handle('SearchCreateExpression', [$eb, $term, $language, $actor, &$note_res, &$actor_res]); if (\is_null($note_res) && \is_null($actor_res)) { throw new ServerException("No one claimed responsibility for a match term: {$term}"); } diff --git a/components/Tag/Tag.php b/components/Tag/Tag.php index dcd4e988c0..0bc76315cd 100644 --- a/components/Tag/Tag.php +++ b/components/Tag/Tag.php @@ -155,7 +155,7 @@ class Tag extends Component * * $term /^(note|tag|people|actor)/ means we want to match only either a note or an actor */ - public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, &$note_expr, &$actor_expr): bool + public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, ?string $language, ?Actor $actor, &$note_expr, &$actor_expr) { $search_term = str_contains($term, ':#') ? explode(':', $term)[1] : $term; $canon_search_term = self::canonicalTag($search_term, $language); diff --git a/src/Controller/Feeds.php b/src/Controller/Feeds.php index 68b18ca423..f50191efa2 100644 --- a/src/Controller/Feeds.php +++ b/src/Controller/Feeds.php @@ -74,9 +74,10 @@ class Feeds extends FeedController public function home(Request $request): array { $data = Feed::query( - query: 'from:subscribed-actors OR from:subscribed-groups', + query: 'note-from:subscribed', page: $this->int('p'), language: Common::actor()?->getTopLanguage()?->getLocale(), + actor: Common::actor(), ); return [ '_template' => 'feed/feed.html.twig',