diff --git a/app/Http/Controllers/InteractionController.php b/app/Http/Controllers/InteractionController.php new file mode 100644 index 0000000..a7d1b16 --- /dev/null +++ b/app/Http/Controllers/InteractionController.php @@ -0,0 +1,76 @@ +validate([ + 'content' => 'nullable|string|max:1000', + 'stars' => 'nullable|integer|min:1|max:5', + ]); + + if (!$request->filled('content') && !$request->filled('stars')) { + throw ValidationException::withMessages([ + 'content' => ['Provide a comment (content) and/or a rating (stars).'], + ]); + } + + $model = $this->getModel($type, $id); + if (!$model) { + return response()->json(['message' => 'Item not found'], 404); + } + + $comment = null; + if ($request->filled('content')) { + $comment = $model->comments()->create([ + 'user_id' => auth()->id(), + 'content' => $data['content'], + ])->load('user'); + } + + $rating = null; + if ($request->filled('stars')) { + $rating = $model->ratings()->updateOrCreate( + ['user_id' => auth()->id()], + ['stars' => $data['stars']] + ); + } + + $model = $model->fresh(); + + return response()->json([ + 'message' => 'Interaction saved successfully', + 'comment' => $comment, + 'your_rating' => $rating?->stars, + 'average_rating' => $model->average_rating, + 'ratings_count' => $model->ratings_count, + 'comments_count' => $model->comments_count, + ]); + } + + private function getModel($type, $id) + { + // media, music and playlist all support comments + ratings. + $models = [ + 'music' => \App\Models\Music::class, + 'media' => \App\Models\Media::class, + 'playlist' => \App\Models\MusicPlaylist::class, + ]; + + $class = $models[$type] ?? null; + + return $class ? $class::find($id) : null; + } +} diff --git a/app/Http/Controllers/MediaController.php b/app/Http/Controllers/MediaController.php index 8d9a4e3..a83f179 100644 --- a/app/Http/Controllers/MediaController.php +++ b/app/Http/Controllers/MediaController.php @@ -666,26 +666,27 @@ public function destroy($id) return response()->json(['message' => 'Media deleted']); } - // SAVE media + // SAVE media — uses the shared saved_items system (HasSaves), same as /saves/*. public function toggleSaveMedia($id) { - $user = auth()->user(); + $media = Media::findOrFail($id); - if ($user->savedMedia()->where('media_id', $id)->exists()) { - // already saved → unsave - $user->savedMedia()->detach($id); - return response()->json(['message' => 'Unsaved!']); - } else { - // not saved → save - $user->savedMedia()->attach($id); - return response()->json(['message' => 'Saved!']); - } + $media->toggleSaveStatus(); + + return response()->json([ + 'message' => $media->is_saved ? 'Saved!' : 'Unsaved!', + 'is_saved' => $media->is_saved, + 'saved_count' => $media->saved_count, + ]); } - // GET saved + // GET saved — media the user saved via saved_items. public function saved() { - return auth()->user()->savedMedia()->with(['image','detailImage','categories', 'subCategories', 'myNote' , 'tags'])->get(); + return Media::whereHas('saves', fn ($q) => $q->where('user_id', auth()->id())) + ->with(['image','detailImage','categories', 'subCategories', 'myNote' , 'tags']) + ->latest() + ->get(); } // RECORD a play for the current user (feeds popular + recently played). diff --git a/app/Models/Media.php b/app/Models/Media.php index e548f7d..3646547 100644 --- a/app/Models/Media.php +++ b/app/Models/Media.php @@ -89,14 +89,6 @@ public function getUrlAttribute() return $this->external_url; } - - - public function getIsSavedAttribute() - { - if (!auth()->check()) return false; - - return $this->savedBy() - ->where('user_id', auth()->id()) - ->exists(); - } + // is_saved / saved_count come from the HasSaves trait (saved_items table), + // so the /saves/* endpoints and the media list/show all agree. } diff --git a/app/Models/MusicPlaylist.php b/app/Models/MusicPlaylist.php index 4a5bcc3..796c3d5 100644 --- a/app/Models/MusicPlaylist.php +++ b/app/Models/MusicPlaylist.php @@ -9,9 +9,10 @@ use App\Traits\HasComments; // Add this use App\Traits\HasLikes; use App\Traits\HasSaves; +use App\Traits\HasRatings; class MusicPlaylist extends Model { - use HasComments, HasLikes, HasSaves; + use HasComments, HasLikes, HasSaves, HasRatings; protected $table = 'music_playlists'; protected $fillable = [ diff --git a/routes/api.php b/routes/api.php index 5205588..5a70530 100644 --- a/routes/api.php +++ b/routes/api.php @@ -31,6 +31,7 @@ use App\Http\Controllers\MusicSubcategoryController; use App\Http\Controllers\SaveController; use App\Http\Controllers\LikeController; +use App\Http\Controllers\InteractionController; Route::get('/test-hash', function() { $plain = 'amnk1380'; @@ -312,6 +313,9 @@ }); + // Combined comment + like in one request (music / media / playlist) + Route::post('interactions/{type}/{id}', [InteractionController::class, 'store']); + // Like routes (only for music and media) Route::prefix('likes')->group(function () { Route::post('/like', [LikeController::class, 'like']);