Преглед на файлове

Update SharePipeline, add Undo->Announce support

Daniel Supernault преди 4 години
родител
ревизия
c8e40e0fd3

+ 9 - 7
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);

+ 2 - 6
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);
 

+ 8 - 4
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;

+ 118 - 0
app/Jobs/SharePipeline/UndoSharePipeline.php

@@ -0,0 +1,118 @@
+<?php
+
+namespace App\Jobs\SharePipeline;
+
+use Cache, Log;
+use Illuminate\Support\Facades\Redis;
+use App\{Status, Notification};
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+use League\Fractal;
+use League\Fractal\Serializer\ArraySerializer;
+use App\Transformer\ActivityPub\Verb\UndoAnnounce;
+use GuzzleHttp\{Pool, Client, Promise};
+use App\Util\ActivityPub\HttpSignature;
+use App\Services\StatusService;
+
+class UndoSharePipeline implements ShouldQueue
+{
+	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+	protected $status;
+	public $deleteWhenMissingModels = true;
+
+	public function __construct(Status $status)
+	{
+		$this->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();
+
+	}
+}