FollowerController.php 5.4 KB

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