diff --git a/app/Http/Controllers/AP/APActorController.php b/app/Http/Controllers/AP/APActorController.php index 2364167..c4a0db5 100644 --- a/app/Http/Controllers/AP/APActorController.php +++ b/app/Http/Controllers/AP/APActorController.php @@ -2,11 +2,14 @@ namespace App\Http\Controllers\AP; -use App\Http\Controllers\Controller; -use Illuminate\Http\Request; - use App\Models\User; use App\Models\Actor; +use App\Models\Activity; + +use Illuminate\Http\Request; +use App\Http\Controllers\Controller; + +use App\Types\TypeOrderedCollection; class APActorController extends Controller { @@ -16,4 +19,38 @@ class APActorController extends Controller $response = Actor::build_response ($actor->first ()); return response ()->json ($response)->header ("Content-Type", "application/activity+json"); } + + public function followers (User $user) + { + $actor_id = '"' . str_replace ("/", "\/", $user->actor->actor_id) . '"'; + $followers = Activity::where ("type", "Follow")->where ("object", $actor_id); + $ordered_collection = new TypeOrderedCollection (); + $ordered_collection->collection = $followers->get ()->pluck ("actor")->toArray (); + $ordered_collection->url = route ("ap.followers", $user->name); + $ordered_collection->page_size = 10; + + if (request ()->has ("page")) { + $page = request ()->input ("page"); + return response ()->json ($ordered_collection->build_response_for_page ($page))->header ("Content-Type", "application/activity+json"); + } + + return response ()->json ($ordered_collection->build_response_main ())->header ("Content-Type", "application/activity+json"); + } + + public function following (User $user) + { + $actor_id = '"' . str_replace ("/", "\/", $user->actor->actor_id) . '"'; + $following = Activity::where ("type", "Follow")->where ("actor", $actor_id); + $ordered_collection = new TypeOrderedCollection (); + $ordered_collection->collection = $following->get ()->pluck ("object")->toArray (); + $ordered_collection->url = route ("ap.following", $user->name); + $ordered_collection->page_size = 10; + + if (request ()->has ("page")) { + $page = request ()->input ("page"); + return response ()->json ($ordered_collection->build_response_for_page ($page))->header ("Content-Type", "application/activity+json"); + } + + return response ()->json ($ordered_collection->build_response_main ())->header ("Content-Type", "application/activity+json"); + } } diff --git a/app/Models/User.php b/app/Models/User.php index b7755a8..f216969 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -72,4 +72,14 @@ class User extends Authenticatable { return $this->hasOne (Actor::class); } + + public function mutual_friends () + { + $actor_id = '"' . str_replace ("/", "\/", $this->actor->actor_id) . '"'; + + $followers = Activity::where ("type", "Follow")->where ("object", $actor_id)->get (); + $following = Activity::where ("type", "Follow")->where ("actor", $actor_id)->get (); + + return $followers->intersect ($following); + } } diff --git a/app/Types/TypeOrderedCollection.php b/app/Types/TypeOrderedCollection.php new file mode 100644 index 0000000..01ffd25 --- /dev/null +++ b/app/Types/TypeOrderedCollection.php @@ -0,0 +1,49 @@ +collection) || !isset ($this->url)) { + return []; + } + + $total_items = count ($this->collection); + $total_pages = ceil ($total_items / $this->page_size); + + return [ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => $this->url, + "type" => "OrderedCollection", + "totalItems" => $total_items, + "first" => $this->url . "?page=1", + "last" => $this->url . "?page=" . $total_pages, + ]; + } + + public function build_response_for_page ($page) + { + $total_items = count ($this->collection); + $total_pages = ceil ($total_items / $this->page_size); + if ($page > $total_pages) { + return []; + } + + $offset = ($page - 1) * $this->page_size; + $items = array_slice ($this->collection, $offset, $this->page_size); + + return [ + "@context" => "https://www.w3.org/ns/activitystreams", + "id" => $this->url . "?page=" . $page, + "type" => "OrderedCollectionPage", + "partOf" => $this->url, + "totalItems" => $total_items, + "orderedItems" => $items, + ]; + } +} diff --git a/resources/views/home_loggedin.blade.php b/resources/views/home_loggedin.blade.php index b5749f4..c461327 100644 --- a/resources/views/home_loggedin.blade.php +++ b/resources/views/home_loggedin.blade.php @@ -78,7 +78,7 @@

Your Friends:
- {{ auth ()->user ()->friends }} + {{ count (auth ()->user ()->mutual_friends ()) }}

diff --git a/resources/views/users/profile.blade.php b/resources/views/users/profile.blade.php index a9baab8..c59e9da 100644 --- a/resources/views/users/profile.blade.php +++ b/resources/views/users/profile.blade.php @@ -217,7 +217,7 @@

- {{ $user->name }} has {{ $user->friends }} friends. + {{ $user->name }} has {{ count ($user->mutual_friends ()) }} friends.

diff --git a/routes/api.php b/routes/api.php index 08aa043..ba32acc 100644 --- a/routes/api.php +++ b/routes/api.php @@ -15,6 +15,8 @@ Route::get ("/.well-known/webfinger", [ APWebfingerController::class, "webfinger Route::prefix ("/ap/v1")->group (function () { Route::post ("/user/{user:name}/inbox", [ APInboxController::class, "inbox" ])->name ("ap.inbox"); Route::post ("/user/{user:name}/outbox", [ APOutboxController::class, "outbox" ])->name ("ap.outbox"); + Route::get ("/user/{user:name}/followers", [ APActorController::class, "followers" ])->name ("ap.followers"); + Route::get ("/user/{user:name}/following", [ APActorController::class, "following" ])->name ("ap.following"); Route::get ("/user/{user:name}", [ APActorController::class, "user" ])->name ("ap.user"); Route::post ("/inbox", [ APInstanceInboxController::class, "inbox" ])->name ("ap.inbox");