fix: music test apis

This commit is contained in:
2026-05-20 08:48:35 +03:30
parent 65db1bd5da
commit e446de79fd
9 changed files with 242 additions and 87 deletions
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Models\MusicPlaylist;
use App\Models\MusicCategory;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
@@ -18,22 +19,63 @@ public function index()
public function store(Request $request)
{
$data = $request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'image_id' => 'nullable|exists:images,id',
'order' => 'nullable|integer',
'is_active' => 'nullable|boolean',
]);
try {
$data = $request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'image_id' => 'nullable|exists:images,id',
'order' => 'nullable|integer',
'is_active' => 'nullable|boolean',
]);
$data['slug'] = Str::slug($data['name']);
// Check for duplicate name
$slug = Str::slug($data['name']);
$existingCategory = MusicCategory::where('slug', $slug)->first();
$category = MusicCategory::create($data);
if ($existingCategory) {
return response()->json([
'message' => 'A category with this name already exists',
'errors' => [
'name' => ['The category name "' . $data['name'] . '" is already taken. Please use a different name.']
]
], 422);
}
return response()->json([
'message' => 'Category created successfully',
'category' => $category->load('image')
], 201);
// Optional: Check for duplicate name with case-insensitive comparison
$existingName = MusicCategory::whereRaw('LOWER(name) = ?', [strtolower($data['name'])])->first();
if ($existingName) {
return response()->json([
'message' => 'A category with a similar name already exists',
'errors' => [
'name' => ['Category "' . $existingName->name . '" already exists. Please use a different name.']
]
], 422);
}
$data['slug'] = $slug;
$category = MusicCategory::create($data);
return response()->json([
'message' => 'Category created successfully',
'category' => $category->load('image')
], 201);
} catch (\Illuminate\Database\QueryException $e) {
// Handle database duplicate entry error (if unique constraint exists)
if ($e->errorInfo[1] == 1062) { // MySQL duplicate entry error code
return response()->json([
'message' => 'A category with this name already exists',
'errors' => [
'name' => ['The category name must be unique.']
]
], 422);
}
return response()->json([
'message' => 'An error occurred while creating the category',
'error' => $e->getMessage()
], 500);
}
}
public function show($id)
+152 -68
View File
@@ -8,7 +8,28 @@
use Illuminate\Support\Facades\Storage;
class MusicController extends Controller
{ public function getMusicByPlaylist($playlistId)
{
public function index()
{
$userId = auth()->id();
$music = Music::with(['image', 'playlist'])
->where('type', 'public')
->orWhere(function($query) use ($userId) {
$query->where('type', 'private')
->where('user_id', $userId);
})
->orderBy('created_at', 'desc')
->get();
return response()->json([
'data' => $music,
'total' => $music->count()
]);
}
public function getMusicByPlaylist($playlistId)
{
$playlist = MusicPlaylist::findOrFail($playlistId);
@@ -79,83 +100,146 @@ public function updateOrder(Request $request)
// ✅ Upload music
public function store(Request $request)
{
$data = $request->validate([
'title' => 'required|string|max:255',
'artist' => 'nullable|string|max:255',
'file' => 'required|mimes:mp3,wav,ogg|max:10240', // max 10MB
'type' => 'nullable|in:public,private',
'image_id' => 'nullable|exists:images,id',
]);
try {
$data = $request->validate([
'title' => 'required|string|max:255',
'artist' => 'nullable|string|max:255',
'file' => 'required|mimes:mp3,wav,ogg|max:20971520',
'type' => 'nullable|in:public,private',
'image_id' => 'nullable|exists:images,id',
'playlist_id' => 'nullable|exists:music_playlists,id',
'duration' => 'nullable|string|regex:/^(?:\d+:)?[0-5]?\d:[0-5]\d$/', // validates mm:ss or hh:mm:ss
]);
$path = $request->file('file')->store('music', 'public');
// Handle file upload
if (!$request->hasFile('file')) {
return response()->json([
'message' => 'No file was uploaded'
], 400);
}
$music = Music::create([
'user_id' => auth()->id(),
'title' => $data['title'],
'artist' => $data['artist'] ?? null,
'file_path' => $path,
'type' => $data['type'] ?? 'private',
'image_id' => $data['image_id'] ?? null,
]);
$file = $request->file('file');
return response()->json([
'message' => 'Music uploaded successfully',
'music' => $music->load('image'),
'url' => asset('storage/' . $path),
]);
// Validate file size
if ($file->getSize() > 20971520) {
return response()->json([
'message' => 'File size exceeds 10MB limit'
], 422);
}
$path = $file->store('music', 'public');
if (!$path) {
return response()->json([
'message' => 'Failed to store the file'
], 500);
}
$music = Music::create([
'user_id' => auth()->id(),
'title' => $data['title'],
'artist' => $data['artist'] ?? null,
'file_path' => $path,
'type' => $data['type'] ?? 'private',
'image_id' => $data['image_id'] ?? null,
'playlist_id' => $data['playlist_id'] ?? null,
'duration' => $data['duration'] ?? null, // Store as string
'order' => $this->getNextOrderInPlaylist($data['playlist_id'] ?? null),
'is_active' => true,
]);
return response()->json([
'message' => 'Music uploaded successfully',
'music' => $music->load(['image', 'playlist', 'tags']),
'url' => asset('storage/' . $path),
], 201);
} catch (\Illuminate\Validation\ValidationException $e) {
return response()->json([
'message' => 'Validation failed',
'errors' => $e->errors()
], 422);
} catch (\Exception $e) {
return response()->json([
'message' => 'An error occurred while uploading the music',
'error' => $e->getMessage()
], 500);
}
}
// ✅ Get all public + user private music
public function all()
// Helper method to get next order number in playlist
private function getNextOrderInPlaylist($playlistId)
{
$userId = auth()->id();
$music = Music::where('type', 'public')
->orWhere(function($query) use ($userId) {
$query->where('type', 'private')->where('user_id', $userId);
})
->get();
$music = Music::with('image') // eager load image
->where('type', 'public')
->orWhere(function($query) use ($userId) {
$query->where('type', 'private')->where('user_id', $userId);
})
->get();
return response()->json($music);
}
// ✅ Update music
public function update(Request $request, $id)
{
$music = Music::where('id', $id)->where('user_id', auth()->id())->firstOrFail();
$data = $request->validate([
'title' => 'nullable|string|max:255',
'artist' => 'nullable|string|max:255',
'type' => 'nullable|in:public,private',
'file' => 'nullable|mimes:mp3,wav,ogg|max:10240',
'image_id' => 'nullable|exists:images,id',
]);
if ($request->hasFile('file')) {
Storage::disk('public')->delete($music->file_path);
$path = $request->file('file')->store('music', 'public');
$music->file_path = $path;
if (!$playlistId) {
return 0;
}
$music->fill($data);
$music->save();
return response()->json([
'message' => 'Music updated successfully',
'music' => $music->load('image'),
'url' => asset('storage/' . $music->file_path),
]);
$maxOrder = Music::where('playlist_id', $playlistId)->max('order');
return ($maxOrder ?? -1) + 1;
}
// ✅ Update music with string duration
public function update(Request $request, $id)
{
try {
$music = Music::where('id', $id)->where('user_id', auth()->id())->firstOrFail();
$data = $request->validate([
'title' => 'nullable|string|max:255',
'artist' => 'nullable|string|max:255',
'type' => 'nullable|in:public,private',
'file' => 'nullable|mimes:mp3,wav,ogg|max:10240',
'image_id' => 'nullable|exists:images,id',
'playlist_id' => 'nullable|exists:music_playlists,id',
'duration' => 'nullable|string|regex:/^(?:\d+:)?[0-5]?\d:[0-5]\d$/',
'order' => 'nullable|integer',
'is_active' => 'nullable|boolean',
]);
if ($request->hasFile('file')) {
// Delete old file
Storage::disk('public')->delete($music->file_path);
$path = $request->file('file')->store('music', 'public');
$music->file_path = $path;
}
// Update only provided fields
$music->fill($data);
$music->save();
return response()->json([
'message' => 'Music updated successfully',
'music' => $music->load(['image', 'playlist', 'tags']),
'url' => asset('storage/' . $music->file_path),
]);
} catch (\Exception $e) {
return response()->json([
'message' => 'An error occurred while updating the music',
'error' => $e->getMessage()
], 500);
}
}
// ✅ Get all public + user private music
public function show($id)
{
$userId = auth()->id();
$music = Music::with(['image', 'playlist', 'tags'])
->where(function($query) use ($userId) {
$query->where('type', 'public')
->orWhere(function($q) use ($userId) {
$q->where('type', 'private')
->where('user_id', $userId);
});
})
->findOrFail($id);
return response()->json($music);
}
// ✅ Delete music
public function destroy($id)
{
+7 -1
View File
@@ -4,6 +4,9 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo; // ← Add this
use Illuminate\Database\Eloquent\Relations\BelongsToMany; // ← Add this
use Illuminate\Database\Eloquent\Relations\HasMany; // ← Add this
class Music extends Model
{
use HasFactory;
@@ -19,6 +22,9 @@ class Music extends Model
'order' => 'integer',
'is_active' => 'boolean',
];
protected $attributes = [
'type' => 'public', // Default value
];
// Relation to user (optional)
public function user()
{
@@ -30,7 +36,7 @@ public function playlist(): BelongsTo
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class, 'music_tag');
return $this->belongsToMany(Tag::class, 'music_tags');
}
protected $appends = ['url', 'image_url'];
+2 -1
View File
@@ -3,7 +3,8 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; // ← Add this
use Illuminate\Database\Eloquent\Relations\HasMany; // ← Add this
class MusicCategory extends Model
{
protected $table = 'music_categories';
+2 -1
View File
@@ -3,7 +3,8 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; // ← Add this
use Illuminate\Database\Eloquent\Relations\HasMany; // ← Add this
class MusicPlaylist extends Model
{
protected $table = 'music_playlists';
+2 -1
View File
@@ -3,7 +3,8 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; // ← Add this
use Illuminate\Database\Eloquent\Relations\HasMany; // ← Add this
class Tag extends Model
{
protected $fillable = ['name'];
+15
View File
@@ -1,3 +1,18 @@
<IfModule mod_php7.c>
php_value post_max_size 128M
php_value upload_max_filesize 128M
php_value max_execution_time 300
php_value max_input_time 300
</IfModule>
<IfModule mod_php8.c>
php_value post_max_size 128M
php_value upload_max_filesize 128M
php_value max_execution_time 300
php_value max_input_time 300
</IfModule>
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
+3
View File
@@ -0,0 +1,3 @@
<?php
phpinfo();
?>
+6 -4
View File
@@ -15,6 +15,8 @@
use App\Http\Controllers\ImageController;
use App\Http\Controllers\MusicController;
use App\Http\Controllers\MediaController;
use App\Http\Controllers\MusicCategoryController;
use App\Http\Controllers\MusicPlaylistController;
Route::get('/test-hash', function() {
$plain = 'amnk1380';
@@ -120,10 +122,10 @@
/// music
Route::post('/music', [MusicController::class, 'store']);
Route::get('/music/all', [MusicController::class, 'all']);
Route::put('/music/{id}', [MusicController::class, 'update']);
Route::delete('/music/{id}', [MusicController::class, 'destroy']);
// Route::post('/music', [MusicController::class, 'store']);
// Route::get('/music/all', [MusicController::class, 'all']);
// Route::put('/music/{id}', [MusicController::class, 'update']);
// Route::delete('/music/{id}', [MusicController::class, 'destroy']);
Route::get('/slider', [SliderController::class, 'index']); // list all sliders