now posts can be boosted locally

This commit is contained in:
Ghostie 2025-01-06 21:45:01 -05:00
parent 132696b330
commit 61b272625b
11 changed files with 122 additions and 10 deletions

View File

@ -14,10 +14,14 @@
- [x] Likes - [x] Likes
- [x] Comments - [x] Comments
- [x] Boosts - [x] Boosts
- [ ] Local Boost - [x] Local Boost
- [x] Tags - [x] Tags
- [ ] Mentions
- [ ] Local mentions
- [ ] Private post
- [ ] Pinned Posts - [ ] Pinned Posts
- [ ] Nodeinfo - [ ] Nodeinfo
- [ ] Notifications
- [-] Social features - [-] Social features
- [x] Profile - [x] Profile
@ -37,7 +41,7 @@
- [x] Delete posts - [x] Delete posts
- [x] Like posts - [x] Like posts
- [x] Comment posts - [x] Comment posts
- [ ] Boost posts - [x] Boost posts
- [x] Post tags - [x] Post tags
- [ ] Blog - [ ] Blog
- [ ] Bulletin - [ ] Bulletin

View File

@ -127,4 +127,25 @@ class ActionsPost
return $response; return $response;
} }
public static function boost_post (Actor $actor, Note $note)
{
$client = new Client ();
try
{
$response = $client->post ($actor->outbox, [
"json" => [
"type" => "Boost",
"object" => $note->note_id,
]
]);
}
catch (\Exception $e)
{
return ["error" => "Could not connect to server: " . $e->getMessage ()];
}
return $response;
}
} }

View File

@ -4,6 +4,7 @@ namespace App\Http\Controllers\AP;
use App\Models\Note; use App\Models\Note;
use App\Models\NoteAttachment; use App\Models\NoteAttachment;
use App\Models\Announcement;
use App\Models\User; use App\Models\User;
use App\Models\Actor; use App\Models\Actor;
use App\Models\Activity; use App\Models\Activity;
@ -55,6 +56,10 @@ class APOutboxController extends Controller
return $this->handle_like ($user, $request->get ("object")); return $this->handle_like ($user, $request->get ("object"));
break; break;
case "Boost":
return $this->handle_boost ($user, $request->get ("object"));
break;
case "Post": case "Post":
return $this->handle_post ($user, $request); return $this->handle_post ($user, $request);
break; break;
@ -250,6 +255,46 @@ class APOutboxController extends Controller
]; ];
} }
public function handle_boost (User $user, $object)
{
$object = Note::where ("note_id", $object)->first ();
if (!$object)
return response ()->json ([ "error" => "object not found" ], 404);
$actor = $user->actor ()->first ();
$already_boosted = $actor->boosted_note ($object);
if ($already_boosted)
{
$boost_activity = $already_boosted->activity;
$undo_activity = TypeActivity::craft_undo ($boost_activity, $actor);
$response = TypeActivity::post_to_instances ($undo_activity, $actor);
$boost_exists = Announcement::where ("note_id", $object->id)
->where ("actor_id", $actor->id)
->first ();
if ($boost_exists)
$boost_exists->delete ();
return [
"success" => "unboosted"
];
}
$boost_activity = TypeActivity::craft_announce ($actor, $object->note_id);
$announcement = Announcement::create ([
"activity_id" => $boost_activity->id,
"actor_id" => $actor->id,
"note_id" => $object->id,
]);
$response = TypeActivity::post_to_instances ($boost_activity, $actor);
return [
"success" => "boosted"
];
}
public function handle_post (User $user, $request) public function handle_post (User $user, $request)
{ {
$actor = $user->actor ()->first (); $actor = $user->actor ()->first ();

View File

@ -93,12 +93,12 @@ class HomeController extends Controller
} }
} }
$local_users = User::where ("name", "like", "%$query%")->get (); $local_users = User::where ("name", "like", "%$query%")->orderBy ("created_at", "desc")->get ();
$actors = Actor::where ("name", "like", "%$query%")->orWhere ("preferredUsername", "like", "%$query%")->get (); $actors = Actor::where ("name", "like", "%$query%")->orWhere ("preferredUsername", "like", "%$query%")->orderBy ("created_at", "desc")->get ();
$users = $local_users->merge ($actors)->take (10); $users = $local_users->merge ($actors)->take (10);
$hashtags = Hashtag::withCount ("get_notes")->where ("name", "like", "%$query%")->orderBy ("get_notes_count", "desc")->take (16)->get ()->shuffle (); $hashtags = Hashtag::withCount ("get_notes")->where ("name", "like", "%$query%")->orderBy ("get_notes_count", "desc")->take (16)->get ()->shuffle ();
$posts = Note::where ("content", "like", "%$query%")->paginate (10); $posts = Note::where ("content", "like", "%$query%")->orderBy ("created_at", "desc")->paginate (10);
return view ("search", compact ("users", "hashtags", "posts")); return view ("search", compact ("users", "hashtags", "posts"));
} }

View File

