TIFNJK_E41221880/app/Http/Controllers/api/UserController.php

406 lines
14 KiB
PHP

<?php
namespace App\Http\Controllers\api;
use App\Http\Controllers\Controller;
use App\Models\Classes;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
class UserController extends Controller
{
public function storeFcmToken(Request $request)
{
$validated = $request->validate([
'fcm_token' => 'required|string',
// 'platform' => 'nullable|string',
// device_id DIHAPUS
]);
$user = $request->user();
$user->update([
'device_token' => $validated['fcm_token'],
// 'platform' => $validated['platform'] ?? 'android',
// device_id tidak dipakai
]);
return response()->json([
'success' => true,
'message' => 'FCM token stored successfully',
]);
}
public function getTopicFromClass(Request $request, $classId)
{
// request check Authorization header for Bearer token
$user = $request->user();
if (!$user) {
return response()->json(['success' => false, 'message' => 'Unauthorized'], 401);
}
$class = Classes::find($classId);
if (!$class) {
return response()->json(['success' => false, 'message' => 'Class not found'], 404);
}
if (!$class->fcm_topic) {
return response()->json(['success' => false, 'message' => 'Class does not have an FCM topic'], 400);
}
// Logic untuk subscribe ke topic bisa ditambahkan di sini
// Misalnya simpan di database atau langsung panggil service FCM
return response()->json([
'success' => true,
'message' => "Subscribed to class topic: {$class->fcm_topic}",
'data' => [
'class_id' => $class->id,
'class_name' => $class->name,
'fcm_topic' => $class->fcm_topic,
]
], 200);
}
public function login(Request $request)
{
try {
$user = User::where('email', $request->email)->first();
// cek apakah email user ditemukan
if (!$user) {
return response()->json([
'success' => false,
'message' => 'Akun tidak ditemukan'
], 401);
}
// cek apakah password benar
if (!$user || !Hash::check($request->password, $user->password)) {
return response()->json([
'success' => false,
'message' => 'Email atau password tidak sesuai'
], 401);
}
// check if user is banned
if ($user->is_banned) {
return response()->json([
'success' => false,
'message' => 'Akun anda telah diblokir. Silakan hubungi administrator untuk informasi lebih lanjut.'
], 403);
}
$token = $user->createToken('auth_token')->plainTextToken;
$this->syncTopicSubscribe($user);
$userData = $user->load('teacher', 'student.class');
return response()->json([
'success' => true,
'message' => 'Login successful',
'access_token' => $token,
'token_type' => 'Bearer',
'user' => $userData
], 200);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Something went wrong',
'error' => $e->getMessage() // bisa dihapus di production untuk keamanan
], 500);
}
}
public function register(Request $request)
{
DB::beginTransaction();
try {
//code...
$messages = [
'name.required' => 'Nama harus diisi',
'name.max' => 'Nama maksimal :max karakter',
'email.required' => 'Email harus diisi',
'email.email' => 'Format email tidak valid',
'email.unique' => 'Akun ini sudah terdaftar',
'password.required' => 'Password harus diisi',
'password.min' => 'Password minimal :min karakter',
'role.required' => 'Role harus dipilih',
'role.in' => 'Role tidak valid',
];
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6',
'role' => 'required|in:teacher,student',
], $messages);
// buat akun user
$user = User::create([
'email' => $request->email,
'password' => Hash::make($request->password),
'role' => $request->role,
'profile_picture' => $request->profile_picture ?? null,
]);
// buat record sesuai role
if ($user->role == 'teacher') {
$messagesTeacher = [
'nip.required' => 'NIP harus diisi',
'nip.max' => 'NIP maksimal :max karakter',
'nip.unique' => 'NIP sudah pernah dipakai',
'subject.required' => 'Mata pelajaran harus diisi',
'subject.max' => 'Mata pelajaran maksimal :max karakter',
];
$request->validate([
'nip' => 'required|string|max:50|unique:teachers,nip',
'subject' => 'required|string|max:100',
], $messagesTeacher);
$user->teacher()->create([
'id_user' => $user->id,
'name' => $request->name,
'nip' => $request->nip,
'subject' => $request->subject,
]);
} else if ($user->role == 'student') {
$messagesStudent = [
'nisn.required' => 'NISN harus diisi',
'nisn.max' => 'NISN maksimal :max karakter',
'nisn.unique' => 'Akun ini sudah terdaftar',
'id_class.required' => 'Kelas harus dipilih',
'id_class.integer' => 'ID kelas tidak valid',
'entry_year.required' => 'Tahun masuk harus diisi',
'entry_year.integer' => 'Tahun masuk tidak valid',
];
$request->validate([
'nisn' => 'required|string|max:50|unique:students,nisn',
'id_class' => 'required|integer',
'entry_year' => 'required|integer',
], $messagesStudent);
$user->student()->create([
'id_user' => $user->id,
'name' => $request->name,
'nisn' => $request->nisn,
'id_class' => $request->id_class,
'entry_year' => $request->entry_year,
'pictures' => $request->pictures ?? null,
]);
}
$this->syncTopicSubscribe($user);
DB::commit();
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'success' => true,
'message' => 'Anda berhasil register',
'access_token' => $token,
'token_type' => 'Bearer',
'user' => $user->load('teacher', 'student')
], 201);
} catch (\Illuminate\Validation\ValidationException $e) {
DB::rollBack();
return response()->json([
'success' => false,
'message' => 'Validation error',
'errors' => $e->errors(), // detail error validasi
], 422);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'success' => false,
'message' => 'Registration failed',
'error' => $e->getMessage(), // optional, bisa di-hide kalau production
], 500);
}
}
public function feedback(Request $request)
{
return response()->json([
'message' => 'Halo student, ini feedback testing!',
'user' => $request->user()->only(['id', 'name', 'email', 'role']),
]);
}
private function syncTopicSubscribe(User $user): ?string
{
$user->loadMissing('student.class');
if (!$user->student) {
return null;
}
$topics = ['student_notifications'];
if ($topic = $user->student->class?->fcm_topic) {
$topics[] = $topic;
}
$topics = array_unique(array_filter($topics));
if (empty($topics)) {
return null;
}
$topicSubscribe = implode(', ', $topics);
if ($user->topic_subscribe !== $topicSubscribe) {
$user->update(['topic_subscribe' => $topicSubscribe]);
}
$user->topic_subscribe = $topicSubscribe;
return $topicSubscribe;
}
// get student notification list data from notification table.
// note filter: user_id = auth user id, or his class id.
public function getStudentNotifications(Request $request)
{
$user = $request->user();
$student = $user->student;
if (!$user || !$student) {
return response()->json(['success' => false, 'message' => 'Unauthorized'], 401);
}
// validate query parameters
$request->validate([
'start_date' => 'required|date',
'end_date' => 'required|date',
]);
$classId = $user->student->id_class;
$startDate = $request->input('start_date');
$endDate = Carbon::parse($request->input('end_date'))->endOfDay();
// filter by class id and date range
$notifications = DB::table('notifications')
->where(function ($query) use ($user, $classId) {
$query->where('receiver_id', $user->id)
->orWhere('class_id', $classId)
->orWhere(function ($q) {
$q->whereNull('receiver_id')
->whereNull('class_id');
});
})
->whereBetween('created_at', [$startDate, $endDate])
->orderBy('created_at', 'desc')
->get();
return response()->json([
'success' => true,
'message' => 'Notifications fetched successfully',
'data' => $notifications,
], 200);
}
// get activity teacher history from notification table with related sender_id with the user.
public function getTeacherActivity(Request $request)
{
$user = $request->user();
if (!$user || !$user->teacher) {
return response()->json(['success' => false, 'message' => 'Unauthorized'], 401);
}
// validate query parameters
$request->validate([
'start_date' => 'required|date',
'end_date' => 'required|date',
]);
$startDate = $request->input('start_date');
$endDate = Carbon::parse($request->input('end_date'))->endOfDay();
// filter by sender_id and date range
$activities = DB::table('notifications')
->where('sender_id', $user->id)
->whereBetween('created_at', [$startDate, $endDate])
->orderBy('created_at', 'desc')
->get();
return response()->json([
'success' => true,
'message' => 'Activities fetched successfully',
'data' => $activities,
], 200);
}
// update profile user, for all (teacher, student, admin)
public function updateProfilePhoto(Request $request)
{
// auth check
$user = $request->user();
if (!$user) {
return response()->json(['success' => false, 'message' => 'Unauthorized'], 401);
}
// check user role for separated storage path, for example: profile_pictures/teacher, profile_pictures/student, etc.
$rolePath = match ($user->role) {
'teacher' => 'teacher',
'student' => 'student',
'admin' => 'admin',
default => 'others',
};
// input file check using request validation
// nullable|file|mimes:jpg,jpeg,png|max:2048',
$request->validate([
'profile_picture' => 'required|file|mimes:jpg,jpeg,png|max:2048',
]);
try {
$file = $request->file('profile_picture');
// store to storage:disk public, with unique name
$fileName = 'profile_' . $user->id . '_' . time() . '.' . $file->getClientOriginalExtension();
Storage::disk('public')->putFileAs('profile_pictures/' . $rolePath, $file, $fileName);
// update user profile picture path
$user->update(['profile_picture' => $fileName]);
return response()->json([
'success' => true,
'message' => 'Profile picture updated successfully',
'data' => [
'profile_picture' => $fileName,
'profile_picture_url' => asset('storage/profile_pictures/' . $rolePath . '/' . $fileName),
]
], 200);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Failed to update profile picture',
'error' => $e->getMessage(),
], 500);
}
}
}