First Commit
This commit is contained in:
+432
@@ -0,0 +1,432 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) 2026 Marco Costa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Marco Costa
|
||||
* Email: contato@syspanel.com.br
|
||||
* Project: SysCMS
|
||||
*
|
||||
* This software is licensed, not sold.
|
||||
* Permission is granted to use this software
|
||||
* subject to the terms of the SysCMS Commercial License.
|
||||
*
|
||||
* Redistribution, sublicensing, resale, or
|
||||
* disclosure of this software, in whole or in part,
|
||||
* is strictly prohibited without prior written permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
||||
*/
|
||||
|
||||
namespace Modules\Notes\Controllers;
|
||||
|
||||
use App\Controllers\BaseAdminController;
|
||||
use Kernel\View;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Modules\Notes\Models\Note;
|
||||
use Modules\Notes\Models\Subject;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
/**
|
||||
* Class NotesController
|
||||
*
|
||||
* Main controller for Notes management.
|
||||
*
|
||||
* @package Modules\Notes\Controllers
|
||||
*/
|
||||
class NotesController extends BaseAdminController
|
||||
{
|
||||
/**
|
||||
* NotesController constructor.
|
||||
*
|
||||
* @param View $view
|
||||
*/
|
||||
public function __construct(View $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has permission.
|
||||
*
|
||||
* @param string $permission
|
||||
* @return void
|
||||
*/
|
||||
protected function checkPermission(string $permission)
|
||||
{
|
||||
$user = $this->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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user