Files
server/app/Controllers/OrderController.php
2026-03-18 13:58:20 -03:00

256 lines
9.5 KiB
PHP

<?php
namespace App\Controllers;
use App\Models\Order;
use App\Models\OrderAttachment;
use App\Services\AttachmentService;
use App\Services\OrderProcessor;
use App\Services\TelegramService;
use App\Utils\View;
class OrderController
{
public function index()
{
$orderModel = new Order();
$orders = [];
if (isset($_GET['q']) && !empty($_GET['q'])) {
$search = $_GET['q'];
$conn = \App\Config\Database::getInstance()->getConnection();
// Search by ID, Title, or Domain Content
// Using DISTINCT to avoid duplicates if multiple domains match in same order
$sql = "SELECT DISTINCT o.* FROM orders o
LEFT JOIN order_items oi ON o.id = oi.order_id
LEFT JOIN domains d ON oi.domain_id = d.id
WHERE o.id LIKE :search
OR o.title LIKE :search
OR d.name LIKE :search
ORDER BY o.id DESC";
$stmt = $conn->prepare($sql);
$stmt->execute(['search' => "%$search%"]);
$orders = $stmt->fetchAll();
} else {
$orders = $orderModel->findAll();
// Sort by ID desc
usort($orders, function ($a, $b) {
return $b['id'] - $a['id'];
});
}
// Pagination Logic
$page = isset($_GET['page']) ? (int) $_GET['page'] : 1;
$perPage = 30;
$total = count($orders);
$totalPages = ceil($total / $perPage);
$offset = ($page - 1) * $perPage;
$paginatedOrders = array_slice($orders, $offset, $perPage);
View::render('layouts.admin', [
'title' => 'Ordens Judiciais',
'content' => __DIR__ . '/../../resources/views/admin/orders/index.php',
'orders' => $paginatedOrders,
'pagination' => [
'current' => $page,
'total' => $totalPages,
'next' => ($page < $totalPages) ? $page + 1 : null,
'prev' => ($page > 1) ? $page - 1 : null
]
]);
}
public function create()
{
View::render('layouts.admin', [
'title' => 'Nova Ordem',
'content' => __DIR__ . '/../../resources/views/admin/orders/create.php'
]);
}
public function store()
{
// Detect post_max_size overflow
if (empty($_POST) && empty($_FILES) && isset($_SERVER['CONTENT_LENGTH']) && (int)$_SERVER['CONTENT_LENGTH'] > 0) {
$_SESSION['flash_error'] = "O tamanho total dos arquivos enviados excede o limite permitido pelo servidor.";
View::redirect('/admin/orders/create');
return;
}
if (!isset($_FILES['csv_file']) || $_FILES['csv_file']['error'] !== UPLOAD_ERR_OK) {
$csvError = $_FILES['csv_file']['error'] ?? 'desconhecido';
if ($csvError === UPLOAD_ERR_INI_SIZE || $csvError === UPLOAD_ERR_FORM_SIZE) {
$_SESSION['flash_error'] = "O arquivo CSV/TXT excede o limite de tamanho permitido pelo servidor.";
} else {
$_SESSION['flash_error'] = "Erro no upload do arquivo CSV. (código " . $csvError . ")";
}
View::redirect('/admin/orders/create');
return;
}
// Validate attachments before inserting the order
if (isset($_FILES['attachments']) && !empty($_FILES['attachments']['name'][0])) {
$attachments = $_FILES['attachments'];
$count = count($attachments['name']);
for ($i = 0; $i < $count; $i++) {
$error = $attachments['error'][$i];
if ($error !== UPLOAD_ERR_OK && $error !== UPLOAD_ERR_NO_FILE) {
$fileName = $attachments['name'][$i];
if ($error === UPLOAD_ERR_INI_SIZE || $error === UPLOAD_ERR_FORM_SIZE) {
$_SESSION['flash_error'] = "O anexo '{$fileName}' excede o tamanho máximo permitido.";
} else {
$_SESSION['flash_error'] = "Erro no upload do anexo '{$fileName}': código {$error}.";
}
View::redirect('/admin/orders/create');
return;
}
}
}
$title = $_POST['title'];
$type = $_POST['type'];
$content = \App\Utils\TextFormatter::normalizeLineBreaks($_POST['content']);
$received_at = $_POST['received_at'];
$conn = \App\Config\Database::getInstance()->getConnection();
$conn->beginTransaction();
try {
// Create Order
$sql = "INSERT INTO orders (title, type, content, received_at) VALUES (:title, :type, :content, :received_at)";
$stmt = $conn->prepare($sql);
$stmt->execute([
'title' => $title,
'type' => $type,
'content' => $content,
'received_at' => $received_at
]);
$orderId = $conn->lastInsertId();
// Process CSV (unchanged)
$processor = new OrderProcessor();
$count = $processor->process($orderId, $type, $_FILES['csv_file']['tmp_name']);
// Store attachments (if any were sent)
if (isset($_FILES['attachments']) && !empty($_FILES['attachments']['name'][0])) {
$attachmentService = new AttachmentService();
$attachmentService->storeFiles((int) $orderId, $_FILES['attachments']);
}
// Send Telegram Notification
$telegramService = new TelegramService();
$typeLabel = ($type === 'block') ? 'Bloqueio' : (($type === 'unblock') ? 'Desbloqueio' : $type);
$telegramService->sendOrderNotification([
'id' => $orderId,
'title' => $title,
'type' => $typeLabel
], $count);
$conn->commit();
$_SESSION['flash_success'] = "Ordem criada com sucesso! $count domínios processados.";
View::redirect('/admin/orders');
} catch (\Exception $e) {
$conn->rollBack();
$_SESSION['flash_error'] = "Erro ao processar ordem: " . $e->getMessage();
View::redirect('/admin/orders/create');
}
}
public function view($id)
{
$orderModel = new Order();
$order = $orderModel->find($id);
if (!$order) {
View::redirect('/admin/orders');
}
// Get Items
$conn = \App\Config\Database::getInstance()->getConnection();
$stmt = $conn->prepare("SELECT d.name, oi.action FROM order_items oi JOIN domains d ON oi.domain_id = d.id WHERE oi.order_id = :id");
$stmt->execute(['id' => $id]);
$items = $stmt->fetchAll();
// Get Attachments
$attachmentModel = new OrderAttachment();
$attachments = $attachmentModel->findByOrderId((int) $id);
View::render('layouts.admin', [
'title' => 'Detalhes da Ordem #' . $id,
'content' => __DIR__ . '/../../resources/views/admin/orders/view.php',
'order' => $order,
'items' => $items,
'attachments' => $attachments,
]);
}
public function downloadAttachment($id)
{
$attachmentModel = new OrderAttachment();
$attachment = $attachmentModel->find($id);
if (!$attachment) {
$_SESSION['flash_error'] = "Anexo não encontrado.";
View::redirect('/admin/orders');
return;
}
$attachmentService = new AttachmentService();
$filePath = $attachmentService->getFilePath((int) $attachment['order_id'], $attachment['stored_name']);
if (!file_exists($filePath)) {
$_SESSION['flash_error'] = "Arquivo físico não encontrado no servidor.";
View::redirect('/admin/orders/view/' . $attachment['order_id']);
return;
}
// Serve o arquivo para download
header('Content-Type: ' . ($attachment['mime_type'] ?? 'application/octet-stream'));
header('Content-Disposition: attachment; filename="' . addslashes($attachment['original_name']) . '"');
header('Content-Length: ' . filesize($filePath));
header('Cache-Control: private, no-cache');
header('Pragma: no-cache');
readfile($filePath);
exit;
}
public function uploadAttachments($id)
{
$orderModel = new \App\Models\Order();
$order = $orderModel->find($id);
if (!$order) {
$_SESSION['flash_error'] = "Ordem não encontrada.";
View::redirect('/admin/orders');
return;
}
try {
if (isset($_FILES['new_attachments']) && !empty($_FILES['new_attachments']['name'][0])) {
$attachments = $_FILES['new_attachments'];
$attachmentService = new AttachmentService();
$savedCount = $attachmentService->storeFiles((int) $id, $attachments);
if ($savedCount > 0) {
$_SESSION['flash_success'] = "{$savedCount} anexo(s) adicionado(s) com sucesso à ordem!";
} else {
$_SESSION['flash_error'] = "Nenhum arquivo válido foi recebido.";
}
} else {
$_SESSION['flash_error'] = "Nenhum arquivo foi selecionado.";
}
} catch (\Exception $e) {
$_SESSION['flash_error'] = "Erro de upload: " . $e->getMessage();
}
View::redirect('/admin/orders/view/' . $id);
}
}