diff --git a/README.md b/README.md index eea5099..e6c54c0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Notice that the styles were taken from [AnySpace](https://anyspace.3to.moe/about - [ ] Posts - [ ] Local posts should be federated - [ ] Remote posts should be fetched - - [ ] Follows + - [x] Follows - [ ] Likes - [ ] Comments diff --git a/app/Http/Controllers/AP/APInboxController.php b/app/Http/Controllers/AP/APInboxController.php index ab06aa3..b75605e 100644 --- a/app/Http/Controllers/AP/APInboxController.php +++ b/app/Http/Controllers/AP/APInboxController.php @@ -59,9 +59,6 @@ class APInboxController extends Controller "error" => "Error posting activity", ], 500); } - - $target->user->friends += 1; - $target->user->save (); } public function handle_undo (User $user, $activity) diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 71a17cb..5bab41e 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -2,6 +2,8 @@ namespace App\Http\Controllers; +use App\Types\TypeActor; + use App\Models\User; use Illuminate\Http\Request; @@ -13,4 +15,27 @@ class HomeController extends Controller return view ("home", compact ("latest_users")); } + + public function search () + { + $query = request ()->get ("query"); + + // check if the query is empty + if (empty ($query)) { + return redirect ()->route ("home"); + } + + // check if the search is a federated user + $user_handle = array_slice (explode ("@", $query), 1); + if (count ($user_handle) > 1) { + $username = $user_handle[0]; + $domain = $user_handle[1]; + + $actor = TypeActor::actor_exists_or_obtain_from_handle ($username, $domain); + if (!$actor) + return redirect ()->route ("home"); + + return redirect ()->route ("users.show", "@$actor->preferredUsername@$domain"); + } + } } diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 02450c7..193bc02 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -9,12 +9,27 @@ use Intervention\Image\ImageManager; use Intervention\Image\Drivers\Gd\Driver; use App\Models\User; +use App\Models\Actor; class ProfileController extends Controller { - public function show (User $user) + public function show ($user_name) { - return view ("users.profile", compact ("user")); + $actor = null; + $user = null; + + if (str_starts_with ($user_name, "@")) { + $actor = Actor::where ("local_actor_id", $user_name)->first (); + } + else + { + $user = User::where ("name", $user_name)->first (); + if (!$user) + return redirect ()->route ("home"); + $actor = $user->actor; + } + + return view ("users.profile", compact ("actor", "user")); } public function edit () diff --git a/app/Models/Actor.php b/app/Models/Actor.php index 2db52c0..753d999 100644 --- a/app/Models/Actor.php +++ b/app/Models/Actor.php @@ -14,6 +14,7 @@ class Actor extends Model "type", "actor_id", + "local_actor_id", "following", "followers", diff --git a/app/Types/TypeActor.php b/app/Types/TypeActor.php index 085f0d4..f420980 100644 --- a/app/Types/TypeActor.php +++ b/app/Types/TypeActor.php @@ -111,6 +111,7 @@ class TypeActor { // Use null coalescing operator `??` for safety $actor->actor_id = $request['id'] ?? ''; + $actor->local_actor_id = TypeActor::actor_build_private_id ($actor->actor_id) ?? ''; $actor->type = $request['type'] ?? ''; $actor->following = $request['following'] ?? ''; @@ -141,25 +142,21 @@ class TypeActor { public static function obtain_actor_info ($actor_id) { - $client = new Client (); - $parsed_url = parse_url ($actor_id); $url_instance = $parsed_url["scheme"] . "://" . $parsed_url["host"]; $url_path = explode ("/", $parsed_url["path"]); $actor_name = end ($url_path); - $well_known_url = $url_instance . "/.well-known/webfinger?resource=acct:" . $actor_name . "@" . $parsed_url["host"]; - $res = $client->get ($well_known_url); + $well_known = TypeActor::query_wellknown ($actor_name, $parsed_url ["host"]); - $response = json_decode ($res->getBody ()->getContents ()); - - foreach ($response->links as $link) + foreach ($well_known->links as $link) { if ($link->rel == "self") { + $client = new Client (); $res = $client->request ("GET", $link->href, [ "headers" => [ - "Accept" => "application/activity+json" + "Accept" => "application/json" ] ]); $actor = json_decode ($res->getBody ()->getContents (), true); @@ -172,6 +169,25 @@ class TypeActor { return null; } + public static function query_wellknown ($name, $domain) + { + $client = new Client (); + + $well_known_url = "https://" . $domain . "/.well-known/webfinger?resource=acct:" . $name . "@" . $domain; + + try { + $res = $client->get ($well_known_url, [ + "headers" => [ + "Accept" => "application/json" + ] + ]); + } catch (\Exception $e) { + return json_encode (["error" => "Actor not found"]); + } + + return json_decode ($res->getBody ()->getContents ()); + } + // some little functions public static function actor_exists ($actor_id) { @@ -190,6 +206,33 @@ class TypeActor { return $actor; } + public static function actor_exists_or_obtain_from_handle ($name, $domain) + { + $well_known = TypeActor::query_wellknown ($name, $domain); + if (!$well_known) + return null; + + foreach ($well_known->links as $link) + { + if ($link->rel == "self") + { + return TypeActor::actor_exists_or_obtain ($link->href); + } + } + + return null; + } + + public static function actor_build_private_id ($actor_id) + { + $parsed_url = parse_url ($actor_id); + $split_path = explode ("/", $parsed_url ["path"]); + $username = end ($split_path); + $domain = $parsed_url ["host"]; + + return "@" . $username . "@" . $domain; + } + public static function actor_get_local ($actor_id) { $actor = Actor::where ("actor_id", $actor_id)->first (); diff --git a/database/migrations/2024_12_27_002726_create_actors_table.php b/database/migrations/2024_12_27_002726_create_actors_table.php index fcc5a62..ed6057d 100644 --- a/database/migrations/2024_12_27_002726_create_actors_table.php +++ b/database/migrations/2024_12_27_002726_create_actors_table.php @@ -18,6 +18,7 @@ return new class extends Migration $table->string ("type")->nullable (); $table->string ("actor_id")->unique (); + $table->string ("local_actor_id")->unique ()->nullable (); $table->string ("following")->nullable (); $table->string ("followers")->nullable (); diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index cb25c75..93aa8e3 100644 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -15,7 +15,7 @@