feat: Face ID (scan, register, liveness) + role baru KS/Waka/Ketua Tim + notifikasi WA ortu + scoping wali kelas + error pages premium
This commit is contained in:
@@ -3,9 +3,12 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Classes;
|
||||
use App\Models\HandlingType;
|
||||
use App\Models\SpThreshold;
|
||||
use App\Models\ViolationCategory;
|
||||
use App\Models\ViolationType;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -143,6 +146,147 @@ class MasterDataController extends Controller
|
||||
return back()->with('success', 'Jenis pelanggaran berhasil dihapus.');
|
||||
}
|
||||
|
||||
// === Handling Types (Jenis Penanganan) ===
|
||||
public function handlingTypes(): View
|
||||
{
|
||||
$types = HandlingType::orderBy('sort_order')->orderBy('name')->get();
|
||||
$roles = HandlingType::roles();
|
||||
|
||||
return view('settings.handling-types', compact('types', 'roles'));
|
||||
}
|
||||
|
||||
public function storeHandlingType(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => ['required', 'string', 'max:255', 'unique:handling_types,name'],
|
||||
'icon' => ['required', 'string', 'max:100'],
|
||||
'color' => ['required', 'string', 'max:7'],
|
||||
'sort_order' => ['nullable', 'integer', 'min:0', 'max:999'],
|
||||
]);
|
||||
|
||||
$validated['sort_order'] = $validated['sort_order'] ?? 0;
|
||||
$validated['is_active'] = true;
|
||||
|
||||
HandlingType::create($validated);
|
||||
|
||||
return back()->with('success', 'Jenis penanganan berhasil ditambahkan.');
|
||||
}
|
||||
|
||||
public function updateHandlingType(Request $request, HandlingType $type): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => ['required', 'string', 'max:255', 'unique:handling_types,name,' . $type->id],
|
||||
'icon' => ['required', 'string', 'max:100'],
|
||||
'color' => ['required', 'string', 'max:7'],
|
||||
'sort_order' => ['nullable', 'integer', 'min:0', 'max:999'],
|
||||
'is_active' => ['boolean'],
|
||||
]);
|
||||
|
||||
$validated['sort_order'] = $validated['sort_order'] ?? $type->sort_order;
|
||||
$validated['is_active'] = $request->boolean('is_active');
|
||||
|
||||
$type->update($validated);
|
||||
|
||||
return back()->with('success', 'Jenis penanganan berhasil diperbarui.');
|
||||
}
|
||||
|
||||
public function reorderHandlingTypes(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'order' => ['required', 'array'],
|
||||
'order.*' => ['integer', 'exists:handling_types,id'],
|
||||
]);
|
||||
|
||||
foreach ($validated['order'] as $i => $id) {
|
||||
HandlingType::where('id', $id)->update(['sort_order' => $i + 1]);
|
||||
}
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
public function destroyHandlingType(HandlingType $type): RedirectResponse
|
||||
{
|
||||
if ($type->is_system) {
|
||||
return back()->with('error', 'Jenis penanganan sistem tidak bisa dihapus. Nonaktifkan saja jika tidak diperlukan.');
|
||||
}
|
||||
|
||||
$type->delete();
|
||||
|
||||
return back()->with('success', 'Jenis penanganan berhasil dihapus.');
|
||||
}
|
||||
|
||||
public function storeHandlingRole(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'role' => ['required', 'string', 'max:100'],
|
||||
]);
|
||||
|
||||
$roles = HandlingType::roles();
|
||||
$role = trim($validated['role']);
|
||||
|
||||
if (in_array($role, $roles)) {
|
||||
return back()->with('error', 'Peran "' . $role . '" sudah ada.');
|
||||
}
|
||||
|
||||
$roles[] = $role;
|
||||
HandlingType::saveRoles($roles);
|
||||
|
||||
return back()->with('success', 'Peran "' . $role . '" berhasil ditambahkan.');
|
||||
}
|
||||
|
||||
public function destroyHandlingRole(string $role): RedirectResponse
|
||||
{
|
||||
$roles = HandlingType::roles();
|
||||
$roles = array_values(array_filter($roles, fn($r) => $r !== $role));
|
||||
HandlingType::saveRoles($roles);
|
||||
|
||||
return back()->with('success', 'Peran "' . $role . '" berhasil dihapus.');
|
||||
}
|
||||
|
||||
public function reorderHandlingRoles(Request $request): JsonResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'order' => ['required', 'array'],
|
||||
'order.*' => ['required', 'string', 'max:100'],
|
||||
]);
|
||||
|
||||
HandlingType::saveRoles($validated['order']);
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
// === Homeroom Teachers (Wali Kelas) ===
|
||||
public function homeroomTeachers(): View
|
||||
{
|
||||
$classes = Classes::with('homeroomTeacher')
|
||||
->where('is_active', true)
|
||||
->orderBy('level')
|
||||
->orderBy('name')
|
||||
->get();
|
||||
$teachers = \App\Models\User::where(function ($q) {
|
||||
$q->whereJsonContains('roles', 'wali_kelas')->orWhere('role', 'wali_kelas');
|
||||
})
|
||||
->where('is_active', true)
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
return view('settings.homeroom', compact('classes', 'teachers'));
|
||||
}
|
||||
|
||||
public function updateHomeroomTeacher(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'class_id' => ['required', 'exists:classes,id'],
|
||||
'teacher_id' => ['nullable', 'exists:users,id'],
|
||||
]);
|
||||
|
||||
$class = Classes::findOrFail($validated['class_id']);
|
||||
$class->homeroom_teacher_id = $validated['teacher_id'] ?? null;
|
||||
$class->save();
|
||||
|
||||
return back()->with('success', 'Wali kelas untuk ' . $class->name . ' berhasil diperbarui.');
|
||||
}
|
||||
|
||||
// === SP Thresholds ===
|
||||
public function thresholds(): View
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ class PermissionController extends Controller
|
||||
->get()
|
||||
->groupBy('group');
|
||||
|
||||
$roles = ['admin', 'bk', 'wali_kelas', 'staff', 'other'];
|
||||
$roles = ['admin', 'bk', 'wali_kelas', 'staff', 'other', 'kepala_sekolah', 'waka_kesiswaan', 'ketua_tim'];
|
||||
|
||||
$rolePermissions = [];
|
||||
foreach ($roles as $role) {
|
||||
@@ -69,7 +69,7 @@ class PermissionController extends Controller
|
||||
}
|
||||
|
||||
// Clear cache
|
||||
foreach (['admin', 'bk', 'wali_kelas', 'staff', 'other'] as $role) {
|
||||
foreach (['admin', 'bk', 'wali_kelas', 'staff', 'other', 'kepala_sekolah', 'waka_kesiswaan', 'ketua_tim'] as $role) {
|
||||
Cache::forget('role_permissions:' . $role);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ class SettingsController extends Controller
|
||||
'kepala_sekolah_name' => ['nullable', 'string', 'max:255'],
|
||||
'kepala_sekolah_nip' => ['nullable', 'string', 'max:50'],
|
||||
'bk_koordinator_name' => ['nullable', 'string', 'max:255'],
|
||||
'wa_notification_template' => ['nullable', 'string', 'max:3000'],
|
||||
]);
|
||||
|
||||
foreach ($validated as $key => $value) {
|
||||
|
||||
@@ -25,7 +25,11 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
if ($request->filled('role')) {
|
||||
$query->where('role', $request->role);
|
||||
$role = $request->role;
|
||||
$query->where(function ($q) use ($role) {
|
||||
$q->where('role', $role)
|
||||
->orWhereJsonContains('roles', $role);
|
||||
});
|
||||
}
|
||||
|
||||
$users = $query->orderBy('name')->paginate(20);
|
||||
@@ -40,10 +44,14 @@ class UserController extends Controller
|
||||
'username' => ['required', 'string', 'max:255', 'unique:users,username'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email'],
|
||||
'password' => ['required', 'string', 'min:6'],
|
||||
'role' => ['required', 'in:admin,bk,wali_kelas,staff,other'],
|
||||
'roles' => ['required', 'array', 'min:1'],
|
||||
'roles.*' => ['in:admin,bk,wali_kelas,staff,other,kepala_sekolah,waka_kesiswaan,ketua_tim'],
|
||||
'is_active' => ['boolean'],
|
||||
]);
|
||||
|
||||
$roles = array_values(array_unique($validated['roles']));
|
||||
$validated['roles'] = $roles;
|
||||
$validated['role'] = $roles[0];
|
||||
$validated['password'] = Hash::make($validated['password']);
|
||||
$validated['is_active'] = $request->boolean('is_active', true);
|
||||
|
||||
@@ -60,10 +68,15 @@ class UserController extends Controller
|
||||
'username' => ['required', 'string', 'max:255', 'unique:users,username,' . $user->id],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email,' . $user->id],
|
||||
'password' => ['nullable', 'string', 'min:6'],
|
||||
'role' => ['required', 'in:admin,bk,wali_kelas,staff,other'],
|
||||
'roles' => ['required', 'array', 'min:1'],
|
||||
'roles.*' => ['in:admin,bk,wali_kelas,staff,other,kepala_sekolah,waka_kesiswaan,ketua_tim'],
|
||||
'is_active' => ['boolean'],
|
||||
]);
|
||||
|
||||
$roles = array_values(array_unique($validated['roles']));
|
||||
$validated['roles'] = $roles;
|
||||
$validated['role'] = $roles[0];
|
||||
|
||||
if (!empty($validated['password'])) {
|
||||
$validated['password'] = Hash::make($validated['password']);
|
||||
} else {
|
||||
@@ -92,7 +105,7 @@ class UserController extends Controller
|
||||
|
||||
public function resetPassword(Request $request, User $user): RedirectResponse
|
||||
{
|
||||
if ($user->id === auth()->id() && $user->role === 'admin') {
|
||||
if ($user->id === auth()->id() && $user->isAdmin()) {
|
||||
return back()->with('error', 'Ganti password admin lewat profil.');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user