1
0

UnfollowLegacyAccountMovePipeline.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <?php
  2. namespace App\Jobs\MovePipeline;
  3. use App\Util\ActivityPub\Helpers;
  4. use DateTime;
  5. use DB;
  6. use Exception;
  7. use Illuminate\Contracts\Queue\ShouldQueue;
  8. use Illuminate\Foundation\Queue\Queueable;
  9. use Illuminate\Queue\Middleware\ThrottlesExceptions;
  10. use Illuminate\Queue\Middleware\WithoutOverlapping;
  11. class UnfollowLegacyAccountMovePipeline implements ShouldQueue
  12. {
  13. use Queueable;
  14. public $target;
  15. public $activity;
  16. /**
  17. * The number of times the job may be attempted.
  18. *
  19. * @var int
  20. */
  21. public $tries = 6;
  22. /**
  23. * The maximum number of unhandled exceptions to allow before failing.
  24. *
  25. * @var int
  26. */
  27. public $maxExceptions = 3;
  28. /**
  29. * Create a new job instance.
  30. */
  31. public function __construct($target, $activity)
  32. {
  33. $this->target = $target;
  34. $this->activity = $activity;
  35. }
  36. /**
  37. * Get the middleware the job should pass through.
  38. *
  39. * @return array<int, object>
  40. */
  41. public function middleware(): array
  42. {
  43. return [
  44. new WithoutOverlapping('process-move-undo-legacy-followers:'.$this->target),
  45. (new ThrottlesExceptions(2, 5 * 60))->backoff(5),
  46. ];
  47. }
  48. /**
  49. * Determine the time at which the job should timeout.
  50. */
  51. public function retryUntil(): DateTime
  52. {
  53. return now()->addMinutes(5);
  54. }
  55. /**
  56. * Execute the job.
  57. */
  58. public function handle(): void
  59. {
  60. if (config('app.env') !== 'production' || (bool) config_cache('federation.activitypub.enabled') == false) {
  61. throw new Exception('Activitypub not enabled');
  62. }
  63. $target = $this->target;
  64. $actor = $this->activity;
  65. $targetAccount = Helpers::profileFetch($target);
  66. $actorAccount = Helpers::profileFetch($actor);
  67. if (! $targetAccount || ! $actorAccount) {
  68. throw new Exception('Invalid move accounts');
  69. }
  70. $version = config('pixelfed.version');
  71. $appUrl = config('app.url');
  72. $userAgent = "(Pixelfed/{$version}; +{$appUrl})";
  73. $addlHeaders = [
  74. 'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
  75. 'User-Agent' => $userAgent,
  76. ];
  77. $targetInbox = $actorAccount['sharedInbox'] ?? $actorAccount['inbox_url'];
  78. $targetPid = $actorAccount['id'];
  79. DB::table('followers')
  80. ->join('profiles', 'followers.profile_id', '=', 'profiles.id')
  81. ->where('followers.following_id', $actorAccount['id'])
  82. ->whereNotNull('profiles.user_id')
  83. ->whereNull('profiles.deleted_at')
  84. ->select('profiles.id', 'profiles.user_id', 'profiles.username', 'profiles.private_key', 'profiles.status')
  85. ->chunkById(100, function ($followers) use ($actor, $targetInbox, $targetPid) {
  86. foreach ($followers as $follower) {
  87. if (! $follower->id || ! $follower->private_key || ! $follower->username || ! $follower->user_id || $follower->status === 'delete') {
  88. continue;
  89. }
  90. MoveSendUndoFollowPipeline::dispatch($follower, $targetInbox, $targetPid, $actor)->onQueue('move');
  91. }
  92. }, 'id');
  93. }
  94. }