From c8e40e0fd399e0c501d2160e7a2d491bf2bacd41 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 28 Jun 2021 22:37:38 -0600 Subject: [PATCH] Update SharePipeline, add Undo->Announce support --- app/Http/Controllers/Api/ApiV1Controller.php | 16 +-- app/Http/Controllers/StatusController.php | 8 +- app/Jobs/SharePipeline/SharePipeline.php | 12 +- app/Jobs/SharePipeline/UndoSharePipeline.php | 118 +++++++++++++++++++ 4 files changed, 137 insertions(+), 17 deletions(-) create mode 100644 app/Jobs/SharePipeline/UndoSharePipeline.php diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 681eae421..fb2c415de 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -1938,8 +1938,6 @@ class ApiV1Controller extends Controller ]); if($share->wasRecentlyCreated == true) { - $status->reblogs_count = $status->shares()->count(); - $status->save(); SharePipeline::dispatch($share); } @@ -1971,13 +1969,17 @@ class ApiV1Controller extends Controller } } - Status::whereProfileId($user->profile_id) + $reblog = Status::whereProfileId($user->profile_id) ->whereReblogOfId($status->id) - ->delete(); - $status->reblogs_count = $status->shares()->count(); - $status->save(); + ->first(); - StatusService::del($status->id); + if(!$reblog) { + $resource = new Fractal\Resource\Item($status, new StatusTransformer()); + $res = $this->fractal->createData($resource)->toArray(); + return response()->json($res); + } + + UndoSharePipeline::dispatch($reblog); $resource = new Fractal\Resource\Item($status, new StatusTransformer()); $res = $this->fractal->createData($resource)->toArray(); return response()->json($res); diff --git a/app/Http/Controllers/StatusController.php b/app/Http/Controllers/StatusController.php index 012876aa8..0cf4a513b 100644 --- a/app/Http/Controllers/StatusController.php +++ b/app/Http/Controllers/StatusController.php @@ -6,6 +6,7 @@ use App\Jobs\ImageOptimizePipeline\ImageOptimize; use App\Jobs\StatusPipeline\NewStatusPipeline; use App\Jobs\StatusPipeline\StatusDelete; use App\Jobs\SharePipeline\SharePipeline; +use App\Jobs\SharePipeline\UndoSharePipeline; use App\AccountInterstitial; use App\Media; use App\Profile; @@ -250,7 +251,7 @@ class StatusController extends Controller ->whereReblogOfId($status->id) ->get(); foreach ($shares as $share) { - $share->delete(); + UndoSharePipeline::dispatch($share); $count--; } } else { @@ -263,11 +264,6 @@ class StatusController extends Controller SharePipeline::dispatch($share); } - if($count >= 0) { - $status->reblogs_count = $count; - $status->save(); - } - Cache::forget('status:'.$status->id.':sharedby:userid:'.$user->id); StatusService::del($status->id); diff --git a/app/Jobs/SharePipeline/SharePipeline.php b/app/Jobs/SharePipeline/SharePipeline.php index 46ed8bf25..db7ea4c01 100644 --- a/app/Jobs/SharePipeline/SharePipeline.php +++ b/app/Jobs/SharePipeline/SharePipeline.php @@ -47,8 +47,9 @@ class SharePipeline implements ShouldQueue public function handle() { $status = $this->status; + $parent = $this->status->parent(); $actor = $status->profile; - $target = $status->parent()->profile; + $target = $parent->profile; if ($status->uri !== null) { // Ignore notifications to remote statuses @@ -60,19 +61,22 @@ class SharePipeline implements ShouldQueue ->whereAction('share') ->whereItemId($status->reblog_of_id) ->whereItemType('App\Status') - ->count(); + ->exists(); - if ($target->id === $status->profile_id) { + if($target->id === $status->profile_id) { $this->remoteAnnounceDeliver(); return true; } - if( $exists !== 0) { + if($exists === true) { return true; } $this->remoteAnnounceDeliver(); + $parent->reblogs_count = $parent->shares()->count(); + $parent->save(); + try { $notification = new Notification; $notification->profile_id = $target->id; diff --git a/app/Jobs/SharePipeline/UndoSharePipeline.php b/app/Jobs/SharePipeline/UndoSharePipeline.php new file mode 100644 index 000000000..6336ac675 --- /dev/null +++ b/app/Jobs/SharePipeline/UndoSharePipeline.php @@ -0,0 +1,118 @@ +status = $status; + } + + public function handle() + { + $status = $this->status; + $actor = $status->profile; + $parent = $status->parent(); + $target = $status->parent()->profile; + + if ($status->uri !== null) { + return; + } + + if($target->domain === null) { + Notification::whereProfileId($target->id) + ->whereActorId($status->profile_id) + ->whereAction('share') + ->whereItemId($status->reblog_of_id) + ->whereItemType('App\Status') + ->delete(); + } + + $this->remoteAnnounceDeliver(); + + if($parent->reblogs_count > 0) { + $parent->reblogs_count = $parent->reblogs_count - 1; + $parent->save(); + StatusService::del($parent->id); + } + + $status->delete(); + + return 1; + } + + public function remoteAnnounceDeliver() + { + if(config_cache('federation.activitypub.enabled') == false) { + return 1; + } + + $status = $this->status; + $profile = $status->profile; + + $fractal = new Fractal\Manager(); + $fractal->setSerializer(new ArraySerializer()); + $resource = new Fractal\Resource\Item($status, new UndoAnnounce()); + $activity = $fractal->createData($resource)->toArray(); + + $audience = $status->profile->getAudienceInbox(); + + if(empty($audience) || $status->scope != 'public') { + return 1; + } + + $payload = json_encode($activity); + + $client = new Client([ + 'timeout' => config('federation.activitypub.delivery.timeout') + ]); + + $requests = function($audience) use ($client, $activity, $profile, $payload) { + foreach($audience as $url) { + $headers = HttpSignature::sign($profile, $url, $activity); + yield function() use ($client, $url, $headers, $payload) { + return $client->postAsync($url, [ + 'curl' => [ + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => $payload, + CURLOPT_HEADER => true + ] + ]); + }; + } + }; + + $pool = new Pool($client, $requests($audience), [ + 'concurrency' => config('federation.activitypub.delivery.concurrency'), + 'fulfilled' => function ($response, $index) { + }, + 'rejected' => function ($reason, $index) { + } + ]); + + $promise = $pool->promise(); + + $promise->wait(); + + } +}