diff --git a/app/Http/Controllers/ProfileMigrationController.php b/app/Http/Controllers/ProfileMigrationController.php index 9ac90531c..0ed134cf0 100644 --- a/app/Http/Controllers/ProfileMigrationController.php +++ b/app/Http/Controllers/ProfileMigrationController.php @@ -10,6 +10,7 @@ use App\Models\ProfileMigration; use App\Services\AccountService; use App\Services\WebfingerService; use App\Util\ActivityPub\Helpers; +use Cache; use Illuminate\Http\Request; use Illuminate\Support\Facades\Bus; @@ -61,6 +62,8 @@ class ProfileMigrationController extends Controller 'indexable' => false, ]); AccountService::del($user->profile_id); + Cache::forget('pfc:cached-user:wt:'.strtolower($user->profile->username)); + Cache::forget('pfc:cached-user:wot:'.strtolower($user->profile->username)); Bus::batch([ [ @@ -69,7 +72,7 @@ class ProfileMigrationController extends Controller [ new ProfileMigrationMoveFollowersPipeline($user->profile_id, $newAccount->id), ] - ])->onQueue('follow')->dispatch(); + ])->onQueue('move')->dispatch(); return redirect()->back()->with(['status' => 'Succesfully migrated account!']); } diff --git a/app/Jobs/MovePipeline/CleanupLegacyAccountMovePipeline.php b/app/Jobs/MovePipeline/CleanupLegacyAccountMovePipeline.php index d26ad5624..4ba27308f 100644 --- a/app/Jobs/MovePipeline/CleanupLegacyAccountMovePipeline.php +++ b/app/Jobs/MovePipeline/CleanupLegacyAccountMovePipeline.php @@ -95,6 +95,7 @@ class CleanupLegacyAccountMovePipeline implements ShouldQueue if ($oldProfile) { $oldProfile->moved_to_profile_id = $targetAccount['id']; + $oldProfile->followers_count = 0; $oldProfile->save(); AccountService::del($oldProfile->id); AccountService::del($targetAccount['id']); diff --git a/app/Jobs/MovePipeline/MoveMigrateFollowersPipeline.php b/app/Jobs/MovePipeline/MoveMigrateFollowersPipeline.php index 1cde3818e..7780f7685 100644 --- a/app/Jobs/MovePipeline/MoveMigrateFollowersPipeline.php +++ b/app/Jobs/MovePipeline/MoveMigrateFollowersPipeline.php @@ -3,6 +3,8 @@ namespace App\Jobs\MovePipeline; use App\Follower; +use App\Http\Controllers\FollowerController; +use App\Profile; use App\Util\ActivityPub\Helpers; use DateTime; use DB; @@ -112,8 +114,8 @@ class MoveMigrateFollowersPipeline implements ShouldQueue ->where('followers.following_id', $actorAccount['id']) ->whereNotNull('profiles.user_id') ->whereNull('profiles.deleted_at') - ->select('profiles.id', 'profiles.user_id', 'profiles.username', 'profiles.private_key', 'profiles.status') - ->chunkById(100, function ($followers) use ($targetInbox, $targetPid, $target) { + ->select('profiles.id', 'profiles.user_id', 'profiles.username', 'profiles.private_key', 'profiles.status', 'followers.local_profile') + ->chunkById(100, function ($followers) use ($targetInbox, $targetPid, $targetAccount) { foreach ($followers as $follower) { if (! $follower->private_key || ! $follower->username || ! $follower->user_id || $follower->status === 'delete') { continue; @@ -124,8 +126,14 @@ class MoveMigrateFollowersPipeline implements ShouldQueue 'following_id' => $targetPid, ]); - MoveSendFollowPipeline::dispatch($follower, $targetInbox, $targetPid, $target)->onQueue('follow'); + // If the remote user has migrated to a different instance, + // send a follow request for each local follower to the new + // instance + if ($targetInbox && $follower->local_profile) { + $followerProfile = Profile::find($follower->id); + (new FollowerController)->sendFollow($followerProfile, $targetAccount); + } } - }, 'id'); + }, 'profiles.id', 'id'); } } diff --git a/app/Jobs/MovePipeline/MoveSendFollowPipeline.php b/app/Jobs/MovePipeline/MoveSendFollowPipeline.php deleted file mode 100644 index 6d1cef5e1..000000000 --- a/app/Jobs/MovePipeline/MoveSendFollowPipeline.php +++ /dev/null @@ -1,113 +0,0 @@ - - */ - public function middleware(): array - { - return [ - new WithoutOverlapping('move-send-follow:'.$this->follower->id.':target:'.$this->target), - (new ThrottlesExceptions(2, 5 * 60))->backoff(5), - ]; - } - - /** - * Create a new job instance. - */ - public function __construct($follower, $targetInbox, $targetPid, $target) - { - $this->follower = $follower; - $this->targetInbox = $targetInbox; - $this->targetPid = $targetPid; - $this->target = $target; - } - - /** - * Execute the job. - */ - public function handle(): void - { - $follower = $this->follower; - $targetPid = $this->targetPid; - $targetInbox = $this->targetInbox; - $target = $this->target; - - if (! $follower->username || ! $follower->private_key) { - return; - } - - $permalink = 'https://'.config('pixelfed.domain.app').'/users/'.$follower->username; - $version = config('pixelfed.version'); - $appUrl = config('app.url'); - $userAgent = "(Pixelfed/{$version}; +{$appUrl})"; - $addlHeaders = [ - 'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', - 'User-Agent' => $userAgent, - ]; - - $activity = [ - '@context' => 'https://www.w3.org/ns/activitystreams', - 'type' => 'Follow', - 'actor' => $permalink, - 'object' => $target, - ]; - - $keyId = $permalink.'#main-key'; - $payload = json_encode($activity); - $headers = HttpSignature::signRaw($follower->private_key, $keyId, $targetInbox, $activity, $addlHeaders); - - $client = new Client([ - 'timeout' => config('federation.activitypub.delivery.timeout'), - ]); - - try { - $client->post($targetInbox, [ - 'curl' => [ - CURLOPT_HTTPHEADER => $headers, - CURLOPT_POSTFIELDS => $payload, - CURLOPT_HEADER => true, - ], - ]); - } catch (ClientException $e) { - - } - } -} diff --git a/app/Jobs/MovePipeline/UnfollowLegacyAccountMovePipeline.php b/app/Jobs/MovePipeline/UnfollowLegacyAccountMovePipeline.php index 47ed2aeb6..6f30b797e 100644 --- a/app/Jobs/MovePipeline/UnfollowLegacyAccountMovePipeline.php +++ b/app/Jobs/MovePipeline/UnfollowLegacyAccountMovePipeline.php @@ -106,6 +106,6 @@ class UnfollowLegacyAccountMovePipeline implements ShouldQueue MoveSendUndoFollowPipeline::dispatch($follower, $targetInbox, $targetPid, $actor)->onQueue('move'); } - }, 'id'); + }, 'profiles.id', 'id'); } } diff --git a/app/Jobs/ProfilePipeline/ProfileMigrationDeliverMoveActivityPipeline.php b/app/Jobs/ProfilePipeline/ProfileMigrationDeliverMoveActivityPipeline.php index 5fa27c33d..fd5882cab 100644 --- a/app/Jobs/ProfilePipeline/ProfileMigrationDeliverMoveActivityPipeline.php +++ b/app/Jobs/ProfilePipeline/ProfileMigrationDeliverMoveActivityPipeline.php @@ -14,6 +14,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Log; use League\Fractal; use League\Fractal\Serializer\ArraySerializer; @@ -128,8 +129,8 @@ class ProfileMigrationDeliverMoveActivityPipeline implements ShouldBeUniqueUntil $pool = new Pool($client, $requests($audience), [ 'concurrency' => config('federation.activitypub.delivery.concurrency'), 'fulfilled' => function ($response, $index) { - }, - 'rejected' => function ($reason, $index) { + }, 'rejected' => function ($reason, $index) { + Log::error($reason); }, ]); diff --git a/app/Jobs/ProfilePipeline/ProfileMigrationMoveFollowersPipeline.php b/app/Jobs/ProfilePipeline/ProfileMigrationMoveFollowersPipeline.php index c3d825ec9..b479cf871 100644 --- a/app/Jobs/ProfilePipeline/ProfileMigrationMoveFollowersPipeline.php +++ b/app/Jobs/ProfilePipeline/ProfileMigrationMoveFollowersPipeline.php @@ -3,6 +3,7 @@ namespace App\Jobs\ProfilePipeline; use App\Follower; +use App\Http\Controllers\FollowerController; use App\Profile; use App\Services\AccountService; use Illuminate\Bus\Batchable; @@ -13,6 +14,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\Middleware\WithoutOverlapping; use Illuminate\Queue\SerializesModels; +use Illuminate\Support\Facades\Log; class ProfileMigrationMoveFollowersPipeline implements ShouldBeUniqueUntilProcessing, ShouldQueue { @@ -81,12 +83,21 @@ class ProfileMigrationMoveFollowersPipeline implements ShouldBeUniqueUntilProces $ne->save(); $og->followers_count = 0; $og->save(); + + $targetInbox = $ne['sharedInbox'] ?? $ne['inbox_url']; foreach (Follower::whereFollowingId($this->oldPid)->lazyById(200, 'id') as $follower) { try { $follower->following_id = $this->newPid; $follower->save(); + + // If a local user has migrated to a different instance, send a + // follow request for each local follower to the new instance + if ($targetInbox && $follower->local_profile) { + $followerProfile = Profile::find($follower->profile_id); + (new FollowerController)->sendFollow($followerProfile, $ne); + } } catch (Exception $e) { - $follower->delete(); + Log::error($e); } } AccountService::del($this->oldPid); diff --git a/app/Transformer/ActivityPub/Verb/Move.php b/app/Transformer/ActivityPub/Verb/Move.php index 2460914be..aedb32e59 100644 --- a/app/Transformer/ActivityPub/Verb/Move.php +++ b/app/Transformer/ActivityPub/Verb/Move.php @@ -9,9 +9,9 @@ class Move extends Fractal\TransformerAbstract { public function transform(ProfileMigration $migration) { - $objUrl = $migration->target->permalink(); - $id = $migration->target->permalink('#moves/'.$migration->id); - $to = $migration->target->permalink('/followers'); + $objUrl = $migration->profile->permalink(); + $id = $migration->profile->permalink('#moves/'.$migration->id); + $to = $migration->profile->permalink('/followers'); return [ '@context' => 'https://www.w3.org/ns/activitystreams', @@ -19,7 +19,7 @@ class Move extends Fractal\TransformerAbstract 'actor' => $objUrl, 'type' => 'Move', 'object' => $objUrl, - 'target' => $migration->profile->permalink(), + 'target' => $migration->target->permalink(), 'to' => $to, ]; }