1
0

FollowerController.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\{
  4. Follower,
  5. FollowRequest,
  6. Profile,
  7. UserFilter
  8. };
  9. use Auth, Cache;
  10. use Illuminate\Http\Request;
  11. use App\Jobs\FollowPipeline\FollowPipeline;
  12. use App\Util\ActivityPub\Helpers;
  13. use App\Services\FollowerService;
  14. class FollowerController extends Controller
  15. {
  16. public function __construct()
  17. {
  18. $this->middleware('auth');
  19. }
  20. public function store(Request $request)
  21. {
  22. $this->validate($request, [
  23. 'item' => 'required|string',
  24. 'force' => 'nullable|boolean',
  25. ]);
  26. $force = (bool) $request->input('force', true);
  27. $item = (int) $request->input('item');
  28. $url = $this->handleFollowRequest($item, $force);
  29. if($request->wantsJson() == true) {
  30. return response()->json(200);
  31. } else {
  32. return redirect($url);
  33. }
  34. }
  35. protected function handleFollowRequest($item, $force)
  36. {
  37. $user = Auth::user()->profile;
  38. $target = Profile::where('id', '!=', $user->id)->whereNull('status')->findOrFail($item);
  39. $private = (bool) $target->is_private;
  40. $remote = (bool) $target->domain;
  41. $blocked = UserFilter::whereUserId($target->id)
  42. ->whereFilterType('block')
  43. ->whereFilterableId($user->id)
  44. ->whereFilterableType('App\Profile')
  45. ->exists();
  46. if($blocked == true) {
  47. abort(400, 'You cannot follow this user.');
  48. }
  49. $isFollowing = Follower::whereProfileId($user->id)->whereFollowingId($target->id)->exists();
  50. if($private == true && $isFollowing == 0) {
  51. if($user->following()->count() >= Follower::MAX_FOLLOWING) {
  52. abort(400, 'You cannot follow more than ' . Follower::MAX_FOLLOWING . ' accounts');
  53. }
  54. if($user->following()->where('followers.created_at', '>', now()->subHour())->count() >= Follower::FOLLOW_PER_HOUR) {
  55. abort(400, 'You can only follow ' . Follower::FOLLOW_PER_HOUR . ' users per hour');
  56. }
  57. $follow = FollowRequest::firstOrCreate([
  58. 'follower_id' => $user->id,
  59. 'following_id' => $target->id
  60. ]);
  61. if($remote == true && config('federation.activitypub.remoteFollow') == true) {
  62. $this->sendFollow($user, $target);
  63. }
  64. FollowerService::add($user->id, $target->id);
  65. } elseif ($private == false && $isFollowing == 0) {
  66. if($user->following()->count() >= Follower::MAX_FOLLOWING) {
  67. abort(400, 'You cannot follow more than ' . Follower::MAX_FOLLOWING . ' accounts');
  68. }
  69. if($user->following()->where('followers.created_at', '>', now()->subHour())->count() >= Follower::FOLLOW_PER_HOUR) {
  70. abort(400, 'You can only follow ' . Follower::FOLLOW_PER_HOUR . ' users per hour');
  71. }
  72. $follower = new Follower();
  73. $follower->profile_id = $user->id;
  74. $follower->following_id = $target->id;
  75. $follower->save();
  76. if($remote == true && config('federation.activitypub.remoteFollow') == true) {
  77. $this->sendFollow($user, $target);
  78. }
  79. FollowerService::add($user->id, $target->id);
  80. FollowPipeline::dispatch($follower);
  81. } else {
  82. if($force == true) {
  83. $request = FollowRequest::whereFollowerId($user->id)->whereFollowingId($target->id)->exists();
  84. $follower = Follower::whereProfileId($user->id)->whereFollowingId($target->id)->exists();
  85. if($remote == true && $request && !$follower) {
  86. $this->sendFollow($user, $target);
  87. }
  88. if($remote == true && $follower) {
  89. $this->sendUndoFollow($user, $target);
  90. }
  91. Follower::whereProfileId($user->id)
  92. ->whereFollowingId($target->id)
  93. ->delete();
  94. FollowerService::remove($user->id, $target->id);
  95. }
  96. }
  97. Cache::forget('profile:following:'.$target->id);
  98. Cache::forget('profile:followers:'.$target->id);
  99. Cache::forget('profile:following:'.$user->id);
  100. Cache::forget('profile:followers:'.$user->id);
  101. Cache::forget('api:local:exp:rec:'.$user->id);
  102. Cache::forget('user:account:id:'.$target->user_id);
  103. Cache::forget('user:account:id:'.$user->user_id);
  104. Cache::forget('px:profile:followers-v1.3:'.$user->id);
  105. Cache::forget('px:profile:followers-v1.3:'.$target->id);
  106. Cache::forget('px:profile:following-v1.3:'.$user->id);
  107. Cache::forget('px:profile:following-v1.3:'.$target->id);
  108. Cache::forget('profile:follower_count:'.$target->id);
  109. Cache::forget('profile:follower_count:'.$user->id);
  110. Cache::forget('profile:following_count:'.$target->id);
  111. Cache::forget('profile:following_count:'.$user->id);
  112. return $target->url();
  113. }
  114. public function sendFollow($user, $target)
  115. {
  116. if($target->domain == null || $user->domain != null) {
  117. return;
  118. }
  119. $payload = [
  120. '@context' => 'https://www.w3.org/ns/activitystreams',
  121. 'id' => $user->permalink('#follow/'.$target->id),
  122. 'type' => 'Follow',
  123. 'actor' => $user->permalink(),
  124. 'object' => $target->permalink()
  125. ];
  126. $inbox = $target->sharedInbox ?? $target->inbox_url;
  127. Helpers::sendSignedObject($user, $inbox, $payload);
  128. }
  129. public function sendUndoFollow($user, $target)
  130. {
  131. if($target->domain == null || $user->domain != null) {
  132. return;
  133. }
  134. $payload = [
  135. '@context' => 'https://www.w3.org/ns/activitystreams',
  136. 'id' => $user->permalink('#follow/'.$target->id.'/undo'),
  137. 'type' => 'Undo',
  138. 'actor' => $user->permalink(),
  139. 'object' => [
  140. 'id' => $user->permalink('#follows/'.$target->id),
  141. 'actor' => $user->permalink(),
  142. 'object' => $target->permalink(),
  143. 'type' => 'Follow'
  144. ]
  145. ];
  146. $inbox = $target->sharedInbox ?? $target->inbox_url;
  147. Helpers::sendSignedObject($user, $inbox, $payload);
  148. }
  149. }