feat: API wali murid (Sanctum) + verifikasi admin
- Pasang laravel/sanctum, routes/api.php (prefix api/v1, 10 endpoint) - Migrasi: parent_name di students, parent_students (pivot wali↔anak), parent_devices (token FCM), permission parents-verify - Auth wali: registrasi NISN+HP (auto-verify jika HP cocok data siswa, pending jika tidak) + login token Sanctum - Endpoint: me, logout, students, link anak, violations, sp-letters, notifications, register device - Halaman admin Verifikasi Wali (approve/reject) + menu sidebar - Sync kesiswaan: tarik data orang tua (student_parents) ke students - 8 feature test baru (ParentApiTest) — total suite 39 test hijau
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
<?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('personal_access_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('tokenable');
|
||||
$table->text('name');
|
||||
$table->string('token', 64)->unique();
|
||||
$table->text('abilities')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable()->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('personal_access_tokens');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('students', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('students', 'parent_name')) {
|
||||
$table->string('parent_name', 150)->nullable()->after('parent_phone');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('students', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('students', 'parent_name')) {
|
||||
$table->dropColumn('parent_name');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('parent_students', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->foreignId('student_id')->constrained('students')->cascadeOnDelete();
|
||||
// relation: father | mother | guardian (sesuai student_parents di kesiswaan)
|
||||
$table->string('relation', 20)->nullable();
|
||||
// status: pending (menunggu verifikasi admin) | active | rejected
|
||||
$table->string('status', 20)->default('pending')->index();
|
||||
$table->timestamp('verified_at')->nullable();
|
||||
$table->unsignedBigInteger('verified_by')->nullable();
|
||||
$table->string('rejection_reason', 255)->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'student_id']);
|
||||
$table->index(['student_id', 'status']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('parent_students');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('parent_devices', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('platform', 20)->default('android'); // android | ios
|
||||
$table->string('fcm_token', 255)->nullable();
|
||||
$table->string('device_name', 100)->nullable();
|
||||
$table->timestamp('last_active_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'fcm_token']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('parent_devices');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = now();
|
||||
|
||||
$id = DB::table('permissions')->insertGetId([
|
||||
'key' => 'parents-verify',
|
||||
'group' => 'wali',
|
||||
'label' => 'Verifikasi Akun Wali Murid',
|
||||
'description' => 'Menyetujui/menolak akun wali murid yang mendaftar dari aplikasi mobile',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
// Role yang berhak memverifikasi
|
||||
foreach (['admin', 'bk', 'waka_kesiswaan', 'kepala_sekolah', 'ketua_tim'] as $role) {
|
||||
DB::table('role_permissions')->insertOrIgnore([
|
||||
'role' => $role,
|
||||
'permission_id' => $id,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$ids = DB::table('permissions')->where('key', 'parents-verify')->pluck('id');
|
||||
DB::table('role_permissions')->whereIn('permission_id', $ids)->delete();
|
||||
DB::table('permissions')->where('key', 'parents-verify')->delete();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user