diff --git a/TODO.md b/TODO.md index 59f571a..eb681d4 100644 --- a/TODO.md +++ b/TODO.md @@ -50,4 +50,5 @@ - [ ] Announcements - [ ] Fixes - - [ ] Fix that weird json encoding in the object field of an activity + - [x] Fix that weird json encoding in the object field of an activity + - [ ] The profile attachments are not working, they are not being federalised somehow (the interests thingy) diff --git a/app/Actions/ActionsActivity.php b/app/Actions/ActionsActivity.php new file mode 100644 index 0000000..6fda905 --- /dev/null +++ b/app/Actions/ActionsActivity.php @@ -0,0 +1,33 @@ + "Activity not found",]; + + $child_activity = Activity::where ("activity_id", $child_activity_id)->first (); + $child_activity->delete (); + + // TODO: Should Undo create a new activity in database? + return ["success" => "Activity undone",]; + } +} diff --git a/app/Http/Controllers/AP/APInboxController.php b/app/Http/Controllers/AP/APInboxController.php index 579c8df..6f4b1a4 100644 --- a/app/Http/Controllers/AP/APInboxController.php +++ b/app/Http/Controllers/AP/APInboxController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\AP; +use App\Actions\ActionsActivity; use App\Models\User; use App\Models\Actor; use App\Models\Activity; @@ -87,24 +88,7 @@ class APInboxController extends Controller public function handle_undo (User $user, $activity) { - $actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]); - - $child_activity = $activity ["object"]; - $child_activity_id = ""; - - if (is_array ($child_activity)) - $child_activity_id = $child_activity ["id"]; - else - $child_activity_id = $child_activity; - - if (!TypeActivity::activity_exists ($child_activity_id)) - return response ()->json (["error" => "Child activity doesn't exist",], 404); - - $child_activity = Activity::where ("activity_id", $child_activity_id)->first (); - $child_activity->delete (); - - // TODO: Should Undo create a new activity in database? - return response ()->json (["success" => "Activity undone",], 200); + return response ()->json (ActionsActivity::activity_undo ($activity)); } public function handle_like (User $user, $activity) diff --git a/app/Http/Controllers/AP/APInstanceInboxController.php b/app/Http/Controllers/AP/APInstanceInboxController.php index ad0ce25..9c1aff0 100644 --- a/app/Http/Controllers/AP/APInstanceInboxController.php +++ b/app/Http/Controllers/AP/APInstanceInboxController.php @@ -2,11 +2,13 @@ namespace App\Http\Controllers\AP; +use App\Actions\ActionsActivity; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use App\Models\Actor; use App\Models\Activity; +use App\Models\Announcement; use App\Types\TypeActor; use App\Types\TypeActivity; @@ -26,6 +28,14 @@ class APInstanceInboxController extends Controller switch ($activity_type) { + case "Announce": + return $this->handle_announce ($activity); + break; + + case "Undo": + return $this->handle_undo ($activity); + break; + case "Create": return $this->handle_create ($activity); break; @@ -47,6 +57,41 @@ class APInstanceInboxController extends Controller return response ()->json (["status" => "ok"]); } + public function handle_announce ($activity) + { + // we suppose an announce is always a note + $note_exists = TypeNote::note_exists ($activity ["object"]); + if (!$note_exists) + { + $note_exists = TypeNote::obtain_external ($activity ["object"]); + if (!$note_exists) + return response ()->json (["status" => "error"]); + } + + $announcement_exists = TypeActivity::activity_exists ($activity ["id"]); + if ($announcement_exists) + return response ()->json (["status" => "ok"]); + + $announcement_actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]); + if (!$announcement_actor) + return response ()->json (["status" => "error"]); + + $activity["activity_id"] = $activity["id"]; + $ann_act = Activity::create ($activity); + $announcement = Announcement::create ([ + "activity_id" => $ann_act->id, + "actor_id" => $announcement_actor->id, + "note_id" => $note_exists->id + ]); + + return response ()->json (["status" => "ok"]); + } + + public function handle_undo ($activity) + { + return response ()->json (ActionsActivity::activity_undo($activity)); + } + public function handle_create ($activity) { if (TypeActivity::activity_exists ($activity ["id"])) diff --git a/app/Models/Actor.php b/app/Models/Actor.php index 775c2b6..55fc673 100644 --- a/app/Models/Actor.php +++ b/app/Models/Actor.php @@ -53,9 +53,14 @@ class Actor extends Model return $this->belongsTo (User::class); } - public function posts () + public function get_posts () { - return $this->hasMany (Note::class, "actor_id")->orderBy ("created_at", "desc"); + $posts = $this->hasMany (Note::class, "actor_id")->orderBy ("created_at", "desc")->get (); + $announcements = $this->hasMany (Announcement::class, "actor_id")->orderBy ("created_at", "desc")->get (); + + $all = $posts->merge ($announcements)->sortByDesc ("created_at"); + + return $all; } public function create_from_user (User $user) diff --git a/app/Models/Announcement.php b/app/Models/Announcement.php new file mode 100644 index 0000000..38570b6 --- /dev/null +++ b/app/Models/Announcement.php @@ -0,0 +1,29 @@ +belongsTo(Activity::class); + } + + public function actor () + { + return $this->belongsTo(Actor::class); + } + + public function note () + { + return $this->belongsTo(Note::class); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 04cea8d..c4f1c3a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -148,7 +148,10 @@ class User extends Authenticatable } $notes = Note::whereIn ("actor_id", $friends_id)->orderBy ("created_at", "desc")->get (); + $announcements = Announcement::whereIn ("actor_id", $friends_id)->orderBy ("created_at", "desc")->get (); - return $notes; + $feed = $notes->merge ($announcements)->sortByDesc ("created_at"); + + return $feed; } } diff --git a/app/Types/TypeActor.php b/app/Types/TypeActor.php index 50739ec..85ec99d 100644 --- a/app/Types/TypeActor.php +++ b/app/Types/TypeActor.php @@ -96,6 +96,9 @@ class TypeActor { "url" => $actor->image ], + "published" => $actor->created_at, + "updated" => $actor->updated_at, + "publicKey" => [ "id" => $actor->actor_id . "#main-key", "owner" => $actor->actor_id, diff --git a/app/Types/TypeNote.php b/app/Types/TypeNote.php index 536ddd8..3de56c3 100644 --- a/app/Types/TypeNote.php +++ b/app/Types/TypeNote.php @@ -8,6 +8,8 @@ use App\Models\Actor; use App\Models\Activity; use App\Models\NoteAttachment; +use GuzzleHttp\Client; + use Illuminate\Support\Facades\Log; class TypeNote @@ -78,13 +80,30 @@ class TypeNote return $note; } - public static function update_from_request (Note $note, $request, Activity $activity, Actor $actor) + public static function update_from_request (Note $note, $request, Activity $activity = null, Actor $actor = null) { - $note->activity_id = $activity->id; - $note->actor_id = $actor->id; + if ($activity) + $note->activity_id = $activity->id; + + if ($actor) + $note->actor_id = $actor->id; + else + { + $actor = TypeActor::actor_exists ($request ["attributedTo"]); + if (!$actor) + { + $actor = TypeActor::obtain_actor_info($request ["attributedTo"]); + if (!$actor) + { + Log::error ("TypeNote::update_from_request: Could not obtain actor info."); + } + } + + $note->actor_id = $actor->id; + } $note->note_id = $request["id"] ?? null; - $note->in_reply_to = $request["inReplyTo"] ?? null; + // $note->in_reply_to = $request["inReplyTo"] ?? null; $note->summary = $request["summary"] ?? null; $note->url = $request["url"] ?? null; $note->attributedTo = $request["attributedTo"] ?? null; @@ -116,6 +135,9 @@ class TypeNote { foreach ($request ["tag"] as $tag) { + if ($tag ["type"] != "Hashtag") + continue; + $tag_name = $tag ["name"]; $hashtag_exists = Hashtag::where ("name", $tag_name)->first (); @@ -131,6 +153,17 @@ class TypeNote $note->get_hashtags ()->attach ($hashtag->id); } } + + if ($request ["inReplyTo"]) + { + $parent_exists = Note::where ("note_id", $request ["inReplyTo"])->first (); + if (!$parent_exists) + { + $parent = TypeNote::obtain_external ($request ["inReplyTo"]); + if ($parent) + $note->in_reply_to = $parent->note_id; + } + } } public static function create_from_request ($request, Activity $activity, Actor $actor) @@ -144,6 +177,36 @@ class TypeNote return $note; } + public static function obtain_external ($note_id) + { + $note = Note::where ("note_id", $note_id)->first (); + if ($note) + return $note; + + try { + $client = new Client (); + $res = $client->request ("GET", $note_id, [ + "headers" => [ + "Accept" => "application/activity+json" + ] + ]); + $body = $res->getBody ()->getContents (); + + $note = Note::create ([ + "note_id" => $note_id + ]); + TypeNote::update_from_request ($note, json_decode ($body, true)); + $note->save (); + } + catch (\Exception $e) + { + Log::error ("TypeNote::obtain_external: " . $e->getMessage ()); + return null; + } + + return $note; + } + // some little functions public static function note_exists ($note_id) { diff --git a/database/migrations/2025_01_06_013945_create_announcements_table.php b/database/migrations/2025_01_06_013945_create_announcements_table.php new file mode 100644 index 0000000..a9f4fe7 --- /dev/null +++ b/database/migrations/2025_01_06_013945_create_announcements_table.php @@ -0,0 +1,30 @@ +id(); + $table->foreignId ("activity_id")->constrained ()->onDelete ('cascade'); + $table->foreignId ('actor_id')->constrained ()->onDelete ('cascade'); + $table->foreignId ("note_id")->constrained ()->onDelete ('cascade'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('announcements'); + } +}; diff --git a/resources/views/browse.blade.php b/resources/views/browse.blade.php index c39eea3..bc54212 100644 --- a/resources/views/browse.blade.php +++ b/resources/views/browse.blade.php @@ -46,7 +46,7 @@
- +
- @if ($post->in_reply_to) + @if ($display_post->in_reply_to) In response to - this post + this post @endif -
- @foreach ($post->attachments as $attachment)
+ @foreach ($display_post->attachments as $attachment)
@endforeach
- {{ $actor->name }} has {{ count ($actor->posts) }} posts. + {{ $actor->name }} has {{ count ($actor->get_posts ()) }} posts.
@if (auth ()->user () && auth ()->user ()->is ($user)) @@ -314,8 +314,8 @@
{{ $reply->summary }}
@@ -79,7 +87,7 @@ elseTags: @foreach ($post->get_hashtags ()->get () as $hashtag) @@ -93,13 +101,13 @@ else
- Likes: {{ $post->get_likes ()->count () }} + Likes: {{ $display_post->get_likes ()->count () }}
- Replies: {{ $post->get_replies ()->count () }} + Replies: {{ $display_post->get_replies ()->count () }}
- + {{-- @if ($actor->user && auth ()->check () && auth ()->user ()->is ($actor->user)) diff --git a/resources/views/home_loggedin.blade.php b/resources/views/home_loggedin.blade.php index 77ebd42..6ad1b2e 100644 --- a/resources/views/home_loggedin.blade.php +++ b/resources/views/home_loggedin.blade.php @@ -139,7 +139,7 @@