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
|
- [x] I cannot follow myself
|
||||||
- [ ] Check when waiting for approval
|
- [ ] Check when waiting for approval
|
||||||
- [ ] Handle Rejection
|
- [ ] Handle Rejection
|
||||||
- [ ] Likes
|
- [x] Likes
|
||||||
- [ ] Comments
|
- [ ] Comments
|
||||||
|
|
||||||
- [-] Social features
|
- [-] Social features
|
||||||
@ -39,8 +39,8 @@ Notice that the styles were taken from [AnySpace](https://anyspace.3to.moe/about
|
|||||||
- [x] Remove friends
|
- [x] Remove friends
|
||||||
- [x] Posts (everything should be federated)
|
- [x] Posts (everything should be federated)
|
||||||
- [x] Create posts
|
- [x] Create posts
|
||||||
- [ ] Delete posts
|
- [x] Delete posts
|
||||||
- [ ] Like posts
|
- [x] Like posts
|
||||||
- [ ] Comment posts
|
- [ ] Comment posts
|
||||||
- [ ] Boost posts
|
- [ ] Boost posts
|
||||||
- [ ] Post tags
|
- [ ] Post tags
|
||||||
|
@ -89,4 +89,25 @@ class ActionsPost
|
|||||||
|
|
||||||
return ["success" => "Post created"];
|
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\Actor;
|
||||||
use App\Models\Activity;
|
use App\Models\Activity;
|
||||||
use App\Models\Follow;
|
use App\Models\Follow;
|
||||||
|
use App\Models\Note;
|
||||||
|
use App\Models\Like;
|
||||||
|
|
||||||
use App\Types\TypeActor;
|
use App\Types\TypeActor;
|
||||||
use App\Types\TypeActivity;
|
use App\Types\TypeActivity;
|
||||||
@ -32,14 +34,20 @@ class APInboxController extends Controller
|
|||||||
case "Undo":
|
case "Undo":
|
||||||
$this->handle_undo ($user, $request->all ());
|
$this->handle_undo ($user, $request->all ());
|
||||||
break;
|
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)
|
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"]);
|
$actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]);
|
||||||
|
|
||||||
$target = TypeActor::actor_get_local ($activity ["object"]);
|
$target = TypeActor::actor_get_local ($activity ["object"]);
|
||||||
@ -77,9 +85,6 @@ class APInboxController extends Controller
|
|||||||
|
|
||||||
public function handle_undo (User $user, $activity)
|
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"]);
|
$actor = TypeActor::actor_exists_or_obtain ($activity ["actor"]);
|
||||||
|
|
||||||
$child_activity = $activity ["object"];
|
$child_activity = $activity ["object"];
|
||||||
@ -99,4 +104,36 @@ class APInboxController extends Controller
|
|||||||
// TODO: Should Undo create a new activity in database?
|
// TODO: Should Undo create a new activity in database?
|
||||||
return response ()->json (["success" => "Activity undone",], 200);
|
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"));
|
return $this->handle_unfollow ($user, $request->get ("object"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "Like":
|
||||||
|
return $this->handle_like ($user, $request->get ("object"));
|
||||||
|
break;
|
||||||
|
|
||||||
case "Post":
|
case "Post":
|
||||||
return $this->handle_post ($user, $request);
|
return $this->handle_post ($user, $request);
|
||||||
break;
|
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)
|
public function handle_post (User $user, $request)
|
||||||
{
|
{
|
||||||
$actor = $user->actor ()->first ();
|
$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)
|
public function delete (Note $note)
|
||||||
{
|
{
|
||||||
$actor = auth ()->user ()->actor ()->first ();
|
$actor = auth ()->user ()->actor ()->first ();
|
||||||
|
@ -76,4 +76,9 @@ class Actor extends Model
|
|||||||
|
|
||||||
return $following && $followers;
|
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");
|
return $this->hasOne (Actor::class, "id", "actor_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_likes ()
|
||||||
|
{
|
||||||
|
return $this->hasMany (Like::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function attachments ()
|
public function attachments ()
|
||||||
{
|
{
|
||||||
return $this->hasMany (NoteAttachment::class);
|
return $this->hasMany (NoteAttachment::class);
|
||||||
|
@ -53,7 +53,7 @@ class TypeActivity {
|
|||||||
$undo_activity->activity_id = env ("APP_URL") . "/activity/" . uniqid ();
|
$undo_activity->activity_id = env ("APP_URL") . "/activity/" . uniqid ();
|
||||||
$undo_activity->type = "Undo";
|
$undo_activity->type = "Undo";
|
||||||
$undo_activity->actor = $self->actor_id;
|
$undo_activity->actor = $self->actor_id;
|
||||||
$undo_activity->object = $activity;
|
$undo_activity->object = TypeActivity::craft_response ($activity);
|
||||||
$undo_activity->save ();
|
$undo_activity->save ();
|
||||||
|
|
||||||
return $undo_activity;
|
return $undo_activity;
|
||||||
@ -119,6 +119,18 @@ class TypeActivity {
|
|||||||
return $delete_activity;
|
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)
|
public static function get_private_key (Actor $actor)
|
||||||
{
|
{
|
||||||
return openssl_get_privatekey ($actor->private_key);
|
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>
|
</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h4>{{ $post->summary }}</h4>
|
||||||
|
|
||||||
{!! $post->content !!}
|
{!! $post->content !!}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -42,6 +44,10 @@ else
|
|||||||
<br>
|
<br>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span><b>Likes:</b> {{ $post->get_likes ()->count () }}</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
<a href="{{ route ('posts.show', [ 'note' => $post ]) }}">
|
<a href="{{ route ('posts.show', [ 'note' => $post ]) }}">
|
||||||
<button type="button">View</button>
|
<button type="button">View</button>
|
||||||
</a>
|
</a>
|
||||||
|
@ -62,6 +62,17 @@
|
|||||||
|
|
||||||
<br>
|
<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="comments" id="comments">
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
<h4>Comments</h4>
|
<h4>Comments</h4>
|
||||||
|
@ -31,6 +31,7 @@ Route::get ("/user/{user_name}", [ ProfileController::class, "show" ])->name ("u
|
|||||||
// posts routes
|
// posts routes
|
||||||
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::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");
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user