406 lines
14 KiB
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);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|