From e7940a21eeb6c22efacce5a62ca16dea1060ae4e Mon Sep 17 00:00:00 2001 From: Eliseu Amaro Date: Fri, 31 Dec 2021 23:26:39 +0000 Subject: [PATCH] [PLUGINS][TreeNotes] Feed only shows each note and its respective direct replies, conversation shows whole tree [COMPONENTS][Feed] Added request to FormatNoteList event Every single Note that was provided to FeedController::postProcess is shown. This means, that even though the Feed is formatted to show only a Note and its respective direct replies, those same replies are shown individually again (and they get the chance to show their own direct replies). The Note list provided to FormatNoteList is reversed, and for every index, the respective Note replies are filtered out of the original list. The replies are then added as leafs of the current Note and added to the tree. --- components/Conversation/Controller/Reply.php | 2 +- components/Conversation/Conversation.php | 8 +-- components/Feed/Util/FeedController.php | 4 +- .../templates/right_panel/view.html.twig | 2 +- plugins/TreeNotes/TreeNotes.php | 58 ++++++++++++++++--- src/Entity/Note.php | 2 +- 6 files changed, 59 insertions(+), 17 deletions(-) diff --git a/components/Conversation/Controller/Reply.php b/components/Conversation/Controller/Reply.php index 63a4a7049a..62759ee885 100644 --- a/components/Conversation/Controller/Reply.php +++ b/components/Conversation/Controller/Reply.php @@ -49,7 +49,7 @@ class Reply extends FeedController * * @return array */ - public function addReply(Request $request, int $note_id, int $actor_id) + public function addReply(Request $request, int $note_id) { $user = Common::ensureLoggedIn(); diff --git a/components/Conversation/Conversation.php b/components/Conversation/Conversation.php index 16089c35b0..3a697b8481 100644 --- a/components/Conversation/Conversation.php +++ b/components/Conversation/Conversation.php @@ -86,9 +86,9 @@ class Conversation extends Component } // Generating URL for reply action route - $args = ['note_id' => $note->getId(), 'actor_id' => $note->getActor()->getId()]; + $args = ['note_id' => $note->getId()]; $type = Router::ABSOLUTE_PATH; - $reply_action_url = Router::url('reply_add', $args, $type); + $reply_action_url = Router::url('conversation_reply_to', $args, $type); $query_string = $request->getQueryString(); // Concatenating get parameter to redirect the user to where he came from @@ -109,7 +109,7 @@ class Conversation extends Component { // If Actor is adding a reply, get parent's Note id // Else it's null - $extra_args['reply_to'] = $request->get('_route') === 'reply_add' ? (int) $request->get('note_id') : null; + $extra_args['reply_to'] = $request->get('_route') === 'conversation_reply_to' ? (int) $request->get('note_id') : null; return Event::next; } @@ -147,7 +147,7 @@ class Conversation extends Component public function onAddRoute(RouteLoader $r): bool { - $r->connect('reply_add', '/object/note/new?to={actor_id<\d+>}&reply_to={note_id<\d+>}', [ReplyController::class, 'addReply']); + $r->connect('conversation_reply_to', '/conversation/reply?reply_to_note={note_id<\d+>}', [ReplyController::class, 'addReply']); $r->connect('conversation', '/conversation/{conversation_id<\d+>}', [Controller\Conversation::class, 'showConversation']); $r->connect('conversation_mute', '/conversation/{conversation_id<\d+>}/mute', [Controller\Conversation::class, 'muteConversation']); diff --git a/components/Feed/Util/FeedController.php b/components/Feed/Util/FeedController.php index d625374cd0..cd30eb2093 100644 --- a/components/Feed/Util/FeedController.php +++ b/components/Feed/Util/FeedController.php @@ -38,6 +38,7 @@ use App\Entity\Actor; use App\Entity\Note; use App\Util\Common; use Functional as F; +use function App\Core\I18n\_m; abstract class FeedController extends Controller { @@ -49,12 +50,11 @@ abstract class FeedController extends Controller protected function postProcess(array $result): array { $actor = Common::actor(); - if (\array_key_exists('notes', $result)) { $notes = $result['notes']; self::enforceScope($notes, $actor); Event::handle('FilterNoteList', [$actor, &$notes, $result['request']]); - Event::handle('FormatNoteList', [$notes, &$result['notes']]); + Event::handle('FormatNoteList', [$notes, &$result['notes'], &$result['request']]); } return $result; diff --git a/components/RightPanel/templates/right_panel/view.html.twig b/components/RightPanel/templates/right_panel/view.html.twig index f7f9c9c79f..9981fe0ef4 100644 --- a/components/RightPanel/templates/right_panel/view.html.twig +++ b/components/RightPanel/templates/right_panel/view.html.twig @@ -15,7 +15,7 @@

