added supports for hashtags

This commit is contained in:
Ghostie 2025-01-05 14:38:36 -05:00
parent e0f7100e60
commit cc3fc9e7fa
8 changed files with 140 additions and 1 deletions

View File

@ -20,6 +20,19 @@ class ActionsPost
{ {
public static function process_content_and_attachments ($request) 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")); $processed_content = Str::markdown ($request->get ("content"));
$attachments = []; $attachments = [];
@ -44,6 +57,7 @@ class ActionsPost
"content" => $processed_content, "content" => $processed_content,
"attachments" => $attachments, "attachments" => $attachments,
"inReplyTo" => $request->inReplyTo ?? null, "inReplyTo" => $request->inReplyTo ?? null,
"tags" => $processed_tags
]; ];
} }
@ -81,6 +95,7 @@ class ActionsPost
"content" => $processed ["content"], "content" => $processed ["content"],
"attachments" => $processed ["attachments"], "attachments" => $processed ["attachments"],
"inReplyTo" => $processed ["inReplyTo"] ?? null, "inReplyTo" => $processed ["inReplyTo"] ?? null,
"tags" => $processed ["tags"] ?? null,
] ]
]); ]);
} }

View File

@ -10,6 +10,7 @@ use App\Models\Activity;
use App\Models\Instance; use App\Models\Instance;
use App\Models\Follow; use App\Models\Follow;
use App\Models\Like; use App\Models\Like;
use App\Models\Hashtag;
use App\Types\TypeActor; use App\Types\TypeActor;
use App\Types\TypeActivity; use App\Types\TypeActivity;
@ -260,6 +261,24 @@ class APOutboxController extends Controller
ActionsPost::create_attachments ($note, $request ["attachments"]); 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); $create_activity = TypeActivity::craft_create ($actor, $note);
$note->activity_id = $create_activity->id; $note->activity_id = $create_activity->id;

16
app/Models/Hashtag.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Hashtag extends Model
{
protected $fillable = [
"name"
];
public function get_notes () {
return $this->belongsToMany(Note::class, 'note_hashtag');
}
}

View File

@ -46,6 +46,11 @@ class Note extends Model
return $this->hasOne (Note::class, "note_id", "in_reply_to"); return $this->hasOne (Note::class, "note_id", "in_reply_to");
} }
public function get_hashtags ()
{
return $this->belongsToMany (Hashtag::class, "note_hashtag");
}
public function attachments () public function attachments ()
{ {
return $this->hasMany (NoteAttachment::class); return $this->hasMany (NoteAttachment::class);

View File

@ -3,6 +3,7 @@
namespace App\Types; namespace App\Types;
use App\Models\Note; use App\Models\Note;
use App\Models\Hashtag;
use App\Models\Actor; use App\Models\Actor;
use App\Models\Activity; use App\Models\Activity;
use App\Models\NoteAttachment; 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; return $response;
} }
@ -89,7 +100,7 @@ class TypeNote
foreach ($request ["attachment"] as $attachment) 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 // TODO: Store its type in the database
$attachment_url = $attachment ["url"]; $attachment_url = $attachment ["url"];
$exists = NoteAttachment::where ("url", $attachment_url)->first (); $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) public static function create_from_request ($request, Activity $activity, Actor $actor)

View File

@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('hashtags', function (Blueprint $table) {
$table->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');
}
};

View File

@ -79,6 +79,17 @@ else
</div> </div>
@endif @endif
@if ($post->get_hashtags ()->count () > 0)
<p>
<b>Tags:</b>
@foreach ($post->get_hashtags ()->get () as $hashtag)
<a href="#">
<span class="tag">{{ $hashtag->name }}</span>
</a>
@endforeach
</p>
@endif
<hr> <hr>
<p> <p>

View File

@ -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"); Route::delete ("/post/{note}", [ PostController::class, "delete" ])->name ("posts.delete")->middleware ("auth");
// other routes // 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 ("/search", [ HomeController::class, "search" ])->name ("search");
Route::get ("/requests", [ HomeController::class, "requests" ])->name ("requests")->middleware ("auth"); Route::get ("/requests", [ HomeController::class, "requests" ])->name ("requests")->middleware ("auth");
Route::post ("/requests", [ HomeController::class, "requests_accept" ])->middleware ("auth"); Route::post ("/requests", [ HomeController::class, "requests_accept" ])->middleware ("auth");