From cc3fc9e7faf4724082ff58752c785805d88795c0 Mon Sep 17 00:00:00 2001 From: Ghostie Date: Sun, 5 Jan 2025 14:38:36 -0500 Subject: [PATCH] added supports for hashtags --- app/Actions/ActionsPost.php | 15 +++++++ .../Controllers/AP/APOutboxController.php | 19 +++++++++ app/Models/Hashtag.php | 16 ++++++++ app/Models/Note.php | 5 +++ app/Types/TypeNote.php | 33 ++++++++++++++- ...025_01_05_185958_create_hashtags_table.php | 40 +++++++++++++++++++ .../views/components/comment_block.blade.php | 11 +++++ routes/web.php | 2 + 8 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 app/Models/Hashtag.php create mode 100644 database/migrations/2025_01_05_185958_create_hashtags_table.php diff --git a/app/Actions/ActionsPost.php b/app/Actions/ActionsPost.php index 4dcef64..534a76b 100644 --- a/app/Actions/ActionsPost.php +++ b/app/Actions/ActionsPost.php @@ -20,6 +20,19 @@ class ActionsPost { public static function process_content_and_attachments ($request) { + preg_match_all ("/#\w+/", $request->get ("content"), $tag_matches); + $tags = $tag_matches [0]; + $processed_tags = []; + + foreach ($tags as $tag) + { + $processed_tags[] = [ + "type" => "Hashtag", + "name" => $tag, + "url" => route ("tags", ["tag" => $tag]) + ]; + } + $processed_content = Str::markdown ($request->get ("content")); $attachments = []; @@ -44,6 +57,7 @@ class ActionsPost "content" => $processed_content, "attachments" => $attachments, "inReplyTo" => $request->inReplyTo ?? null, + "tags" => $processed_tags ]; } @@ -81,6 +95,7 @@ class ActionsPost "content" => $processed ["content"], "attachments" => $processed ["attachments"], "inReplyTo" => $processed ["inReplyTo"] ?? null, + "tags" => $processed ["tags"] ?? null, ] ]); } diff --git a/app/Http/Controllers/AP/APOutboxController.php b/app/Http/Controllers/AP/APOutboxController.php index ea9d0c0..dc745ab 100644 --- a/app/Http/Controllers/AP/APOutboxController.php +++ b/app/Http/Controllers/AP/APOutboxController.php @@ -10,6 +10,7 @@ use App\Models\Activity; use App\Models\Instance; use App\Models\Follow; use App\Models\Like; +use App\Models\Hashtag; use App\Types\TypeActor; use App\Types\TypeActivity; @@ -260,6 +261,24 @@ class APOutboxController extends Controller ActionsPost::create_attachments ($note, $request ["attachments"]); } + if (isset ($request ["tags"])) + { + foreach ($request ["tags"] as $tag) + { + $tag_exists = Hashtag::where ("name", $tag ["name"])->first (); + if ($tag_exists) + { + $note->get_hashtags ()->attach ($tag_exists->id); + continue; + } + + $tag = Hashtag::create ([ + "name" => $tag ["name"] + ]); + $note->get_hashtags ()->attach ($tag->id); + } + } + $create_activity = TypeActivity::craft_create ($actor, $note); $note->activity_id = $create_activity->id; diff --git a/app/Models/Hashtag.php b/app/Models/Hashtag.php new file mode 100644 index 0000000..939a62e --- /dev/null +++ b/app/Models/Hashtag.php @@ -0,0 +1,16 @@ +belongsToMany(Note::class, 'note_hashtag'); + } +} diff --git a/app/Models/Note.php b/app/Models/Note.php index 9dc6ae8..d27ad9c 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -46,6 +46,11 @@ class Note extends Model return $this->hasOne (Note::class, "note_id", "in_reply_to"); } + public function get_hashtags () + { + return $this->belongsToMany (Hashtag::class, "note_hashtag"); + } + public function attachments () { return $this->hasMany (NoteAttachment::class); diff --git a/app/Types/TypeNote.php b/app/Types/TypeNote.php index 39184ef..536ddd8 100644 --- a/app/Types/TypeNote.php +++ b/app/Types/TypeNote.php @@ -3,6 +3,7 @@ namespace App\Types; use App\Models\Note; +use App\Models\Hashtag; use App\Models\Actor; use App\Models\Activity; use App\Models\NoteAttachment; @@ -43,6 +44,16 @@ class TypeNote ]; } + $tags = $note->get_hashtags ()->get (); + foreach ($tags as $tag) + { + $response ["tag"] [] = [ + "type" => "Hashtag", + "name" => $tag->name, + "url" => route ("tags", ["tag" => $tag->name]) + ]; + } + return $response; } @@ -89,7 +100,7 @@ class TypeNote foreach ($request ["attachment"] as $attachment) { - // TODO: Check if it's type and proceed based on that + // TODO: Check it's type and proceed based on that // TODO: Store its type in the database $attachment_url = $attachment ["url"]; $exists = NoteAttachment::where ("url", $attachment_url)->first (); @@ -100,6 +111,26 @@ class TypeNote ]); } } + + if ($request ["tag"]) + { + foreach ($request ["tag"] as $tag) + { + $tag_name = $tag ["name"]; + + $hashtag_exists = Hashtag::where ("name", $tag_name)->first (); + if ($hashtag_exists) + { + $note->get_hashtags ()->attach ($hashtag_exists->id); + continue; + } + + $hashtag = Hashtag::create ([ + "name" => $tag_name + ]); + $note->get_hashtags ()->attach ($hashtag->id); + } + } } public static function create_from_request ($request, Activity $activity, Actor $actor) diff --git a/database/migrations/2025_01_05_185958_create_hashtags_table.php b/database/migrations/2025_01_05_185958_create_hashtags_table.php new file mode 100644 index 0000000..30ed3f0 --- /dev/null +++ b/database/migrations/2025_01_05_185958_create_hashtags_table.php @@ -0,0 +1,40 @@ +id(); + + $table->string('name')->unique(); + + $table->timestamps(); + }); + + Schema::create('note_hashtag', function (Blueprint $table) { + $table->id (); + + $table->foreignId ('note_id')->constrained ()->onDelete ('cascade'); + $table->foreignId ('hashtag_id')->constrained ()->onDelete ('cascade'); + + $table->timestamps (); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('hashtags'); + Schema::dropIfExists('note_hashtag'); + } +}; diff --git a/resources/views/components/comment_block.blade.php b/resources/views/components/comment_block.blade.php index 094d802..213f93f 100644 --- a/resources/views/components/comment_block.blade.php +++ b/resources/views/components/comment_block.blade.php @@ -79,6 +79,17 @@ else @endif + @if ($post->get_hashtags ()->count () > 0) +

+ Tags: + @foreach ($post->get_hashtags ()->get () as $hashtag) + + {{ $hashtag->name }} + + @endforeach +

+ @endif +

diff --git a/routes/web.php b/routes/web.php index 6ef296a..15bdd97 100644 --- a/routes/web.php +++ b/routes/web.php @@ -36,6 +36,8 @@ Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.sho Route::delete ("/post/{note}", [ PostController::class, "delete" ])->name ("posts.delete")->middleware ("auth"); // other routes +Route::get ("/browse", [ HomeController::class, "browse" ])->name ("browse"); // TODO: This +Route::get ("/tags/{tag}", [ HomeController::class, "tag" ])->name ("tags"); // TODO: This Route::get ("/search", [ HomeController::class, "search" ])->name ("search"); Route::get ("/requests", [ HomeController::class, "requests" ])->name ("requests")->middleware ("auth"); Route::post ("/requests", [ HomeController::class, "requests_accept" ])->middleware ("auth");