From ce7d38fc76d2cd29d8a691fac4447843148185c7 Mon Sep 17 00:00:00 2001 From: vionar3 Date: Thu, 17 Jul 2025 14:26:59 +0700 Subject: [PATCH] final chapter after sidang --- .../Controllers/API/ProgressController.php | 303 +++++++++++------- .../Controllers/API/UploadAudioController.php | 25 +- app/Http/Controllers/API/UserControler.php | 19 +- app/Models/Latihan.php | 6 +- app/Models/Progress.php | 11 +- app/Models/SubMateri.php | 5 + app/Models/User.php | 5 + ...ove_recorded_audio_from_progress_table.php | 30 ++ ...8_add_recorded_audio_to_progress_table.php | 30 ++ ...ngajar_nilai_status_from_latihan_table.php | 30 ++ ...24_164247_add_fields_to_progress_table.php | 30 ++ routes/api.php | 11 +- 12 files changed, 364 insertions(+), 141 deletions(-) create mode 100644 database/migrations/2025_06_23_161503_remove_recorded_audio_from_progress_table.php create mode 100644 database/migrations/2025_06_23_161958_add_recorded_audio_to_progress_table.php create mode 100644 database/migrations/2025_06_24_163828_remove_feedback_pengajar_nilai_status_from_latihan_table.php create mode 100644 database/migrations/2025_06_24_164247_add_fields_to_progress_table.php diff --git a/app/Http/Controllers/API/ProgressController.php b/app/Http/Controllers/API/ProgressController.php index 29563af..9b193b2 100644 --- a/app/Http/Controllers/API/ProgressController.php +++ b/app/Http/Controllers/API/ProgressController.php @@ -13,6 +13,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use App\Helpers\ResponseFormatter; +use Illuminate\Support\Facades\DB; class ProgressController extends Controller { @@ -139,150 +140,218 @@ public function getProgressPercentageById(Request $request, $user_id) // Ambil semua submateri yang ada di sistem $totalSubmateri = SubMateri::count(); // Menghitung semua submateri yang ada - $completedSubmateri = Progress::where('user_id', $user->id) - ->where('status', 'selesai') - ->count(); // Menghitung submateri yang statusnya selesai + + // Ambil progres terbaru untuk setiap submateri berdasarkan user_id dan submateri_id + $completedSubmateriQuery = Progress::where('user_id', $user->id) + ->where('status', 'selesai') // Hanya yang selesai + ->orderBy('updated_at', 'desc') // Mengurutkan berdasarkan updated_at + ->get(); + + // Filter hanya progres terbaru untuk setiap submateri + $completedSubmateri = $completedSubmateriQuery->unique('sub_materi_id'); + + // Menghitung jumlah submateri yang telah selesai (terbaru) + $completedCount = $completedSubmateri->count(); // Menghitung persentase progres - $progressPercentage = ($totalSubmateri > 0) ? ($completedSubmateri / $totalSubmateri) * 100 : 0; + $progressPercentage = ($totalSubmateri > 0) ? ($completedCount / $totalSubmateri) * 100 : 0; // Return hasil persentase progres return response()->json([ 'user_id' => $user->id, 'nama_lengkap' => $user->nama_lengkap, 'total_submateri' => $totalSubmateri, - 'completed_submateri' => $completedSubmateri, + 'completed_submateri' => $completedCount, 'progress_percentage' => $progressPercentage ]); } -public function saveRecordedAudioName(Request $request, $id_latihan) - { - // Validasi data yang masuk - $request->validate([ - 'recorded_audio' => 'required|string', // Nama file audio yang disimpan - ]); - - // Temukan latihan berdasarkan ID (tanpa memeriksa user_id) - $latihan = Latihan::find($id_latihan); - - // Jika latihan ditemukan, simpan nama file rekaman ke kolom recorder_audio - if ($latihan) { - $latihan->recorder_audio = $request->recorded_audio; - $latihan->status = 'benar'; // Status latihan diubah menjadi selesai - $latihan->save(); - - return response()->json([ - 'message' => 'Rekaman berhasil disimpan!', - 'latihan' => $latihan, - ], 200); - } else { - return response()->json([ - 'message' => 'Latihan tidak ditemukan.', - ], 404); - } - } - - // API untuk menyimpan data progres latihan yang telah diselesaikan - public function saveProgress(Request $request, $submateri_id) - { - // Validasi data yang masuk - $request->validate([ - 'latihan_ids' => 'required|array', // Array dari ID latihan yang telah diselesaikan - 'latihan_ids.*' => 'exists:latihan,id', // Pastikan ID latihan ada di tabel latihan - ]); - - // Ambil user_id dari token yang digunakan (auth) - $user_id = Auth::id(); // Mendapatkan ID pengguna yang terautentikasi - - // Ambil data submateri untuk menampilkan title - $submateri = SubMateri::find($submateri_id); - if (!$submateri) { - return response()->json(['message' => 'SubMateri tidak ditemukan'], 404); - } - - // Menyimpan progres untuk setiap latihan yang diselesaikan oleh pengguna - $savedProgress = []; - foreach ($request->latihan_ids as $latihanId) { - // Temukan latihan berdasarkan ID - $latihan = Latihan::find($latihanId); - - // Jika latihan ditemukan, simpan ke tabel progres - if ($latihan) { - $progress = Progress::updateOrCreate( - [ - 'user_id' => $user_id, // Gunakan user_id dari token - 'sub_materi_id' => $submateri_id, - 'id_latihan' => $latihan->id, - ], - [ - 'status' => 'menunggu', // Status latihan diatur sebagai 'menunggu' setelah selesai - 'nilai' => $latihan->nilai, // Nilai latihan yang diberikan oleh pengajar - ] - ); - - // Menambahkan data progres yang baru disimpan untuk ditampilkan - $savedProgress[] = [ - 'user_id' => $user_id, - 'sub_materi_id' => $submateri_id, - 'submateri_title' => $submateri->title, // Menambahkan title dari submateri - 'status' => 'menunggu', - 'id_latihan' => $latihan->id, - 'potongan_ayat' => $latihan->potongan_ayat, - 'latin_text' => $latihan->latin_text, - 'recorder_audio' => $latihan->recorder_audio, - ]; - } - } - - return response()->json([ - 'message' => 'Progres latihan berhasil disimpan.', - 'progress' => $savedProgress, - ], 200); - } - - public function getHasilPenilaianByUserAndSubMateri($submateri_id) +public function updateStatusBatch(Request $request) { - // Ambil user_id dari token yang digunakan (auth) - $user_id = Auth::id(); // Mendapatkan ID pengguna yang terautentikasi + // Validasi input hanya array of ID + $request->validate([ + 'progress_ids' => 'required|array|min:1', + 'progress_ids.*' => 'integer|exists:progress,id', + ]); - // Ambil data berdasarkan user_id dan submateri_id - $progressData = Progress::with([ - 'latihan' => function ($query) { - $query->select('id', 'potongan_ayat', 'latin_text', 'recorder_audio', 'feedback_pengajar', 'status'); - } + $progressIds = $request->input('progress_ids'); + + // Update status menjadi 'menunggu' + Progress::whereIn('id', $progressIds)->update(['status' => 'menunggu']); + + return response()->json([ + 'message' => 'Status berhasil diubah menjadi menunggu.', + 'updated_ids' => $progressIds, + ]); +} + +public function progressMenunggu() +{ + $progressList = Progress::where('status', 'menunggu') + ->with([ + 'user:id,nama_lengkap', + 'subMateri:id,title,subtitle' ]) - ->where('user_id', $user_id) // Mengambil progress berdasarkan user_id yang terautentikasi - ->where('sub_materi_id', $submateri_id) // Mengambil progress berdasarkan submateri_id - ->get(['user_id', 'sub_materi_id', 'id_latihan', 'nilai']); // Pilih data yang diperlukan dari tabel progress + ->orderByDesc('created_at') + ->get(); - // Cek apakah ada data progress - if ($progressData->isEmpty()) { - return response()->json(['message' => 'Tidak ada data progres untuk pengguna ini pada submateri ini'], 404); - } + // Filter unik berdasarkan kombinasi user_id dan sub_materi_id + $filtered = $progressList->unique(fn($item) => $item->user_id . '-' . $item->sub_materi_id); - // Menyiapkan hasil yang akan dikembalikan - $results = $progressData->map(function ($progress) { + $data = $filtered->map(function ($progress) { return [ 'user_id' => $progress->user_id, 'sub_materi_id' => $progress->sub_materi_id, - 'id_latihan' => $progress->id_latihan, - 'nilai' => $progress->nilai, - 'potongan_ayat' => $progress->latihan->potongan_ayat, - 'latin_text' => $progress->latihan->latin_text, - 'recorder_audio' => $progress->latihan->recorder_audio, - 'feedback_pengajar' => $progress->latihan->feedback_pengajar, - 'status' => $progress->latihan->status, + 'nama_lengkap' => $progress->user->nama_lengkap, + 'title' => $progress->subMateri->title, + 'subtitle' => $progress->subMateri->subtitle, + 'status' => $progress->status, + 'created_at' => $progress->created_at, + // 'audio_file' => $progress->recorder_audio, ]; }); return response()->json([ - 'message' => 'Data hasil penilaian berhasil diambil.', - 'data' => $results - ], 200); + 'status' => true, + 'message' => 'Data progress santri dengan status menunggu', + 'data' => $data->values(), // reset index + ]); } +public function getProgressLatihanByUserAndSubmateri($user_id, $sub_materi_id) +{ + // Ambil data progress untuk user dan sub_materi_id yang diberikan + $progressList = Progress::where('user_id', $user_id) + ->where('sub_materi_id', $sub_materi_id) + ->with(['latihan', 'subMateri']) + ->orderBy('updated_at', 'desc') // Mengurutkan berdasarkan updated_at secara descending + ->limit(3) // Batasi hanya 3 data terbaru + ->get(); + + // Jika data progress kosong, kembalikan respons bahwa tidak ada data + if ($progressList->isEmpty()) { + return response()->json([ + 'status' => false, + 'message' => 'Tidak ada progress ditemukan', + 'data' => [] + ]); + } + + // Memetakan data progress untuk menambahkan status_validasi, feedback_pengajar, dan total_nilai + $data = $progressList->map(function ($item) { + return [ + 'id_progress' => $item->id, + 'title' => $item->subMateri->title ?? '', + 'subtitle' => $item->subMateri->subtitle ?? '', + 'id_latihan' => $item->id_latihan, + 'potongan_ayat' => $item->latihan->potongan_ayat ?? null, + 'latin_text' => $item->latihan->latin_text ?? null, + 'status' => $item->status, // Status dari progress + 'status_validasi' => $item->status_validasi, // status_validasi yang ditambahkan + 'feedback_pengajar' => $item->feedback_pengajar, // feedback_pengajar yang ditambahkan + 'nilai' => $item->nilai, // Nilai dari progress + 'recorder_audio' => $item->recorder_audio, + 'total_nilai' => $item->total_nilai, // total_nilai yang ditambahkan + ]; + }); + + // Mengembalikan data progress latihan yang berhasil diambil beserta informasi tambahan + return response()->json([ + 'status' => true, + 'message' => 'Data progress latihan berhasil diambil', + 'data' => $data + ]); +} + + + +public function savePenilaian(Request $request) +{ + // Validate the incoming request + $validatedData = $request->validate([ + 'id_progress' => 'required|array', + 'id_progress.*' => 'exists:progress,id', // Ensure the progress id exists + 'status_validasi' => 'required|array', + 'status_validasi.*' => 'in:benar,salah', // Status must be 'benar' or 'salah' + 'feedback_pengajar' => 'nullable|array', + 'feedback_pengajar.*' => 'nullable|string', + 'nilai' => 'required|array', + 'nilai.*' => 'integer|min:0|max:100', // Ensure each nilai is between 0 and 100 + ]); + + // Start the DB transaction + DB::beginTransaction(); + + try { + $totalNilaiSum = 0; + $nilaiCount = 0; + $updatedProgress = []; + + // Loop through each id_progress to update each record individually + foreach ($validatedData['id_progress'] as $index => $id_progress) { + // Find the Progress record + $progress = Progress::findOrFail($id_progress); + + // Update the progress record + $progress->status_validasi = $validatedData['status_validasi'][$index]; + $progress->feedback_pengajar = $validatedData['feedback_pengajar'][$index] ?? null; + $progress->nilai = $validatedData['nilai'][$index]; + $progress->save(); + + // Add nilai to the total sum for average calculation + $totalNilaiSum += $progress->nilai; + $nilaiCount++; + + // Collect updated progress data + $updatedProgress[] = [ + 'id_progress' => $progress->id, + 'status_validasi' => $progress->status_validasi, + 'feedback_pengajar' => $progress->feedback_pengajar, + 'nilai' => $progress->nilai, + ]; + } + + // Calculate the total_nilai (average) + $total_nilai = $nilaiCount > 0 ? $totalNilaiSum / $nilaiCount : 0; + + // Determine the status based on total_nilai + $status = ($total_nilai > 70) ? 'selesai' : 'gagal'; + + // Update total_nilai and status for each id_progress + foreach ($validatedData['id_progress'] as $index => $id_progress) { + $progress = Progress::findOrFail($id_progress); + $progress->total_nilai = $total_nilai; + $progress->status = $status; // Set the status based on the total_nilai + $progress->save(); + } + + // Commit the transaction + DB::commit(); + + // Return the updated progress data along with total_nilai and status + return response()->json([ + 'status' => true, + 'message' => 'Penilaian berhasil disimpan', + 'data' => [ + 'total_nilai' => $total_nilai, + 'status' => $status, // Include status in the response + 'progress' => $updatedProgress, + ] + ], 200); + + } catch (\Exception $e) { + // Rollback the transaction in case of error + DB::rollBack(); + return response()->json([ + 'status' => false, + 'message' => 'Terjadi kesalahan saat menyimpan penilaian', + 'error' => $e->getMessage(), + ], 500); + } +} + + } diff --git a/app/Http/Controllers/API/UploadAudioController.php b/app/Http/Controllers/API/UploadAudioController.php index 2b68c46..881a43c 100644 --- a/app/Http/Controllers/API/UploadAudioController.php +++ b/app/Http/Controllers/API/UploadAudioController.php @@ -4,27 +4,40 @@ use App\Http\Controllers\Controller; use Illuminate\Http\Request; +use App\Models\Progress; class UploadAudioController extends Controller { - public function uploadAudio(Request $request) + public function uploadAudio(Request $request) { - print($request->file('recorded_audio')); // Validasi file $request->validate([ - // 'recorded_audio' => 'required|mimes:m4a,mp3,wav|max:10240', // Batasi ukuran file (misalnya 10MB) - 'recorded_audio' => 'required|mimes:m4a,mp3,wav', // Batasi ukuran file (misalnya 10MB) + 'recorded_audio' => 'required|max:10240', // Batasi ukuran file (misalnya 10MB) + 'sub_materi_id' => 'required|exists:sub_materi,id', // Validasi sub_materi_id + 'id_latihan' => 'required|exists:latihan,id', // Validasi id_latihan ]); + // Mendapatkan user_id dari autentikasi token + $user_id = auth()->user()->id; + // Mendapatkan file dari request $file = $request->file('recorded_audio'); // Menyimpan file di disk public $path = $file->store('audio_files', 'public'); // Menyimpan di folder `storage/app/public/audio_files` + // Menyimpan data ke tabel Progress + $progress = Progress::create([ + 'user_id' => $user_id, + 'sub_materi_id' => $request->sub_materi_id, + 'id_latihan' => $request->id_latihan, + 'recorder_audio' => $path, // Simpan path file audio + ]); + return response()->json([ - 'message' => 'File berhasil diupload!', - 'file_path' => $path + 'message' => 'File berhasil diupload dan data progress tersimpan!', + 'file_path' => $path, + 'progress' => $progress, ], 200); } } diff --git a/app/Http/Controllers/API/UserControler.php b/app/Http/Controllers/API/UserControler.php index 33f0d38..db9a99e 100644 --- a/app/Http/Controllers/API/UserControler.php +++ b/app/Http/Controllers/API/UserControler.php @@ -121,6 +121,7 @@ public function loginWithTelp(Request $request) 'access_token' => $tokenResult, 'token_type' => 'Bearer', 'user' => [ + 'id' => $user->id, 'peran' => $user->peran // Ensure 'peran' is included here ] ], 'Authenticated'); @@ -496,22 +497,23 @@ public function getUserProgres(Request $request) $progresData = Progress::where('user_id', $santri->id) ->where('status', 'selesai') // Menghitung submateri yang sudah selesai ->with('submateri') // Load data submateri yang terkait - ->get(); + ->orderBy('updated_at', 'desc') // Ambil yang terakhir berdasarkan updated_at + ->first(); // Ambil hanya satu data yang terbaru (progres terakhir) - // Hitung jumlah submateri yang selesai - $completedSubmateriCount = $progresData->count(); // Menghitung jumlah data progres yang selesai - - // Hanya tampilkan santri yang telah menyelesaikan submateri - if ($completedSubmateriCount > 0) { + // Cek jika progres ada dan sudah selesai + if ($progresData) { return [ 'user_id' => $santri->id, 'nama_lengkap' => $santri->nama_lengkap, 'no_telp_wali' => $santri->no_telp_wali, - 'completed_submateri' => $completedSubmateriCount, // Jumlah submateri yang telah selesai + 'completed_submateri' => 1, // Hanya tampilkan yang sudah selesai + 'status' => $progresData->status, + 'nilai' => $progresData->nilai, + 'updated_at' => $progresData->updated_at, ]; } })->filter(function ($santri) { - return $santri !== null; // Filter out santri that haven't completed any submateri + return $santri !== null; // Filter out santri yang tidak ada progres yang selesai }); // Jika tidak ada santri yang menyelesaikan submateri @@ -539,4 +541,5 @@ public function getUserProgres(Request $request) + } diff --git a/app/Models/Latihan.php b/app/Models/Latihan.php index eedd6be..7edee02 100644 --- a/app/Models/Latihan.php +++ b/app/Models/Latihan.php @@ -20,9 +20,9 @@ class Latihan extends Model 'materi_description', 'correct_audio', 'recorder_audio', - 'feedback_pengajar', - 'nilai', - 'status', + // 'feedback_pengajar', + // 'nilai', + // 'status', ]; public function progress() diff --git a/app/Models/Progress.php b/app/Models/Progress.php index 7ee396c..ce6d9a7 100644 --- a/app/Models/Progress.php +++ b/app/Models/Progress.php @@ -9,18 +9,17 @@ class Progress extends Model { use HasFactory; - protected $fillable = ['user_id', 'sub_materi_id', 'status', 'nilai','id_latihan',]; + protected $fillable = ['user_id', 'sub_materi_id', 'status', 'nilai','id_latihan','recorder_audio','status_validasi','feedback_pengajar','total_nilai',]; // Relasi ke User - public function user() - { - return $this->belongsTo(User::class); - } + public function user() { + return $this->belongsTo(User::class, 'user_id'); +} // Relasi ke SubMateri public function subMateri() { - return $this->belongsTo(SubMateri::class); + return $this->belongsTo(SubMateri::class,'sub_materi_id'); } // Relasi ke Latihan diff --git a/app/Models/SubMateri.php b/app/Models/SubMateri.php index 300a0bc..96b9dec 100644 --- a/app/Models/SubMateri.php +++ b/app/Models/SubMateri.php @@ -30,4 +30,9 @@ public function kategori() { return $this->belongsTo(Kategori::class, 'id_kategori'); } + +public function progresses() +{ + return $this->hasMany(Progress::class); +} } diff --git a/app/Models/User.php b/app/Models/User.php index 668ff4f..96da50a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -49,4 +49,9 @@ class User extends Authenticatable protected $casts = [ 'email_verified_at' => 'datetime', ]; + + public function progresses() +{ + return $this->hasMany(Progress::class); +} } diff --git a/database/migrations/2025_06_23_161503_remove_recorded_audio_from_progress_table.php b/database/migrations/2025_06_23_161503_remove_recorded_audio_from_progress_table.php new file mode 100644 index 0000000..5e82832 --- /dev/null +++ b/database/migrations/2025_06_23_161503_remove_recorded_audio_from_progress_table.php @@ -0,0 +1,30 @@ +dropColumn('recorder_audio'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('latihan', function (Blueprint $table) { + // Menambahkan kembali kolom 'recorded_audio' jika rollback dilakukan + $table->string('recorder_audio')->nullable(); + }); + } +}; diff --git a/database/migrations/2025_06_23_161958_add_recorded_audio_to_progress_table.php b/database/migrations/2025_06_23_161958_add_recorded_audio_to_progress_table.php new file mode 100644 index 0000000..3eb028d --- /dev/null +++ b/database/migrations/2025_06_23_161958_add_recorded_audio_to_progress_table.php @@ -0,0 +1,30 @@ +string('recorder_audio')->nullable(); // Anda bisa menyesuaikan tipe data sesuai kebutuhan + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('progress', function (Blueprint $table) { + // Menghapus kolom 'recorded_audio' jika rollback dilakukan + $table->dropColumn('recorded_audio'); + }); + } +}; diff --git a/database/migrations/2025_06_24_163828_remove_feedback_pengajar_nilai_status_from_latihan_table.php b/database/migrations/2025_06_24_163828_remove_feedback_pengajar_nilai_status_from_latihan_table.php new file mode 100644 index 0000000..b6c5df4 --- /dev/null +++ b/database/migrations/2025_06_24_163828_remove_feedback_pengajar_nilai_status_from_latihan_table.php @@ -0,0 +1,30 @@ +dropColumn(['feedback_pengajar', 'nilai', 'status']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('latihan', function (Blueprint $table) { + $table->text('feedback_pengajar')->nullable(); + $table->integer('nilai')->nullable(); + $table->string('status', 20)->nullable(); + }); + } +}; diff --git a/database/migrations/2025_06_24_164247_add_fields_to_progress_table.php b/database/migrations/2025_06_24_164247_add_fields_to_progress_table.php new file mode 100644 index 0000000..5796362 --- /dev/null +++ b/database/migrations/2025_06_24_164247_add_fields_to_progress_table.php @@ -0,0 +1,30 @@ +enum('status_validasi', ['benar', 'salah'])->nullable(); // status_validasi field + $table->text('feedback_pengajar')->nullable(); // feedback_pengajar field + $table->integer('total_nilai')->nullable(); // total_nilai field + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('progress', function (Blueprint $table) { + $table->dropColumn(['status_validasi', 'feedback_pengajar', 'total_nilai']); + }); + } +}; diff --git a/routes/api.php b/routes/api.php index 774ca17..64d6afe 100644 --- a/routes/api.php +++ b/routes/api.php @@ -73,9 +73,18 @@ Route::get('/progres/presentase', [ProgressController::class, 'getProgressPercentage']); Route::get('/progres/{user_id}', [ProgressController::class, 'getProgressPercentageById']); Route::put('latihan/{id_latihan}/saverecord', [ProgressController::class, 'saveRecordedAudioName']); - Route::post('progress/{submateri_id}/save', [ProgressController::class, 'saveProgress']); + // Route::post('progress/{submateri_id}/save', [ProgressController::class, 'saveProgress']); Route::get('/hasil-penilaian/{submateri_id}', [ProgressController::class, 'getHasilPenilaianByUserAndSubMateri']); + // Route::post('/upload_audio', [UploadAudioController::class, 'uploadAudio']); Route::post('/upload_audio', [UploadAudioController::class, 'uploadAudio']); + Route::post('/update_progress_status', [ProgressController::class, 'updateStatusBatch']); + + Route::get('/progress/menunggu', [ProgressController::class, 'progressMenunggu']); + + Route::get('/progress/latihan/{user_id}/{sub_materi_id}', [ProgressController::class, 'getProgressLatihanByUserAndSubmateri']); + Route::post('save_penilaian', [ProgressController::class, 'savePenilaian']); + + });