From cf09b48e924338559df459a3f083f15fde6dc7f8 Mon Sep 17 00:00:00 2001 From: Eliseu Amaro Date: Mon, 1 Nov 2021 21:19:20 +0000 Subject: [PATCH] [PLUGINS][Repeat] Added note_repeat entity, fixed visual discrepancies, and completed the expected functionality. [ENTITY][Note] Removed repeat_off from table. It is now part of the Repeat plugin. --- plugins/Repeat/Controller/Repeat.php | 38 ++++++-- plugins/Repeat/Entity/NoteRepeat.php | 92 +++++++++++++++++++ plugins/Repeat/Repeat.php | 32 ++++++- .../plugins/repeat/cards/note/view.html.twig | 58 +++++++++--- .../repeat/remove_from_repeats.html.twig | 2 +- src/Entity/Note.php | 8 +- src/Twig/Runtime.php | 9 ++ templates/network/feed.html.twig | 1 + 8 files changed, 210 insertions(+), 30 deletions(-) create mode 100644 plugins/Repeat/Entity/NoteRepeat.php diff --git a/plugins/Repeat/Controller/Repeat.php b/plugins/Repeat/Controller/Repeat.php index c9bb8fcf07..a1c25a8ac9 100644 --- a/plugins/Repeat/Controller/Repeat.php +++ b/plugins/Repeat/Controller/Repeat.php @@ -34,6 +34,7 @@ use App\Util\Exception\InvalidFormException; use App\Util\Exception\NoLoggedInUser; use App\Util\Exception\NoSuchNoteException; use App\Util\Exception\RedirectException; +use Plugin\Repeat\Entity\NoteRepeat; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpFoundation\Request; use function App\Core\I18n\_m; @@ -52,7 +53,7 @@ class Repeat extends Controller { $user = Common::ensureLoggedIn(); $opts = ['actor_id' => $user->getId(), 'repeat_of' => $id]; - $note_already_repeated = DB::count('note', $opts) >= 1; + $note_already_repeated = DB::count('note_repeat', $opts) >= 1; if (is_null($note_already_repeated)) { throw new NoSuchNoteException(); } @@ -71,15 +72,38 @@ class Repeat extends Controller $form_add_to_repeat->handleRequest($request); if ($form_add_to_repeat->isSubmitted()) { + if (!is_null($note)) { - DB::persist(Note::create([ - 'actor_id' => $user->getId(), - 'repeat_of' => $note->getId(), - 'content' => $note->getContent(), + $actor_id = $user->getId(); + $content = $note->getContent(); + + // Create a new note with the same content as the original + $repeat = Note::create([ + 'actor_id' => $actor_id, + 'content' => $content, 'content_type' => $note->getContentType(), 'rendered' => $note->getRendered(), 'is_local' => true, - ])); + ]); + DB::persist($repeat); + + // Update DB + DB::flush(); + + // Find the id of the note we just created + $repeat_id = $repeat->getId(); + $og_id = $note->getId(); + + // Add it to note_repeat table + if (!is_null($repeat_id)) { + DB::persist(NoteRepeat::create([ + 'id' => $repeat_id, + 'actor_id' => $actor_id, + 'repeat_of' => $og_id + ])); + } + + // Update DB one last time DB::flush(); } @@ -106,7 +130,7 @@ class Repeat extends Controller public function repeatRemoveNote(Request $request, int $id): array { $user = Common::ensureLoggedIn(); - $opts = ['note_id' => $id, 'actor_id' => $user->getId()]; + $opts = ['id' => $id]; $remove_repeat_note = DB::find('note', $opts); if (is_null($remove_repeat_note)) { throw new NoSuchNoteException(); diff --git a/plugins/Repeat/Entity/NoteRepeat.php b/plugins/Repeat/Entity/NoteRepeat.php new file mode 100644 index 0000000000..c5dcd05329 --- /dev/null +++ b/plugins/Repeat/Entity/NoteRepeat.php @@ -0,0 +1,92 @@ +. + +// }}} + +namespace Plugin\Repeat\Entity; + +use App\Core\Entity; + +/** + * Entity for notices + * + * @category DB + * @package GNUsocial + * + * @author Eliseu Amaro + * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class NoteRepeat extends Entity +{ + private int $id; + private int $actor_id; + private int $repeat_of; + + public function setId(int $id): self + { + $this->id = $id; + return $this; + } + + public function getId(): int + { + return $this->id; + } + + public function setActorId(int $actor_id): self + { + $this->actor_id = $actor_id; + return $this; + } + + public function getActorId(): ?int + { + return $this->actor_id; + } + + public function setRepeatOf(int $repeat_of): self + { + $this->repeat_of = $repeat_of; + return $this; + } + + public function getRepeatOf(): int + { + return $this->repeat_of; + } + + public static function schemaDef(): array + { + return [ + 'name' => 'note_repeat', + 'fields' => [ + 'id' => ['type' => 'int', 'not null' => true, 'description' => 'The id of the repeat itself'], + 'actor_id' => ['type' => 'int', 'not null' => true, 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to one', 'description' => 'Who made this repeat'], + 'repeat_of' => ['type' => 'int', 'not null' => true, 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'description' => 'Note this is a repeat of'], + ], + 'primary key' => ['id'], + 'foreign keys' => [ + 'note_repeat_of_id_fkey' => ['note', ['repeat_of' => 'id']], + ], + ]; + } +} diff --git a/plugins/Repeat/Repeat.php b/plugins/Repeat/Repeat.php index 3bd7f79996..a9fcf58106 100644 --- a/plugins/Repeat/Repeat.php +++ b/plugins/Repeat/Repeat.php @@ -25,11 +25,13 @@ use App\Core\DB\DB; use App\Core\Event; use App\Core\Router\RouteLoader; use App\Core\Router\Router; +use App\Util\Exception\DuplicateFoundException; use App\Util\Exception\InvalidFormException; use App\Util\Exception\NoSuchNoteException; use App\Core\Modules\NoteHandlerPlugin; use App\Entity\Note; use App\Util\Common; +use App\Util\Exception\NotFoundException; use App\Util\Exception\RedirectException; use App\Util\Formatting; use Symfony\Component\HttpFoundation\Request; @@ -53,21 +55,30 @@ class Repeat extends NoteHandlerPlugin return Event::next; } - // If note is repeat, "is_repeated" is 1 - $opts = ['actor_id' => $user->getId(), 'repeat_of' => $note->getId()]; - $is_repeated = DB::count('note', $opts) >= 1; + // If note is repeated, "is_repeated" is 1 + $opts = ['repeat_of' => $note->getId()]; + try { + if (DB::findOneBy('note_repeat', $opts)) { + return Event::next; + } + } catch (DuplicateFoundException $e) { + } catch (NotFoundException $e) { + } + + $is_repeat = DB::count('note_repeat', ['id' => $note->getId()]) >= 1; + // Generating URL for repeat action route $args = ['id' => $note->getId()]; $type = Router::ABSOLUTE_PATH; - $repeat_action_url = $is_repeated ? + $repeat_action_url = $is_repeat ? Router::url('repeat_remove', $args, $type) : Router::url('repeat_add', $args, $type); // Concatenating get parameter to redirect the user to where he came from $repeat_action_url .= '?from=' . substr($request->getQueryString(), 2); - $extra_classes = $is_repeated ? "note-actions-set" : "note-actions-unset"; + $extra_classes = $is_repeat ? "note-actions-set" : "note-actions-unset"; $repeat_action = [ "url" => $repeat_action_url, "classes" => "button-container repeat-button-container $extra_classes", @@ -89,6 +100,17 @@ class Repeat extends NoteHandlerPlugin return Event::next; } + public function onGetAdditionalTemplateVars(array $vars, array &$result) + { + $note_id = $vars['note_id']; + + $opts = ['id' => $note_id]; + $is_repeat = DB::count('note_repeat', $opts) >= 1; + + $result = ['is_repeat' => (bool)$is_repeat]; + return Event::stop; + } + public function onAddRoute(RouteLoader $r): bool { // Add/remove note to/from repeats diff --git a/plugins/Repeat/templates/plugins/repeat/cards/note/view.html.twig b/plugins/Repeat/templates/plugins/repeat/cards/note/view.html.twig index 62ebfd64a2..43ad26628a 100644 --- a/plugins/Repeat/templates/plugins/repeat/cards/note/view.html.twig +++ b/plugins/Repeat/templates/plugins/repeat/cards/note/view.html.twig @@ -1,22 +1,54 @@ {% extends '/cards/note/view.html.twig' %} +{% block note_author_repeated %} + {# Microformat's h-card properties indicates a face icon is a "u-logo" #} + + + {% if fullname is not null %} + {{ fullname }} + {% else %} + {{ nickname }} + {% endif %} + + {{ nickname }} {{ "repeated the following note" | trans }} + +{% endblock note_author_repeated %} + {% macro macro_note(note, replies) %} {% set nickname = note.getActorNickname() %} {% set fullname = note.getActorFullname() %} {% set actor_url = note.getActor().getUrl() %} - {% set repeat_of = note.getRepeatOf() %} + {% set additional_vars = handle_event('GetAdditionalTemplateVars', {'note_id': note.getId(), 'actor_id': note.getActorId()}) %} -
- {{ block('note_sidebar') }} -
-
- {{ block('note_author') }} - {{ block('note_actions') }} + {% if additional_vars['is_repeat'] %} +
+ {{ block('note_sidebar') }} +
+
+ {{ block('note_author_repeated') }} + {{ block('note_actions') }} +
+ + {{ block('note_replies') }}
- - {{ block('note_replies') }} -
-
+ + {% else %} +
+ {{ block('note_sidebar') }} +
+
+ {{ block('note_author') }} + {{ block('note_actions') }} +
+ + {{ block('note_replies') }} +
+
+ {% endif %} {% endmacro macro_note %} \ No newline at end of file diff --git a/plugins/Repeat/templates/repeat/remove_from_repeats.html.twig b/plugins/Repeat/templates/repeat/remove_from_repeats.html.twig index a38a8a4ebc..a41fdda3eb 100644 --- a/plugins/Repeat/templates/repeat/remove_from_repeats.html.twig +++ b/plugins/Repeat/templates/repeat/remove_from_repeats.html.twig @@ -13,7 +13,7 @@
{{ noteView.macro_note_minimal(note) }} - {{ form(remove_favourite) }} + {{ form(remove_repeat) }}
{% endblock body %} diff --git a/src/Entity/Note.php b/src/Entity/Note.php index 9e9b6c8072..6dd908efba 100644 --- a/src/Entity/Note.php +++ b/src/Entity/Note.php @@ -162,7 +162,7 @@ class Note extends Entity return $this->conversation; } - public function setRepeatOf(?int $repeat_of): self +/* public function setRepeatOf(?int $repeat_of): self { $this->repeat_of = $repeat_of; return $this; @@ -171,7 +171,7 @@ class Note extends Entity public function getRepeatOf(): ?int { return $this->repeat_of; - } + }*/ public function setScope(int $scope): self { @@ -349,7 +349,7 @@ class Note extends Entity 'is_local' => ['type' => 'bool', 'description' => 'was this note generated by a local actor'], 'source' => ['type' => 'varchar', 'foreign key' => true, 'length' => 32, 'target' => 'NoteSource.code', 'multiplicity' => 'many to one', 'description' => 'fkey to source of note, like "web", "im", or "clientname"'], 'conversation' => ['type' => 'int', 'foreign key' => true, 'target' => 'Conversation.id', 'multiplicity' => 'one to one', 'description' => 'the local conversation id'], - 'repeat_of' => ['type' => 'int', 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'description' => 'note this is a repeat of'], +// 'repeat_of' => ['type' => 'int', 'foreign key' => true, 'target' => 'Note.id', 'multiplicity' => 'one to one', 'description' => 'note this is a repeat of'], 'scope' => ['type' => 'int', 'not null' => true, 'default' => VisibilityScope::PUBLIC, 'description' => 'bit map for distribution scope; 0 = everywhere; 1 = this server only; 2 = addressees; 4 = groups; 8 = followers; 16 = messages; null = default'], 'url' => ['type' => 'text', 'description' => 'Permalink to Note'], 'language' => ['type' => 'int', 'foreign key' => true, 'target' => 'Language.id', 'multiplicity' => 'one to many', 'description' => 'The language for this note'], @@ -361,7 +361,7 @@ class Note extends Entity 'note_created_id_is_local_idx' => ['created', 'is_local'], 'note_actor_created_idx' => ['actor_id', 'created'], 'note_is_local_created_actor_idx' => ['is_local', 'created', 'actor_id'], - 'note_repeat_of_created_idx' => ['repeat_of', 'created'], +// 'note_repeat_of_created_idx' => ['repeat_of', 'created'], 'note_conversation_created_idx' => ['conversation', 'created'], 'note_reply_to_idx' => ['reply_to'], ], diff --git a/src/Twig/Runtime.php b/src/Twig/Runtime.php index de8ad7eab7..336877e539 100644 --- a/src/Twig/Runtime.php +++ b/src/Twig/Runtime.php @@ -134,6 +134,15 @@ class Runtime implements RuntimeExtensionInterface, EventSubscriberInterface return $result; } + public function getAdditionalTemplateVars(array $vars): array + { + $result = []; + if (Event::handle('GetAdditionalTemplateVars', [$vars, &$result]) !== Event::stop) { + return []; + } + return $result; + } + // ---------------------------------------------------------- /** diff --git a/templates/network/feed.html.twig b/templates/network/feed.html.twig index 0be1f49e57..2973d06151 100644 --- a/templates/network/feed.html.twig +++ b/templates/network/feed.html.twig @@ -1,4 +1,5 @@ {% extends 'stdgrid.html.twig' %} + {% set override_import = handle_override_template_import('/network/feed.html.twig', '/cards/note/view.html.twig') %} {% import override_import as noteView %}