diff --git a/app/Federation/Handlers/QuoteRequestHandler.php b/app/Federation/Handlers/QuoteRequestHandler.php index 7c0c19d27..75c3a680a 100644 --- a/app/Federation/Handlers/QuoteRequestHandler.php +++ b/app/Federation/Handlers/QuoteRequestHandler.php @@ -3,6 +3,7 @@ namespace App\Federation\Handlers; use App\Federation\ActivityBuilders\QuoteRequestActivityBuilder; +use App\Jobs\Federation\DiscoverInstance; use App\Models\Comment; use App\Models\CommentReply; use App\Models\Profile; @@ -25,6 +26,11 @@ class QuoteRequestHandler */ public function handle(array $activity, Profile $actor, ?Profile $target = null): void { + // Ensure we discover the instance if this is a new remote actor + if (! $actor->local && $actor->uri) { + DiscoverInstance::dispatch($actor->uri)->onQueue('activitypub-in'); + } + $quotedObjectUrl = $activity['object']; $quotePostUrl = is_array($activity['instrument']) ? ($activity['instrument']['id'] ?? null) @@ -160,6 +166,31 @@ protected function approveQuoteRequest( string $quotePostUrl, Profile $quoterProfile ): void { + // Ensure the quoter profile has an inbox URL for delivery + if (! $quoterProfile->inbox_url) { + // Try to re-fetch the actor data to get the inbox URL (bypass cache) + $actorData = app(\App\Services\ActivityPubService::class)->get($quoterProfile->uri, [], true, true, true, true); + + if ($actorData && isset($actorData['inbox'])) { + $quoterProfile->inbox_url = $actorData['inbox']; + $quoterProfile->shared_inbox_url = data_get($actorData, 'endpoints.sharedInbox'); + $quoterProfile->save(); + + // Discover the instance since we're seeing it for the first time + DiscoverInstance::dispatch($quoterProfile->uri)->onQueue('activitypub-in'); + + } else { + if (config('logging.dev_log')) { + Log::error('QuoteRequest handler: Failed to fetch inbox_url for quoter', [ + 'quoter_id' => $quoterProfile->id, + 'quoter_uri' => $quoterProfile->uri, + ]); + } + + return; + } + } + $existing = QuoteAuthorization::where('quote_post_url', $quotePostUrl) ->where('quotable_type', get_class($quotable)) ->where('quotable_id', $quotable->id) @@ -212,6 +243,30 @@ protected function approveQuoteRequest( */ protected function rejectQuoteRequest(array $activity, $quotable, Profile $quoterProfile): void { + // Ensure the quoter profile has an inbox URL for delivery + if (! $quoterProfile->inbox_url) { + // Try to re-fetch the actor data to get the inbox URL (bypass cache) + $actorData = app(\App\Services\ActivityPubService::class)->get($quoterProfile->uri, [], true, true, true, true); + if ($actorData && isset($actorData['inbox'])) { + $quoterProfile->inbox_url = $actorData['inbox']; + $quoterProfile->shared_inbox_url = data_get($actorData, 'endpoints.sharedInbox'); + $quoterProfile->save(); + + // Discover the instance since we're seeing it for the first time + DiscoverInstance::dispatch($quoterProfile->uri)->onQueue('activitypub-in'); + + } else { + if (config('logging.dev_log')) { + Log::error('QuoteRequest handler: Failed to fetch inbox_url for quoter (reject)', [ + 'quoter_id' => $quoterProfile->id, + 'quoter_uri' => $quoterProfile->uri, + ]); + } + + return; + } + } + $reject = QuoteRequestActivityBuilder::buildReject( $activity, $quotable->profile diff --git a/app/Services/ActivityPubService.php b/app/Services/ActivityPubService.php index 61866c43d..aa5673f18 100644 --- a/app/Services/ActivityPubService.php +++ b/app/Services/ActivityPubService.php @@ -10,7 +10,7 @@ class ActivityPubService { - public function get($url, $params = [], $signed = true, $validateUrl = true, $validateContentType = true) + public function get($url, $params = [], $signed = true, $validateUrl = true, $validateContentType = true, $bypassCache = false) { if ($validateUrl) { $valid = app(SanitizeService::class)->url($url, true); @@ -21,9 +21,11 @@ public function get($url, $params = [], $signed = true, $validateUrl = true, $va $cacheKey = 'activitypub-fetch:'.sha1($url.json_encode($params)); - $cached = Cache::get($cacheKey); - if ($cached !== null) { - return $cached; + if (! $bypassCache) { + $cached = Cache::get($cacheKey); + if ($cached !== null) { + return $cached; + } } $lock = Cache::lock('activitypub-fetch_lock:'.sha1($url.json_encode($params)), 10); @@ -31,17 +33,19 @@ public function get($url, $params = [], $signed = true, $validateUrl = true, $va try { $lock->block(10); - $cached = Cache::get($cacheKey); - if ($cached !== null) { - return $cached; + if (! $bypassCache) { + $cached = Cache::get($cacheKey); + if ($cached !== null) { + return $cached; + } } $result = $this->fetchActivityPub($url, $params, $signed, $validateContentType); - if ($result !== false) { - Cache::put($cacheKey, $result, 14400); + if ($result !== false && $result !== null) { + Cache::put($cacheKey, $result, 14400); // Cache successful results for 4 hours } else { - Cache::put($cacheKey, null, 14400); + Cache::put($cacheKey, null, 300); // Cache failures for only 5 minutes } return $result;