diff --git a/plugins/ActivityPub/ActivityPub.php b/plugins/ActivityPub/ActivityPub.php index 47131f1931..fb7871ff6e 100644 --- a/plugins/ActivityPub/ActivityPub.php +++ b/plugins/ActivityPub/ActivityPub.php @@ -70,6 +70,7 @@ use function count; use function is_null; use const PHP_URL_HOST; use const PREG_SET_ORDER; +use InvalidArgumentException; /** * Adds ActivityPub support to GNU social when enabled @@ -115,13 +116,13 @@ class ActivityPub extends Plugin 'activitypub_inbox', '/inbox.json', [Inbox::class, 'handle'], - options: ['accept' => self::$accept_headers, 'format' => self::$accept_headers[0]], + options: ['format' => self::$accept_headers[0]], ); $r->connect( 'activitypub_actor_inbox', '/actor/{gsactor_id<\d+>}/inbox.json', [Inbox::class, 'handle'], - options: ['accept' => self::$accept_headers, 'format' => self::$accept_headers[0]], + options: ['format' => self::$accept_headers[0]], ); $r->connect( 'activitypub_actor_outbox', @@ -140,7 +141,7 @@ class ActivityPub extends Plugin * @param string|null $url * @return bool */ - public function onStartGetActorUrl(Actor $actor, int $type, ?string &$url): bool + public function onStartGetActorUri(Actor $actor, int $type, ?string &$url): bool { if ( // Is remote? @@ -384,6 +385,34 @@ class ActivityPub extends Plugin } } + /** + * @param mixed $object + * @return string got from URI + */ + public static function getUriByObject(mixed $object): string + { + if ($object instanceof Note) { + if($object->getIsLocal()) { + return $object->getUrl(); + } else { + // Try known remote objects + $known_object = ActivitypubObject::getByPK(['object_type' => 'note', 'object_id' => $object->getId()]); + if ($known_object instanceof ActivitypubObject) { + return $known_object->getObjectUri(); + } + } + } else if ($object instanceof Activity) { + // Try known remote activities + $known_activity = ActivitypubActivity::getByPK(['activity_id' => $object->getId()]); + if ($known_activity instanceof ActivitypubActivity) { + return $known_activity->getActivityUri(); + } else { + return Router::url('activity_view', ['id' => $object->getId()], Router::ABSOLUTE_URL); + } + } + throw new InvalidArgumentException('ActivityPub::getUriByObject found a limitation with: '.var_export($object, true)); + } + /** * Get a Note from ActivityPub URI, if it doesn't exist, attempt to fetch it * This should only be necessary internally. diff --git a/plugins/ActivityPub/Util/Model/Activity.php b/plugins/ActivityPub/Util/Model/Activity.php index 90917e4577..f5ce715a94 100644 --- a/plugins/ActivityPub/Util/Model/Activity.php +++ b/plugins/ActivityPub/Util/Model/Activity.php @@ -151,25 +151,29 @@ class Activity extends Model if ($object::class !== 'App\Entity\Activity') { throw new InvalidArgumentException('First argument type is Activity'); } - - $gs_verb_to_activity_stream_two_verb = fn($verb): string => match ($verb) { - 'create' => 'Create', - default => throw new ClientException('Invalid verb'), - }; + + $gs_verb_to_activity_stream_two_verb = null; + if (Event::handle('GSVerbToActivityStreamsTwoActivityType', [($verb = $object->getVerb()), &$gs_verb_to_activity_stream_two_verb]) === Event::next) { + $gs_verb_to_activity_stream_two_verb = match ($verb) { + 'create' => 'Create', + 'undo' => 'Undo', + default => throw new ClientException('Invalid verb'), + }; + } $attr = [ - 'type' => $gs_verb_to_activity_stream_two_verb($object->getVerb()), + 'type' => $gs_verb_to_activity_stream_two_verb, '@context' => 'https://www.w3.org/ns/activitystreams', 'id' => Router::url('activity_view', ['id' => $object->getId()], Router::ABSOLUTE_URL), 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), 'actor' => $object->getActor()->getUri(Router::ABSOLUTE_URL), 'to' => ['https://www.w3.org/ns/activitystreams#Public'], // TODO: implement proper scope address 'cc' => ['https://www.w3.org/ns/activitystreams#Public'], - 'object' => self::jsonToType(self::toJson($object->getObject())), ]; + $attr['object'] = $attr['type'] === 'Create' ? self::jsonToType(Model::toJson($object->getObject())) : ActivityPub::getUriByObject($object->getObject()); $type = self::jsonToType($attr); Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); return $type->toJson($options); } -} \ No newline at end of file +}