diff --git a/plugins/DeleteNote/DeleteNote.php b/plugins/DeleteNote/DeleteNote.php index 26d6cd0b49..4965bcf20b 100644 --- a/plugins/DeleteNote/DeleteNote.php +++ b/plugins/DeleteNote/DeleteNote.php @@ -1,6 +1,6 @@ * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org @@ -49,6 +53,35 @@ use Symfony\Component\HttpFoundation\Request; */ class DeleteNote extends NoteHandlerPlugin { + /** + * **Checks actor permissions for the DeleteNote action, deletes given Note + * and creates respective Activity and Notification** + * + * Ensures the given Actor has sufficient permissions to perform the + * deletion. + * If it does, **Undertaker** will carry on, spelling doom for + * the given Note and **everything related to it** + * - Replies and Conversation **are unaffected**, except for the fact that + * this Note no longer exists, of course + * - Replies to this Note **will** remain on the same Conversation, and can + * **still be seen** on that Conversation (potentially separated from a + * parent, this Note) + * + * Replies shouldn't be taken out of context in any additional way, and + * **Undertaker** only calls the methods necessary to accomplish the + * deletion of this Note. Not any other as collateral damage. + * + * Creates the **_delete_ (verb)** Activity, performed on the given **Note + * (object)**, by the given **Actor (subject)**. Launches the + * NewNotification Event, stating who dared to call Undertaker. + * + * @param \App\Entity\Actor $actor + * @param \App\Entity\Note $note + * + * @return \App\Entity\Activity + * @throws \App\Util\Exception\ClientException + * @throws \App\Util\Exception\ServerException + */ private static function undertaker(Actor $actor, Note $note): Activity { // Check permissions @@ -64,12 +97,28 @@ class DeleteNote extends NoteHandlerPlugin return $activity; } + /** + * Delegates **DeleteNote::undertaker** to delete the Note provided + * + * Checks whether the Note has already been deleted, only passing on the + * responsibility to undertaker if the Note wasn't. + * + * @param \App\Entity\Note|int $note + * @param \App\Entity\Actor|int $actor + * @param string $source + * + * @return \App\Entity\Activity|null + * @throws \App\Util\Exception\ClientException + * @throws \App\Util\Exception\DuplicateFoundException + * @throws \App\Util\Exception\NotFoundException + * @throws \App\Util\Exception\ServerException + */ public static function deleteNote(Note|int $note, Actor|int $actor, string $source = 'web'): ?Activity { - $actor = \is_int($actor) ? Actor::getById($actor) : $actor; - $note = \is_int($note) ? Note::getById($note) : $note; + $actor = is_int($actor) ? Actor::getById($actor) : $actor; + $note = is_int($note) ? Note::getById($note) : $note; // Try and find if note was already deleted - if (\is_null(DB::findOneBy(Activity::class, ['verb' => 'delete', 'object_type' => 'note', 'object_id' => $note->getId()], return_null: true))) { + if (is_null(DB::findOneBy(Activity::class, ['verb' => 'delete', 'object_type' => 'note', 'object_id' => $note->getId()], return_null: true))) { // If none found, then undertaker has a job to do return self::undertaker($actor, $note); } else { @@ -77,6 +126,14 @@ class DeleteNote extends NoteHandlerPlugin } } + /** + * Adds and connects the _delete_note_action_ route to + * Controller\DeleteNote::class + * + * @param \App\Core\Router\RouteLoader $r + * + * @return bool Event hook + */ public function onAddRoute(RouteLoader $r) { $r->connect(id: 'delete_note_action', uri_path: '/object/note/{note_id<\d+>}/delete', target: Controller\DeleteNote::class); @@ -84,31 +141,48 @@ class DeleteNote extends NoteHandlerPlugin return Event::next; } + /** + * **Catches AddExtraNoteActions Event** + * + * Adds an anchor link to the route _delete_note_action_ in the **Note card + * template**. More specifically, in the **note_actions block**. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @param \App\Entity\Note $note + * @param array $actions + * + * @return bool Event hook + * @throws \App\Util\Exception\DuplicateFoundException + * @throws \App\Util\Exception\NotFoundException + * @throws \App\Util\Exception\ServerException + */ public function onAddExtraNoteActions(Request $request, Note $note, array &$actions) { - if (\is_null($actor = Common::actor())) { + if (is_null($actor = Common::actor())) { return Event::next; } // Only add action if note wasn't already deleted! - if (\is_null(DB::findOneBy(Activity::class, ['verb' => 'delete', 'object_type' => 'note', 'object_id' => $note->getId()], return_null: true)) - // And has permissions - && $actor->canAdmin($note->getActor())) { + if (is_null(DB::findOneBy(Activity::class, ['verb' => 'delete', 'object_type' => 'note', 'object_id' => $note->getId()], return_null: true)) + // And has permissions + && $actor->canAdmin($note->getActor())) { $delete_action_url = Router::url('delete_note_action', ['note_id' => $note->getId()]); - $query_string = $request->getQueryString(); + $query_string = $request->getQueryString(); $delete_action_url .= '?from=' . mb_substr($query_string, 2); $actions[] = [ - 'title' => _m('Delete note'), + 'title' => _m('Delete note'), 'classes' => '', - 'url' => $delete_action_url, + 'url' => $delete_action_url, ]; } return Event::next; } - // ActivityPub + /* + * ActivityPub handling and processing for DeleteNote start + */ - private function activitypub_handler(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool + private function activitypub_handler(Actor $actor, AbstractObject $type_activity, mixed $type_object, ?ActivitypubActivity &$ap_act): bool { if ($type_activity->get('type') !== 'Delete' || !($type_object instanceof Note)) { @@ -116,25 +190,25 @@ class DeleteNote extends NoteHandlerPlugin } $activity = self::deleteNote($type_object, $actor, source: 'ActivityPub'); - if (!\is_null($activity)) { + if (!is_null($activity)) { // Store ActivityPub Activity - $ap_act = \Plugin\ActivityPub\Entity\ActivitypubActivity::create([ - 'activity_id' => $activity->getId(), + $ap_act = ActivitypubActivity::create([ + 'activity_id' => $activity->getId(), 'activity_uri' => $type_activity->get('id'), - 'created' => new DateTime($type_activity->get('published') ?? 'now'), - 'modified' => new DateTime(), + 'created' => new DateTime($type_activity->get('published') ?? 'now'), + 'modified' => new DateTime(), ]); DB::persist($ap_act); } return Event::stop; } - public function onNewActivityPubActivity(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, \ActivityPhp\Type\AbstractObject $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool + public function onNewActivityPubActivity(Actor $actor, AbstractObject $type_activity, AbstractObject $type_object, ?ActivitypubActivity &$ap_act): bool { return $this->activitypub_handler($actor, $type_activity, $type_object, $ap_act); } - public function onNewActivityPubActivityWithObject(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool + public function onNewActivityPubActivityWithObject(Actor $actor, AbstractObject $type_activity, mixed $type_object, ?ActivitypubActivity &$ap_act): bool { return $this->activitypub_handler($actor, $type_activity, $type_object, $ap_act); }