From 117549bf1e5c84b2b06e159f0b2765e86d621619 Mon Sep 17 00:00:00 2001 From: Eliseu Amaro Date: Thu, 27 Jan 2022 00:54:27 +0000 Subject: [PATCH] [PLUGINS][Favourite] Remove favourite action properly removes note_favourite Entity now [COMPONENTS][Collection] Simplyfying feed-action-details template section [COMPONENTS] Documentation work [PLUGINS] Documentation work --- .../templates/collection/notes.html.twig | 12 +- components/Conversation/Conversation.php | 45 +++++-- .../Conversation/Entity/Conversation.php | 1 - components/LeftPanel/LeftPanel.php | 7 +- plugins/Favourite/Favourite.php | 114 +++++++++++++----- plugins/Oomox/Oomox.php | 6 +- plugins/RepeatNote/Controller/Repeat.php | 34 +++--- plugins/RepeatNote/RepeatNote.php | 66 ++++++++-- .../assets/default_theme/css/pages/feeds.css | 11 +- templates/cards/attachments/show.html.twig | 11 +- templates/cards/note/view.html.twig | 24 ++-- 11 files changed, 227 insertions(+), 104 deletions(-) diff --git a/components/Collection/templates/collection/notes.html.twig b/components/Collection/templates/collection/notes.html.twig index 011073a333..09c8fdc1b7 100644 --- a/components/Collection/templates/collection/notes.html.twig +++ b/components/Collection/templates/collection/notes.html.twig @@ -30,13 +30,11 @@ {{ icon('filter', 'icon icon-feed-actions') | raw }} {# button-container #} -
- - {% for block in handle_event('AddFeedActions', app.request, notes is defined and notes is not empty) %} - {{ block | raw }} - {% endfor %} - -
+ + {% for block in handle_event('AddFeedActions', app.request, notes is defined and notes is not empty) %} + {{ block | raw }} + {% endfor %} + diff --git a/components/Conversation/Conversation.php b/components/Conversation/Conversation.php index ad5bf5a31d..0f35113bf2 100644 --- a/components/Conversation/Conversation.php +++ b/components/Conversation/Conversation.php @@ -1,9 +1,7 @@ . - // }}} +/** + * @author Hugo Sales + * @author Eliseu Amaro + * @copyright 2021-2022 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + namespace Component\Conversation; use App\Core\Cache; @@ -34,7 +38,6 @@ use App\Entity\Activity; use App\Entity\Actor; use App\Entity\Note; use App\Util\Common; -use App\Util\Exception\RedirectException; use App\Util\Formatting; use Component\Conversation\Entity\Conversation as ConversationEntity; use Component\Conversation\Entity\ConversationMute; @@ -101,6 +104,8 @@ class Conversation extends Component * 'id' (HTML markup id used to redirect user to this anchor upon performing the action) * * @throws \App\Util\Exception\ServerException + * + * @return bool EventHook */ public function onAddNoteActions(Request $request, Note $note, array &$actions): bool { @@ -134,7 +139,14 @@ class Conversation extends Component } /** - * Posting event to add extra info to a note + * Posting event to add extra information to Component\Posting form data + * + * @param array $data Transport data to be filled with reply_to_id + * + * @throws \App\Util\Exception\ClientException + * @throws \App\Util\Exception\NoSuchNoteException + * + * @return bool EventHook */ public function onPostingModifyData(Request $request, Actor $actor, array &$data): bool { @@ -153,6 +165,8 @@ class Conversation extends Component * * @param array $vars Contains information related to Note currently being rendered * @param array $result Contains keys 'actors', and 'action'. Needed to construct a string, stating who ($result['actors']), has already performed a reply ($result['action']), in the given Note (vars['note']) + * + * @return bool EventHook */ public function onAppendCardNote(array $vars, array &$result): bool { @@ -184,8 +198,10 @@ class Conversation extends Component * * @param \App\Entity\Actor $actor The Actor currently attempting to post a Note * @param null|\App\Entity\Actor $context_actor The 'owner' of the current route (e.g. Group or Actor), used to target it + * + * @return bool EventHook */ - public function onPostingGetContextActor(Request $request, Actor $actor, ?Actor &$context_actor) + public function onPostingGetContextActor(Request $request, Actor $actor, ?Actor &$context_actor): bool { $to_note_id = $request->query->get('reply_to_id'); if (!\is_null($to_note_id)) { @@ -198,10 +214,8 @@ class Conversation extends Component /** * Add minimal Note card to RightPanel template - * - * @throws RedirectException */ - public function onPrependPostingForm(Request $request, array &$elements) + public function onPrependPostingForm(Request $request, array &$elements): bool { $elements[] = Formatting::twigRenderFile('cards/note/macro_note_minimal_wrapper.html.twig', ['note' => Note::getById((int) $request->query->get('reply_to_id'))]); return Event::next; @@ -213,6 +227,8 @@ class Conversation extends Component * * @param \App\Entity\Note $note Note being deleted * @param \App\Entity\Actor $actor Actor that performed the delete action + * + * @return bool EventHook */ public function onNoteDeleteRelated(Note &$note, Actor $actor): bool { @@ -233,7 +249,7 @@ class Conversation extends Component * * @return bool EventHook */ - public function onAddExtraNoteActions(Request $request, Note $note, array &$actions) + public function onAddExtraNoteActions(Request $request, Note $note, array &$actions): bool { if (\is_null($user = Common::user())) { return Event::next; @@ -261,7 +277,14 @@ class Conversation extends Component return Event::next; } - public function onNewNotificationShould(Activity $activity, Actor $actor) + /** + * Prevents new Notifications to appear for muted conversations + * + * @param Activity $activity Notification Activity + * + * @return bool EventHook + */ + public function onNewNotificationShould(Activity $activity, Actor $actor): bool { if ($activity->getObjectType() === 'note' && ConversationMute::isMuted($activity, $actor)) { return Event::stop; diff --git a/components/Conversation/Entity/Conversation.php b/components/Conversation/Entity/Conversation.php index 9ed2d8cb62..86c56a4b2d 100644 --- a/components/Conversation/Entity/Conversation.php +++ b/components/Conversation/Entity/Conversation.php @@ -26,7 +26,6 @@ namespace Component\Conversation\Entity; use App\Core\DB\DB; use App\Core\Entity; use App\Core\Router\Router; -use App\Entity\Note; /** * Entity class for Conversations diff --git a/components/LeftPanel/LeftPanel.php b/components/LeftPanel/LeftPanel.php index 51806a6bb7..89026b5cf6 100644 --- a/components/LeftPanel/LeftPanel.php +++ b/components/LeftPanel/LeftPanel.php @@ -42,7 +42,12 @@ class LeftPanel extends Component return Event::next; } - public function onAppendFeed(Actor $actor, string $title, string $route, array $route_params) + /** + * @throws \App\Util\Exception\DuplicateFoundException + * @throws \App\Util\Exception\ServerException + * @throws ClientException + */ + public function onAppendFeed(Actor $actor, string $title, string $route, array $route_params): bool { $cache_key = Feed::cacheKey($actor); $feeds = Feed::getFeeds($actor); diff --git a/plugins/Favourite/Favourite.php b/plugins/Favourite/Favourite.php index 2952eebaad..dfd9ea993d 100644 --- a/plugins/Favourite/Favourite.php +++ b/plugins/Favourite/Favourite.php @@ -21,6 +21,13 @@ declare(strict_types = 1); // }}} +/** + * @author Eliseu Amaro + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021-2022 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + namespace Plugin\Favourite; use App\Core\Cache; @@ -49,10 +56,10 @@ class Favourite extends NoteHandlerPlugin * * A new notification is then handled, informing all interested Actors of this action * + * @param int $note_id Note id being favoured + * @param int $actor_id Actor performing favourite Activity + * * @throws \App\Util\Exception\ServerException - * @throws \Doctrine\ORM\OptimisticLockException - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\TransactionRequiredException */ public static function favourNote(int $note_id, int $actor_id, string $source = 'web'): ?Activity { @@ -84,20 +91,21 @@ class Favourite extends NoteHandlerPlugin * * Informs all interested Actors of this action, handling out the NewNotification event * + * @param int $note_id Note id being unfavoured + * @param int $actor_id Actor undoing favourite Activity + * * @throws \App\Util\Exception\ServerException - * @throws \Doctrine\ORM\OptimisticLockException - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\TransactionRequiredException */ public static function unfavourNote(int $note_id, int $actor_id, string $source = 'web'): ?Activity { $note_already_favoured = Cache::get( FavouriteEntity::cacheKeys($note_id, $actor_id)['favourite'], - fn () => DB::findOneBy('note_favourite', ['note_id' => $note_id, 'actor_id' => $actor_id], return_null: true), + static fn () => DB::findOneBy('note_favourite', ['note_id' => $note_id, 'actor_id' => $actor_id], return_null: true), ); $activity = null; if (!\is_null($note_already_favoured)) { - DB::remove($note_already_favoured); + DB::removeBy(FavouriteEntity::class, ['note_id' => $note_id, 'actor_id' => $actor_id]); + Cache::delete(FavouriteEntity::cacheKeys($note_id, $actor_id)['favourite']); $favourite_activity = DB::findBy('activity', ['verb' => 'favourite', 'object_type' => 'note', 'actor_id' => $actor_id, 'object_id' => $note_id], order_by: ['created' => 'DESC'])[0]; $activity = Activity::create([ @@ -118,11 +126,10 @@ class Favourite extends NoteHandlerPlugin * HTML rendering event that adds the favourite form as a note * action, if a user is logged in * - * @throws \Doctrine\ORM\OptimisticLockException - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\TransactionRequiredException + * @param Note $note Current Note being rendered + * @param array $actions Array containing all Note actions to be rendered * - * @return bool Event hook + * @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers */ public function onAddNoteActions(Request $request, Note $note, array &$actions): bool { @@ -134,9 +141,9 @@ class Favourite extends NoteHandlerPlugin $opts = ['note_id' => $note->getId(), 'actor_id' => $user->getId()]; $is_favourite = !\is_null( Cache::get( - FavouriteEntity::cacheKeys($note->getId(), $user->getId())['favourite'], - fn () => DB::findOneBy('note_favourite', $opts, return_null: true), - ), + FavouriteEntity::cacheKeys($note->getId(), $user->getId())['favourite'], + static fn () => DB::findOneBy('note_favourite', $opts, return_null: true), + ), ); // Generating URL for favourite action route @@ -162,7 +169,15 @@ class Favourite extends NoteHandlerPlugin return Event::next; } - public function onAppendCardNote(array $vars, array &$result) + /** + * Appends on Note currently being rendered complementary information regarding whom (subject) performed which Activity (verb) on aforementioned Note (object) + * + * @param array $vars Array containing necessary info to process event. In this case, contains the current Note being rendered + * @param array $result Contains a hashmap for each Activity performed on Note (object) + * + * @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers + */ + public function onAppendCardNote(array $vars, array &$result): bool { // If note is the original and user isn't the one who repeated, append on end "user repeated this" // If user is the one who repeated, append on end "you repeated this, remove repeat?" @@ -198,6 +213,9 @@ class Favourite extends NoteHandlerPlugin return Event::next; } + /** + * Maps Routes to their respective Controllers + */ public function onAddRoute(RouteLoader $r): bool { // Add/remove note to/from favourites @@ -214,7 +232,14 @@ class Favourite extends NoteHandlerPlugin return Event::next; } - public function onCreateDefaultFeeds(int $actor_id, LocalUser $user, int &$ordering) + /** + * Creates two feeds, including reverse favourites or favourites performed by given Actor + * + * @param int $actor_id Whom the favourites belong to + * + * @throws \App\Util\Exception\ServerException + */ + public function onCreateDefaultFeeds(int $actor_id, LocalUser $user, int &$ordering): bool { DB::persist(Feed::create([ 'actor_id' => $actor_id, @@ -243,6 +268,15 @@ class Favourite extends NoteHandlerPlugin * @param mixed $type_object Activity's Object * @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity * + * @throws \App\Util\Exception\ClientException + * @throws \App\Util\Exception\DuplicateFoundException + * @throws \App\Util\Exception\NoSuchActorException + * @throws \App\Util\Exception\ServerException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * * @return bool Returns `Event::stop` if handled, `Event::next` otherwise */ private function activitypub_handler(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool @@ -262,24 +296,22 @@ class Favourite extends NoteHandlerPlugin } else { return Event::next; } - } else { // Undo Favourite - if ($type_object instanceof \ActivityPhp\Type\AbstractObject) { - $ap_prev_favourite_act = \Plugin\ActivityPub\Util\Model\Activity::fromJson($type_object); - $prev_favourite_act = $ap_prev_favourite_act->getActivity(); - if ($prev_favourite_act->getVerb() === 'favourite' && $prev_favourite_act->getObjectType() === 'note') { - $note_id = $prev_favourite_act->getObjectId(); - } else { - return Event::next; - } - } elseif ($type_object instanceof Activity) { - if ($type_object->getVerb() === 'favourite' && $type_object->getObjectType() === 'note') { - $note_id = $type_object->getObjectId(); - } else { - return Event::next; - } + } elseif ($type_object instanceof \ActivityPhp\Type\AbstractObject) { + $ap_prev_favourite_act = \Plugin\ActivityPub\Util\Model\Activity::fromJson($type_object); + $prev_favourite_act = $ap_prev_favourite_act->getActivity(); + if ($prev_favourite_act->getVerb() === 'favourite' && $prev_favourite_act->getObjectType() === 'note') { + $note_id = $prev_favourite_act->getObjectId(); } else { return Event::next; } + } elseif ($type_object instanceof Activity) { + if ($type_object->getVerb() === 'favourite' && $type_object->getObjectType() === 'note') { + $note_id = $type_object->getObjectId(); + } else { + return Event::next; + } + } else { + return Event::next; } if ($type_activity->get('type') === 'Like') { @@ -308,6 +340,15 @@ class Favourite extends NoteHandlerPlugin * @param \ActivityPhp\Type\AbstractObject $type_object Activity Streams 2.0 Object * @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity * + * @throws \App\Util\Exception\ClientException + * @throws \App\Util\Exception\DuplicateFoundException + * @throws \App\Util\Exception\NoSuchActorException + * @throws \App\Util\Exception\ServerException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * * @return bool Returns `Event::stop` if handled, `Event::next` otherwise */ public function onNewActivityPubActivity(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, \ActivityPhp\Type\AbstractObject $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool @@ -323,6 +364,15 @@ class Favourite extends NoteHandlerPlugin * @param mixed $type_object Object * @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity * + * @throws \App\Util\Exception\ClientException + * @throws \App\Util\Exception\DuplicateFoundException + * @throws \App\Util\Exception\NoSuchActorException + * @throws \App\Util\Exception\ServerException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * * @return bool Returns `Event::stop` if handled, `Event::next` otherwise */ public function onNewActivityPubActivityWithObject(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool diff --git a/plugins/Oomox/Oomox.php b/plugins/Oomox/Oomox.php index 42153e2ec4..082817556d 100644 --- a/plugins/Oomox/Oomox.php +++ b/plugins/Oomox/Oomox.php @@ -49,7 +49,7 @@ use Symfony\Component\HttpFoundation\Request; class Oomox extends Plugin { /** - * Map URLs to actions + * Maps Routes to their respective Controllers */ public function onAddRoute(RouteLoader $r): bool { @@ -108,10 +108,8 @@ class Oomox extends Plugin /** * Adds to array $styles the generated CSS according to user settings, if any are present. - * - * @return bool */ - public function onEndShowStyles(array &$styles, string $route) + public function onEndShowStyles(array &$styles, string $route): bool { $user = Common::user(); if (!\is_null($user) && !\is_null(Cache::get(self::cacheKey($user), fn () => self::getEntity($user)))) { diff --git a/plugins/RepeatNote/Controller/Repeat.php b/plugins/RepeatNote/Controller/Repeat.php index 2eac64a650..5f30191c9d 100644 --- a/plugins/RepeatNote/Controller/Repeat.php +++ b/plugins/RepeatNote/Controller/Repeat.php @@ -33,7 +33,6 @@ use App\Entity\Note; use App\Util\Common; use App\Util\Exception\ClientException; use App\Util\Exception\NoLoggedInUser; -use App\Util\Exception\NoSuchNoteException; use App\Util\Exception\RedirectException; use App\Util\Exception\ServerException; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -44,9 +43,11 @@ class Repeat extends Controller /** * Controller for the note repeat non-JS page * + * @param int $note_id Note being repeated + * + * @throws \App\Util\Exception\DuplicateFoundException * @throws ClientException * @throws NoLoggedInUser - * @throws NoSuchNoteException * @throws RedirectException * @throws ServerException */ @@ -79,14 +80,13 @@ class Repeat extends Controller if (Router::isAbsolute($from)) { Log::warning("Actor {$actor_id} attempted to reply to a note and then get redirected to another host, or the URL was invalid ({$from})"); throw new ClientException(_m('Can not redirect to outside the website from here'), 400); // 400 Bad request (deceptive) - } else { - // TODO anchor on element id - throw new RedirectException(url: $from); } - } else { - // If we don't have a URL to return to, go to the instance root - throw new RedirectException('root'); + // TODO anchor on element id + throw new RedirectException(url: $from); } + + // If we don't have a URL to return to, go to the instance root + throw new RedirectException('root'); } return [ @@ -97,9 +97,14 @@ class Repeat extends Controller } /** + * Controller for the note unrepeat non-JS page + * + * @param int $note_id Note being unrepeated + * + * @throws \App\Util\Exception\DuplicateFoundException + * @throws \App\Util\Exception\NotFoundException * @throws ClientException * @throws NoLoggedInUser - * @throws NoSuchNoteException * @throws RedirectException * @throws ServerException */ @@ -134,14 +139,13 @@ class Repeat extends Controller if (Router::isAbsolute($from)) { Log::warning("Actor {$actor_id} attempted to reply to a note and then get redirected to another host, or the URL was invalid ({$from})"); throw new ClientException(_m('Can not redirect to outside the website from here'), 400); // 400 Bad request (deceptive) - } else { - // TODO anchor on element id - throw new RedirectException(url: $from); } - } else { - // If we don't have a URL to return to, go to the instance root - throw new RedirectException('root'); + // TODO anchor on element id + throw new RedirectException(url: $from); } + + // If we don't have a URL to return to, go to the instance root + throw new RedirectException('root'); } return [ diff --git a/plugins/RepeatNote/RepeatNote.php b/plugins/RepeatNote/RepeatNote.php index 7654270317..8e2661fc56 100644 --- a/plugins/RepeatNote/RepeatNote.php +++ b/plugins/RepeatNote/RepeatNote.php @@ -19,6 +19,13 @@ declare(strict_types = 1); // along with GNU social. If not, see . // }}} +/** + * @author Eliseu Amaro + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021-2022 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + namespace Plugin\RepeatNote; use App\Core\Cache; @@ -32,7 +39,6 @@ use App\Entity\Activity; use App\Entity\Actor; use App\Entity\Note; use App\Util\Common; -use App\Util\Exception\BugFoundException; use App\Util\Exception\ClientException; use App\Util\Exception\DuplicateFoundException; use App\Util\Exception\ServerException; @@ -57,7 +63,9 @@ class RepeatNote extends NoteHandlerPlugin * In the end, the Activity is created, and a new notification for the * repeat Activity created * - * @throws BugFoundException + * @param Note $note Note being repeated + * @param int $actor_id Actor id of whom is performing the repeat Activity + * * @throws ClientException * @throws DuplicateFoundException * @throws ServerException @@ -116,6 +124,11 @@ class RepeatNote extends NoteHandlerPlugin * Finally, creates a new Activity, undoing the repeat, and the respective * Notification is handled. * + * @param int $note_id Note id being unrepeated + * @param int $actor_id Actor undoing repeat Activity + * + * @throws \App\Util\Exception\NotFoundException + * @throws DuplicateFoundException * @throws ServerException */ public static function unrepeatNote(int $note_id, int $actor_id, string $source = 'web'): ?Activity @@ -176,6 +189,10 @@ class RepeatNote extends NoteHandlerPlugin /** * Filters repeats out of Conversations, and replaces a repeat with the * original Note on Actor feed + * + * @param array $notes List of Notes to be filtered + * + * @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers */ public function onFilterNoteList(?Actor $actor, array &$notes, Request $request): bool { @@ -183,7 +200,7 @@ class RepeatNote extends NoteHandlerPlugin // it's pretty cool if (str_starts_with($request->get('_route'), 'actor_view_')) { $notes = array_map( - fn (Note $note) => RepeatEntity::isNoteRepeat($note) + static fn (Note $note) => RepeatEntity::isNoteRepeat($note) ? Note::getById(RepeatEntity::getByPK($note->getId())->getRepeatOf()) : $note, $notes, @@ -192,7 +209,7 @@ class RepeatNote extends NoteHandlerPlugin } // Filter out repeats altogether - $notes = array_filter($notes, fn (Note $note) => !RepeatEntity::isNoteRepeat($note)); + $notes = array_filter($notes, static fn (Note $note) => !RepeatEntity::isNoteRepeat($note)); return Event::next; } @@ -200,7 +217,7 @@ class RepeatNote extends NoteHandlerPlugin * HTML rendering event that adds the repeat form as a note * action, if a user is logged in * - * @return bool Event hook + * @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers */ public function onAddNoteActions(Request $request, Note $note, array &$actions): bool { @@ -244,7 +261,7 @@ class RepeatNote extends NoteHandlerPlugin * @param array $result Rendered String containing anchors for Actors that * repeated the Note * - * @return bool + * @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers */ public function onAppendCardNote(array $vars, array &$result) { @@ -278,6 +295,11 @@ class RepeatNote extends NoteHandlerPlugin /** * Deletes every repeat entity that is related to a deleted Note in its * respective table + * + * @param Note $note Note to be deleted + * @param Actor $actor Who performed the Delete action + * + * @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers */ public function onNoteDeleteRelated(Note &$note, Actor $actor): bool { @@ -299,7 +321,7 @@ class RepeatNote extends NoteHandlerPlugin * - **repeat_remove** * same as above, except that it undoes the aforementioned action * - * @return bool Event hook + * @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers */ public function onAddRoute(RouteLoader $r): bool { @@ -320,6 +342,16 @@ class RepeatNote extends NoteHandlerPlugin * @param mixed $type_object Activity's Object * @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity * + * @throws \App\Util\Exception\NoSuchActorException + * @throws \App\Util\Exception\NotFoundException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws ClientException + * @throws DuplicateFoundException + * @throws ServerException + * * @return bool Returns `Event::stop` if handled, `Event::next` otherwise */ private function activitypub_handler(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool @@ -387,6 +419,16 @@ class RepeatNote extends NoteHandlerPlugin * @param \ActivityPhp\Type\AbstractObject $type_object Activity Streams 2.0 Object * @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity * + * @throws \App\Util\Exception\NoSuchActorException + * @throws \App\Util\Exception\NotFoundException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws ClientException + * @throws DuplicateFoundException + * @throws ServerException + * * @return bool Returns `Event::stop` if handled, `Event::next` otherwise */ public function onNewActivityPubActivity(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, \ActivityPhp\Type\AbstractObject $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool @@ -402,6 +444,16 @@ class RepeatNote extends NoteHandlerPlugin * @param mixed $type_object Object * @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity * + * @throws \App\Util\Exception\NoSuchActorException + * @throws \App\Util\Exception\NotFoundException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws ClientException + * @throws DuplicateFoundException + * @throws ServerException + * * @return bool Returns `Event::stop` if handled, `Event::next` otherwise */ public function onNewActivityPubActivityWithObject(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool diff --git a/public/assets/default_theme/css/pages/feeds.css b/public/assets/default_theme/css/pages/feeds.css index d8c3dc216c..34e5eee0c7 100644 --- a/public/assets/default_theme/css/pages/feeds.css +++ b/public/assets/default_theme/css/pages/feeds.css @@ -98,10 +98,11 @@ .feed-actions-details[open] > .feed-actions-details-dropdown, .note-actions-extra-details[open] > summary + * { background: var(--background-card); - border: 2px solid var(--border); + border: 1px solid var(--border); border-radius: var(--s); box-shadow: var(--shadow); display: flex; + flex-direction: column; padding: 4px 8px; position: absolute; right: 0; @@ -167,14 +168,16 @@ text-decoration: underline; } -.h-entry figure { +.h-entry figure, +.note-attachments-unit figure { background: var(--gradient); border-radius: var(--s); margin: unset; padding: var(--s); } -.h-entry img { +.h-entry img, +.note-attachments-unit figure img { background: repeating-conic-gradient(#ffffff66 0deg 90deg, #ffffff33 0deg 180deg) 0 0/40px 40px round; } @@ -279,7 +282,7 @@ embed header { .note-actions-extra-details summary { opacity: 0.5; } -.note-actions-extra-details[open] > summary + * > li { +.note-actions-extra-details[open] > summary + * > a { font-size: 0.937rem; line-height: 2; } diff --git a/templates/cards/attachments/show.html.twig b/templates/cards/attachments/show.html.twig index 1a72a61763..0328ea0eae 100644 --- a/templates/cards/attachments/show.html.twig +++ b/templates/cards/attachments/show.html.twig @@ -1,10 +1,9 @@ {% extends 'stdgrid.html.twig' %} {% block body %} -
-
- {% include '/cards/attachments/view.html.twig' with {'attachment': attachment, 'note': note, 'title': title} only %} - {{ 'Download link' | trans }} -
-
+
+

{{ 'Attachment' | trans }} {{ title }}

+ {% include '/cards/attachments/view.html.twig' with {'attachment': attachment, 'note': note, 'title': title} only %} + {{ 'Original attachment link' | trans }} +
{% endblock body %} \ No newline at end of file diff --git a/templates/cards/note/view.html.twig b/templates/cards/note/view.html.twig index e3fe3a7f9c..16df0f1ca9 100644 --- a/templates/cards/note/view.html.twig +++ b/templates/cards/note/view.html.twig @@ -4,29 +4,20 @@
  • - {{ icon('kebab', 'icon icon-note-actions-extra') | raw }} {# button-container #} + {{ icon('kebab', 'icon icon-note-actions-extra') | raw }} - +
  • {% for current_action in get_note_actions(note) %} -
  • - -
  • +
  • {% endfor %} {% endif %} @@ -79,7 +70,8 @@ {% block note_author %} {# Microformat's h-card properties indicates a face icon is a "u-logo" #} - + {% if fullname is not null %} {{ fullname }} {% else %}