{% set current_path = app.request.get('_route') %} - {% if current_path == 'reply_add' %} + {% if current_path == 'conversation_reply_to' %} {{ "Reply to note" | trans }} {% else %} {{ "Create a note" | trans }} diff --git a/plugins/TreeNotes/TreeNotes.php b/plugins/TreeNotes/TreeNotes.php index f1df8787d5..2b1f1b78c0 100644 --- a/plugins/TreeNotes/TreeNotes.php +++ b/plugins/TreeNotes/TreeNotes.php @@ -23,30 +23,72 @@ namespace Plugin\TreeNotes; use App\Core\Modules\Plugin; use App\Entity\Note; +use Symfony\Component\HttpFoundation\Request; class TreeNotes extends Plugin { + /** - * Format the given $notes_in_trees_out in a list of reply trees + * Formatting notes without taking a direct reply out of context + * Show whole conversation in conversation related routes + * + * @param array $notes_in + * @param array $notes_out + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @return void */ - public function onFormatNoteList(array $notes_in, ?array &$notes_out) + public function onFormatNoteList(array $notes_in, array &$notes_out, Request $request) { - $roots = array_filter($notes_in, static fn (Note $note) => \is_null($note->getReplyTo())); - $notes_out = $this->build_tree($roots, $notes_in); + if (str_starts_with($request->get('_route'), 'conversation')) { + $parents = $this->conversationFormat($notes_in); + $notes_out = $this->conversationFormatTree($parents, $notes_in); + } else { + $notes_out = $this->feedFormatTree($notes_in); + } } - private function build_tree(array $parents, array $notes) + private function feedFormatTree(array $notes): array + { + $tree = []; + $notes = array_reverse($notes); + foreach ($notes as $note) { + if (!is_null($children = $note->getReplies())) { + $notes = array_filter($notes, fn (Note $n) => !in_array($n, $children)); + + $tree[] = [ + 'note' => $note, + 'replies' => array_map( + function ($n) { + return ['note' => $n, 'replies' => []]; + }, + $children + ), + ]; + } else { + $tree[] = ['note' => $note, 'replies' => []]; + } + } + return array_reverse($tree); + } + + private function conversationFormat(array $notes_in) + { + return array_filter($notes_in, static fn (Note $note) => \is_null($note->getReplyTo())); + } + + private function conversationFormatTree(array $parents, array $notes) { $subtree = []; foreach ($parents as $p) { - $subtree[] = $this->build_subtree($p, $notes); + $subtree[] = $this->conversationFormatSubTree($p, $notes); } return $subtree; } - private function build_subtree(Note $parent, array $notes) + private function conversationFormatSubTree(Note $parent, array $notes) { $children = array_filter($notes, fn (Note $note) => $note->getReplyTo() === $parent->getId()); - return ['note' => $parent, 'replies' => $this->build_tree($children, $notes)]; + return ['note' => $parent, 'replies' => $this->conversationFormatTree($children, $notes)]; } } diff --git a/src/Entity/Note.php b/src/Entity/Note.php index ad71ffef2f..ad9e811ef7 100644 --- a/src/Entity/Note.php +++ b/src/Entity/Note.php @@ -352,7 +352,7 @@ class Note extends Entity */ public function getReplies(): array { - return Cache::getList('note-replies-' . $this->getId(), fn () => DB::findBy('note', ['reply_to' => $this->getId()], order_by: ['created' => 'DESC', 'id' => 'DESC'])); + return DB::findBy('note', ['reply_to' => $this->getId()], order_by: ['created' => 'DESC', 'id' => 'DESC']); } /**