added like functionality
This commit is contained in:
parent
d32c81575f
commit
b65dedae06
@ -22,7 +22,7 @@ Notice that the styles were taken from [AnySpace](https://anyspace.3to.moe/about
|
||||
- [x] I cannot follow myself
|
||||
- [ ] Check when waiting for approval
|
||||
- [ ] Handle Rejection
|
||||
- [ ] Likes
|
||||
- [x] Likes
|
||||
- [ ] Comments
|
||||
|
||||
- [-] Social features
|
||||
@ -39,8 +39,8 @@ Notice that the styles were taken from [AnySpace](https://anyspace.3to.moe/about
|
||||
- [x] Remove friends
|
||||
- [x] Posts (everything should be federated)
|
||||
- [x] Create posts
|
||||
- [ ] Delete posts
|
||||
- [ ] Like posts
|
||||
- [x] Delete posts
|
||||
- [x] Like posts
|
||||
- [ ] Comment posts
|
||||
- [ ] Boost posts
|
||||
- [ ] Post tags
|
||||
|
@ -89,4 +89,25 @@ class ActionsPost
|
||||
|
||||
return ["success" => "Post created"];
|
||||
}
|
||||
|
||||
public static function like_post (Actor $actor, Note $note)
|
||||
{
|
||||
$client = new Client ();
|
||||
|
||||
try
|
||||
{
|
||||
$response = $client->post ($actor->outbox, [
|
||||
"json" => [
|
||||
"type" => "Like",
|
||||
"object" => $note->note_id,
|
||||
]
|
||||
]);
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
return ["error" => "Could not connect to server."];
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ use App\Models\User;
|
||||
use App\Models\Actor;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Follow;
|
||||
use App\Models\Note;
|
||||
use App\Models\Like;
|
||||
|
||||
use App\Types\TypeActor;
|
||||
use App\Types\TypeActivity;
|
||||
@ -32,14 +34,20 @@ class APInboxController extends Controller
|
||||
case "Undo":
|
||||
$this->handle_undo ($user, $request->all ());
|
||||
break;
|
||||
|
||||
case "Like":
|
||||
$this->handle_like ($user, $request->all ());
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::info ("APInboxController@index");
|
||||
Log::info ("Unknown type: " . $type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function handle_follow (User $user, $activity)
|
||||
{
|
||||
if (TypeActivity::activity_exists ($activity ["id"]))
|
||||
return response ()->json (["error" => "Activity already exists",], 409);
|
||||
|
||||
$actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]);
|
||||
|
||||
$target = TypeActor::actor_get_local ($activity ["object"]);
|
||||
@ -77,9 +85,6 @@ class APInboxController extends Controller
|
||||
|
||||
public function handle_undo (User $user, $activity)
|
||||
{
|
||||
if (TypeActivity::activity_exists ($activity ["id"]))
|
||||
return response ()->json (["error" => "Activity already exists",], 409);
|
||||
|
||||
$actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]);
|
||||
|
||||
$child_activity = $activity ["object"];
|
||||
@ -99,4 +104,36 @@ class APInboxController extends Controller
|
||||
// TODO: Should Undo create a new activity in database?
|
||||
return response ()->json (["success" => "Activity undone",], 200);
|
||||
}
|
||||
|
||||
public function handle_like (User $user, $activity)
|
||||
{
|
||||
$actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]);
|
||||
$note_id = $activity ["object"];
|
||||
$note = Note::where ("note_id", $note_id)->first ();
|
||||
if (!$note)
|
||||
{
|
||||
Log::info ("Note not found: " . $note_id);
|
||||
return response ()->json (["error" => "Note not found",], 404);
|
||||
}
|
||||
|
||||
// check like doesn't already exist
|
||||
$like_exists = $actor->liked_note ($note);
|
||||
if ($like_exists)
|
||||
return response ()->json (["error" => "Like already exists",], 409);
|
||||
|
||||
$activity ["activity_id"] = $activity ["id"];
|
||||
$activity_exists = TypeActivity::activity_exists ($activity ["id"]);
|
||||
if (!$activity_exists)
|
||||
$act = Activity::create ($activity);
|
||||
else
|
||||
$act = Activity::where ("activity_id", $activity ["id"])->first ();
|
||||
|
||||
$like = Like::create ([
|
||||
"activity_id" => $act->id,
|
||||
"actor_id" => $actor->id,
|
||||
"note_id" => $note->id,
|
||||
]);
|
||||
|
||||
return response ()->json (["success" => "Like created",], 200);
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,10 @@ class APOutboxController extends Controller
|
||||
return $this->handle_unfollow ($user, $request->get ("object"));
|
||||
break;
|
||||
|
||||
case "Like":
|
||||
return $this->handle_like ($user, $request->get ("object"));
|
||||
break;
|
||||
|
||||
case "Post":
|
||||
return $this->handle_post ($user, $request);
|
||||
break;
|
||||
@ -200,6 +204,37 @@ class APOutboxController extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
public function handle_like (User $user, $request)
|
||||
{
|
||||
$object = Note::where ("note_id", $request)->first ();
|
||||
if (!$object)
|
||||
return response ()->json ([ "error" => "object not found" ], 404);
|
||||
|
||||
$actor = $user->actor ()->first ();
|
||||
$already_liked = $actor->liked_note ($object);
|
||||
if ($already_liked)
|
||||
{
|
||||
// undo the like
|
||||
$like_activity = $already_liked->get_activity ()->first ();
|
||||
$undo_activity = TypeActivity::craft_undo ($like_activity, $actor);
|
||||
|
||||
$response = TypeActivity::post_activity ($undo_activity, $actor, $object->get_actor ()->first ());
|
||||
return [
|
||||
"success" => "unliked"
|
||||
];
|
||||
}
|
||||
|
||||
$like_activity = TypeActivity::craft_like ($actor, $object->note_id);
|
||||
$response = TypeActivity::post_activity ($like_activity, $actor, $object->get_actor ()->first ());
|
||||
|
||||
if ($response->getStatusCode () < 200 || $response->getStatusCode () >= 300)
|
||||
return response ()->json ([ "error" => "failed to post activity" ], 500);
|
||||
|
||||
return [
|
||||
"success" => "liked"
|
||||
];
|
||||
}
|
||||
|
||||
public function handle_post (User $user, $request)
|
||||
{
|
||||
$actor = $user->actor ()->first ();
|
||||
|
@ -70,6 +70,19 @@ class PostController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function like (Note $note)
|
||||
{
|
||||
if (!auth ()->check ())
|
||||
return back ()->with ("error", "You need to be logged in to like a post.");
|
||||
|
||||
$user = auth ()->user ();
|
||||
$actor = $user->actor ()->first ();
|
||||
|
||||
$response = ActionsPost::like_post ($actor, $note);
|
||||
|
||||
return back ()->with ("success", "Post liked successfully.");
|
||||
}
|
||||
|
||||
public function delete (Note $note)
|
||||
{
|
||||
$actor = auth ()->user ()->actor ()->first ();
|
||||
|
@ -76,4 +76,9 @@ class Actor extends Model
|
||||
|
||||
return $following && $followers;
|
||||
}
|
||||
|
||||
public function liked_note (Note $note)
|
||||
{
|
||||
return Like::where ("actor_id", $this->id)->where ("note_id", $note->id)->first ();
|
||||
}
|
||||
}
|
||||
|
29
app/Models/Like.php
Normal file
29
app/Models/Like.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Like extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
"activity_id",
|
||||
"note_id",
|
||||
"actor_id"
|
||||
];
|
||||
|
||||
public function get_activity ()
|
||||
{
|
||||
return $this->belongsTo (Activity::class, "activity_id");
|
||||
}
|
||||
|
||||
public function get_note ()
|
||||
{
|
||||
return $this->belongsTo (Note::class, "note_id");
|
||||
}
|
||||
|
||||
public function get_actor ()
|
||||
{
|
||||
return $this->belongsTo (Actor::class, "actor_id");
|
||||
}
|
||||
}
|
@ -30,6 +30,11 @@ class Note extends Model
|
||||
return $this->hasOne (Actor::class, "id", "actor_id");
|
||||
}
|
||||
|
||||
public function get_likes ()
|
||||
{
|
||||
return $this->hasMany (Like::class);
|
||||
}
|
||||
|
||||
public function attachments ()
|
||||
{
|
||||
return $this->hasMany (NoteAttachment::class);
|
||||
|
@ -53,7 +53,7 @@ class TypeActivity {
|
||||
$undo_activity->activity_id = env ("APP_URL") . "/activity/" . uniqid ();
|
||||
$undo_activity->type = "Undo";
|
||||
$undo_activity->actor = $self->actor_id;
|
||||
$undo_activity->object = $activity;
|
||||
$undo_activity->object = TypeActivity::craft_response ($activity);
|
||||
$undo_activity->save ();
|
||||
|
||||
return $undo_activity;
|
||||
@ -119,6 +119,18 @@ class TypeActivity {
|
||||
return $delete_activity;
|
||||
}
|
||||
|
||||
public static function craft_like (Actor $actor, $id)
|
||||
{
|
||||
$like_activity = new Activity ();
|
||||
$like_activity->activity_id = env ("APP_URL") . "/activity/" . uniqid ();
|
||||
$like_activity->type = "Like";
|
||||
$like_activity->actor = $actor->actor_id;
|
||||
$like_activity->object = $id;
|
||||
$like_activity->save ();
|
||||
|
||||
return $like_activity;
|
||||
}
|
||||
|
||||
public static function get_private_key (Actor $actor)
|
||||
{
|
||||
return openssl_get_privatekey ($actor->private_key);
|
||||
|
32
database/migrations/2025_01_04_184440_create_likes_table.php
Normal file
32
database/migrations/2025_01_04_184440_create_likes_table.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?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('likes', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->foreignId ("activity_id")->constrained ()->onDelete ("cascade");
|
||||
$table->foreignId ("note_id")->constrained ()->onDelete ("cascade");
|
||||
$table->foreignId ("actor_id")->constrained ()->onDelete ("cascade");
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('likes');
|
||||
}
|
||||
};
|
@ -31,6 +31,8 @@ else
|
||||
</b>
|
||||
</p>
|
||||
|
||||
<h4>{{ $post->summary }}</h4>
|
||||
|
||||
{!! $post->content !!}
|
||||
|
||||
<p>
|
||||
@ -42,6 +44,10 @@ else
|
||||
<br>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<span><b>Likes:</b> {{ $post->get_likes ()->count () }}</span>
|
||||
</p>
|
||||
|
||||
<a href="{{ route ('posts.show', [ 'note' => $post ]) }}">
|
||||
<button type="button">View</button>
|
||||
</a>
|
||||
|
@ -62,6 +62,17 @@
|
||||
|
||||
<br>
|
||||
|
||||
<div class="buttons">
|
||||
<form action="{{ route ('posts.like', [ 'note' => $note->id ]) }}" method="POST">
|
||||
@csrf
|
||||
<button type="submit">{{ auth ()->user ()->actor ()->first ()->liked_note ($note) ? "Undo Like" : "Like" }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<b>Likes</b>: {{ $note->get_likes ()->count () }}
|
||||
</p>
|
||||
|
||||
<div class="comments" id="comments">
|
||||
<div class="heading">
|
||||
<h4>Comments</h4>
|
||||
|
@ -31,6 +31,7 @@ Route::get ("/user/{user_name}", [ ProfileController::class, "show" ])->name ("u
|
||||
// posts routes
|
||||
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}/like", [ PostController::class, "like" ])->name ("posts.like")->middleware ("auth");
|
||||
Route::get ("/post/{note}", [ PostController::class, "show" ])->name ("posts.show");
|
||||
Route::delete ("/post/{note}", [ PostController::class, "delete" ])->name ("posts.delete")->middleware ("auth");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user