getCurrentUser(); if (!$user || !$user->hasPermission($permission)) { $this->addFlash('error', 'Você não tem permissão para acessar esta área.'); $this->redirect('admin/dashboard')->send(); exit; } } /** * Display a listing of the notes. * * @param Request $request * @return \Symfony\Component\HttpFoundation\Response */ public function index(Request $request) { $this->checkPermission('notes.view'); $query = Note::currentUser()->with('subject'); // Search system if ($search = $request->query->get('search')) { $query->where(function ($q) use ($search) { $q->where('notes_title', 'like', "%{$search}%") ->orWhere('notes_content', 'like', "%{$search}%"); }); } // Subject filter if ($subject_id = $request->query->get('subject_id')) { $query->where('notes_subject_id', $subject_id); } $notes = $query->orderBy('notes_is_pinned', 'desc') ->orderBy('created_at', 'desc') ->get(); // Get subjects for filter and select $subjects = Subject::currentUser()->orderBy('subjects_name')->get(); return $this->renderAdminView('@notes/admin/index.twig', [ 'title' => __('notes.title'), 'notes' => $notes, 'subjects' => $subjects, 'filters' => [ 'search' => $search, 'subject_id' => $subject_id ] ]); } /** * Show the form for creating a new note. * * @return \Symfony\Component\HttpFoundation\Response */ public function create() { $this->checkPermission('notes.create'); $subjects = Subject::currentUser()->orderBy('subjects_name')->get(); return $this->renderAdminView('@notes/admin/create.twig', [ 'title' => __('notes.add_note'), 'subjects' => $subjects ]); } /** * Store a newly created note. * * @param Request $request * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function store(Request $request) { $this->checkPermission('notes.create'); $data = $request->request->all(); try { // Ensure session is started if (session_status() === PHP_SESSION_NONE) { session_start(); } $busId = $_SESSION['user_idbus'] ?? null; if (empty($busId)) { $busId = 1; } $noteData = [ 'notes_idbus' => $busId, 'notes_iduser' => $_SESSION['user_id'] ?? null, 'notes_title' => $data['notes_title'], 'notes_content' => $data['notes_content'] ?? null, 'notes_subject_id' => $data['notes_subject_id'] ?: null, 'notes_color' => $data['notes_color'] ?? '#ffffff', 'notes_is_pinned' => isset($data['notes_is_pinned']) ? 1 : 0 ]; // Handle image upload if ($request->files->has('notes_image') && $request->files->get('notes_image')) { $file = $request->files->get('notes_image'); if ($file->isValid()) { $noteData['notes_image'] = $this->handleUpload($file); } } // Handle file upload if ($request->files->has('notes_file') && $request->files->get('notes_file')) { $file = $request->files->get('notes_file'); if ($file->isValid()) { $noteData['notes_file'] = $this->handleUpload($file); } } Note::create($noteData); $this->addFlash('success', __('notes.flash_note_created')); } catch (\Exception $e) { // Check if error is missing column (SQLSTATE[42S22]) if (strpos($e->getMessage(), '42S22') !== false) { \App\Helpers\Log::warning('Missing columns in notes table. Migration might be pending.', ['error' => $e->getMessage()]); // Try saving without the new columns unset($noteData['notes_image'], $noteData['notes_file']); try { Note::create($noteData); $this->addFlash('success', __('notes.flash_note_created') . ' (Aviso: Anexos não suportados até que a migração seja executada)'); } catch (\Exception $e2) { \App\Helpers\Log::error('Error storing note fallback', ['error' => $e2->getMessage()]); $this->addFlash('error', 'Erro ao criar a nota: ' . $e2->getMessage()); } } else { \App\Helpers\Log::error('Error storing note', ['error' => $e->getMessage()]); $this->addFlash('error', 'Erro ao criar a nota: ' . $e->getMessage()); } } return $this->redirect('/admin/notes'); } /** * Show the form for editing the specified note. * * @param Request $request * @param int $id * @return \Symfony\Component\HttpFoundation\Response */ public function edit(Request $request, $id) { $this->checkPermission('notes.edit'); $note = Note::currentUser()->findOrFail($id); $subjects = Subject::currentUser()->orderBy('subjects_name')->get(); return $this->renderAdminView('@notes/admin/edit.twig', [ 'title' => __('notes.edit_note'), 'note' => $note, 'subjects' => $subjects ]); } /** * Update the specified note. * * @param Request $request * @param int $id * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function update(Request $request, $id) { $this->checkPermission('notes.edit'); $data = $request->request->all(); try { $note = Note::currentUser()->findOrFail($id); $noteData = [ 'notes_title' => $data['notes_title'], 'notes_content' => $data['notes_content'] ?? null, 'notes_subject_id' => $data['notes_subject_id'] ?: null, 'notes_color' => $data['notes_color'] ?? '#ffffff', 'notes_is_pinned' => isset($data['notes_is_pinned']) ? 1 : 0 ]; // Handle image upload if ($request->files->has('notes_image') && $request->files->get('notes_image')) { $file = $request->files->get('notes_image'); if ($file->isValid()) { // Delete old image if ($note->notes_image) { $this->deletePhysicalFile($note->notes_image); } $noteData['notes_image'] = $this->handleUpload($file); } } // Handle file upload if ($request->files->has('notes_file') && $request->files->get('notes_file')) { $file = $request->files->get('notes_file'); if ($file->isValid()) { // Delete old file if ($note->notes_file) { $this->deletePhysicalFile($note->notes_file); } $noteData['notes_file'] = $this->handleUpload($file); } } $note->update($noteData); $this->addFlash('success', __('notes.flash_note_updated')); } catch (\Exception $e) { // Check if error is missing column (SQLSTATE[42S22]) if (strpos($e->getMessage(), '42S22') !== false) { \App\Helpers\Log::warning('Missing columns in notes table. Migration might be pending.', ['id' => $id, 'error' => $e->getMessage()]); // Try updating without the new columns unset($noteData['notes_image'], $noteData['notes_file']); try { $note->update($noteData); $this->addFlash('success', __('notes.flash_note_updated') . ' (Aviso: Anexos não suportados até que a migração seja executada)'); } catch (\Exception $e2) { \App\Helpers\Log::error('Error updating note fallback', ['id' => $id, 'error' => $e2->getMessage()]); $this->addFlash('error', 'Erro ao atualizar a nota: ' . $e2->getMessage()); } } else { \App\Helpers\Log::error('Error updating note', ['id' => $id, 'error' => $e->getMessage()]); $this->addFlash('error', 'Erro ao atualizar a nota: ' . $e->getMessage()); } } return $this->redirect('/admin/notes'); } /** * Remove the specified note. * * @param Request $request * @param int $id * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function delete(Request $request, $id) { $this->checkPermission('notes.delete'); $note = Note::currentUser()->findOrFail($id); // Delete attachments if ($note->notes_image) { $this->deletePhysicalFile($note->notes_image); } if ($note->notes_file) { $this->deletePhysicalFile($note->notes_file); } $note->delete(); $this->addFlash('success', __('notes.flash_note_deleted')); return $this->redirect('/admin/notes'); } /** * Handle file upload. * * @param \Symfony\Component\HttpFoundation\File\UploadedFile $file * @return string|null */ protected function handleUpload($file): ?string { if (!$file) { return null; } $destination = dirname(__DIR__, 4) . '/storage/uploads/notes'; if (!is_dir($destination)) { mkdir($destination, 0755, true); } $filename = uniqid('img_') . '.' . $file->guessExtension(); $file->move($destination, $filename); return $filename; } /** * Delete physical file. * * @param string $filename * @return void */ protected function deletePhysicalFile(string $filename) { $filePath = dirname(__DIR__, 4) . '/storage/uploads/notes/' . $filename; if (file_exists($filePath) && is_file($filePath)) { unlink($filePath); } } /** * Toggle the pinned status of a note. * * @param Request $request * @param int $id * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function pin(Request $request, $id) { $this->checkPermission('notes.edit'); $note = Note::currentUser()->findOrFail($id); $note->notes_is_pinned = !$note->notes_is_pinned; $note->save(); $this->addFlash('success', $note->notes_is_pinned ? __('notes.flash_note_pinned') : __('notes.flash_note_unpinned')); return $this->redirect('/admin/notes'); } /** * Store a newly created subject. * * @param Request $request * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function storeSubject(Request $request) { $this->checkPermission('notes.create'); $data = $request->request->all(); // Ensure session is started if (session_status() === PHP_SESSION_NONE) { session_start(); } $busId = $_SESSION['user_idbus'] ?? null; if (empty($busId)) { $busId = 1; } Subject::create([ 'subjects_idbus' => $busId, 'subjects_iduser' => $_SESSION['user_id'] ?? null, 'subjects_name' => $data['subjects_name'], 'subjects_color' => $data['subjects_color'] ?? '#6c757d' ]); $this->addFlash('success', __('notes.flash_subject_created')); return $this->redirect('/admin/notes'); } /** * Delete a subject. * * @param Request $request * @param int $id * @return \Symfony\Component\HttpFoundation\RedirectResponse */ public function deleteSubject(Request $request, $id) { $this->checkPermission('notes.delete'); $subject = Subject::currentUser()->findOrFail($id); // Remove reference from notes Note::currentUser()->where('notes_subject_id', $id)->update(['notes_subject_id' => null]); $subject->delete(); $this->addFlash('success', __('notes.flash_subject_deleted')); return $this->redirect('/admin/notes'); } }