@ -83,6 +83,19 @@ class PostController extends Controller
return back ()->with ("success", "Post liked successfully."); return back ()->with ("success", "Post liked successfully.");
} }
public function boost (Note $note)
{
if (!auth ()->check ())
return back ()->with ("error", "You need to be logged in to boost a post.");
$user = auth ()->user ();
$actor = $user->actor ()->first ();
$response = ActionsPost::boost_post ($actor, $note);
return back ()->with ("success", "Post boosted successfully.");
}
public function delete (Note $note) public function delete (Note $note)
{ {
$actor = auth ()->user ()->actor ()->first (); $actor = auth ()->user ()->actor ()->first ();

View File

@ -3,7 +3,7 @@
namespace App\Models; namespace App\Models;
use App\Models\User; use App\Models\User;
use App\Models\Activity; use App\Models\Announcement;
use App\Models\Note; use App\Models\Note;
use App\Types\TypeActor; use App\Types\TypeActor;
@ -86,4 +86,9 @@ class Actor extends Model
{ {
return Like::where ("actor_id", $this->id)->where ("note_id", $note->id)->first (); return Like::where ("actor_id", $this->id)->where ("note_id", $note->id)->first ();
} }
public function boosted_note (Note $note)
{
return Announcement::where ("actor_id", $this->id)->where ("note_id", $note->id)->first ();
}
} }

View File

@ -36,6 +36,11 @@ class Note extends Model
return $this->hasMany (Like::class); return $this->hasMany (Like::class);
} }
public function get_boosts ()
{
return $this->hasMany (Announcement::class);
}
public function get_replies () public function get_replies ()
{ {
return $this->hasMany (Note::class, "in_reply_to", "note_id"); return $this->hasMany (Note::class, "in_reply_to", "note_id");

View File

@ -133,6 +133,18 @@ class TypeActivity {
return $like_activity; return $like_activity;
} }
public static function craft_announce (Actor $actor, $id)
{
$announce_activity = new Activity ();
$announce_activity->activity_id = env ("APP_URL") . "/activity/" . uniqid ();
$announce_activity->type = "Announce";
$announce_activity->actor = $actor->actor_id;
$announce_activity->object = $id;
$announce_activity->save ();
return $announce_activity;
}
public static function get_private_key (Actor $actor) public static function get_private_key (Actor $actor)
{ {
return openssl_get_privatekey ($actor->private_key); return openssl_get_privatekey ($actor->private_key);

View File

@ -118,7 +118,7 @@ class TypeNote
foreach ($attachments as $attachment) foreach ($attachments as $attachment)
$attachment->delete (); $attachment->delete ();
if ($request ["attachment"]) if (isset ($request ["attachment"]) && $request ["attachment"])
{ {
foreach ($request ["attachment"] as $attachment) foreach ($request ["attachment"] as $attachment)
@ -135,7 +135,7 @@ class TypeNote
} }
} }
if ($request ["tag"]) if (isset ($request ["tag"]) && $request ["tag"])
{ {
foreach ($request ["tag"] as $tag) foreach ($request ["tag"] as $tag)
{ {

View File

@ -70,16 +70,22 @@
<br> <br>
@auth @auth
<div class="buttons"> <div class="buttons" style="display: flex; gap: 10px;">
<form action="{{ route ('posts.like', [ 'note' => $note->id ]) }}" method="POST"> <form action="{{ route ('posts.like', [ 'note' => $note->id ]) }}" method="POST">
@csrf @csrf
<button type="submit">{{ auth ()->user ()->actor ()->first ()->liked_note ($note) ? "Undo Like" : "Like" }}</button> <button type="submit">{{ auth ()->user ()->actor ()->first ()->liked_note ($note) ? "Undo Like" : "Like" }}</button>
</form> </form>
<form action="{{ route ('posts.boost', [ 'note' => $note->id ]) }}" method="POST">
@csrf
<button type="submit">{{ auth ()->user ()->actor ()->first ()->boosted_note ($note) ? "Unboost" : "Boost" }}</button>
</form>
</div> </div>
@endauth @endauth
<p> <p>
<b>Likes</b>: {{ $note->get_likes ()->count () }} <b>Likes</b>: {{ $note->get_likes ()->count () }}<br>
<b>Boosts</b>: {{ $note->get_boosts ()->count () }}
</p> </p>
<div class="comments" id="comments"> <div class="comments" id="comments">

View File

@ -33,6 +33,7 @@ Route::middleware ("update_online")->group (function () {
Route::get ("/post/{note}/edit", [ PostController::class, "edit" ])->name ("posts.edit")->middleware ("auth"); Route::get ("/post/{note}/edit", [ PostController::class, "edit" ])->name ("posts.edit")->middleware ("auth");
Route::post ("/post/{note}/edit", [ PostController::class, "update" ])->middleware ("auth"); Route::post ("/post/{note}/edit", [ PostController::class, "update" ])->middleware ("auth");
Route::post ("/post/{note}/like", [ PostController::class, "like" ])->name ("posts.like")->middleware ("auth"); Route::post ("/post/{note}/like", [ PostController::class, "like" ])->name ("posts.like")->middleware ("auth");
Route::post ("/post/{note}/boost", [ PostController::class, "boost" ])->name ("posts.boost")->middleware ("auth");
Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.show"); Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.show");
Route::delete ("/post/{note}", [ PostController::class, "delete" ])->name ("posts.delete")->middleware ("auth"); Route::delete ("/post/{note}", [ PostController::class, "delete" ])->name ("posts.delete")->middleware ("auth");