Files
Nexora/app/Http/Controllers/DocumentController.php

458 lines
13 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Jobs\ProcessDocumentOCR;
use App\Models\Document;
use App\Models\Project;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class DocumentController extends Controller
{
public $comments=[];
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
'files.*' => 'required|file|mimes:pdf,docx,xlsx,jpg,png|max:5120',
'project_id' => 'required|exists:projects,id',
'folder_id' => 'nullable|exists:folders,id'
]);
foreach ($request->file('files') as $file) {
$document = Document::create([
'name' => $file->getClientOriginalName(),
'project_id' => $request->project_id,
'folder_id' => $request->folder_id,
'created_by' => auth()->id()
]);
$document->addMedia($file)->toMediaCollection('documents');
ProcessDocumentOCR::dispatch($document->currentVersion);
}
return redirect()->back()->with('success', 'Files uploaded successfully');
}
/**
* Display the specified resource.
*/
public function show(Document $document)
{
$this->authorize('view', $document); // Si usas políticas
if (!Storage::exists($document->file_path)) {
abort(404);
}
$document->url = Storage::url($document->file_path);
$document->load('user');
return view('documents.show', [
'document' => $document,
'versions' => $document->versions()->latest()->get(),
'comments' => $this->comments,
]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Document $document)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Document $document)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Document $document)
{
//
}
public function upload(Request $request, Project $project)
{
$request->validate([
'files.*' => 'required|mimes:pdf,docx,xlsx,jpeg,png|max:2048'
]);
foreach ($request->file('files') as $file) {
$document = $project->documents()->create([
'name' => $file->getClientOriginalName(),
'status' => 0
]);
$this->createVersion($document, $file);
}
}
private function createVersion(Document $document, $file)
{
$version = $document->versions()->create([
'file_path' => $file->store("projects/{$document->project_id}/documents"),
'hash' => hash_file('sha256', $file),
'user_id' => auth()->id()
]);
$document->update(['current_version_id' => $version->id]);
}
/**
* Actualizar PDF con anotaciones, firmas y sellos
*/
public function updatePdf(Request $request, Document $document)
{
$this->authorize('update', $document);
$request->validate([
'pdf_data' => 'required|string', // PDF modificado en base64
'annotations' => 'sometimes|array',
'signatures' => 'sometimes|array',
'stamps' => 'sometimes|array',
]);
try {
// Procesar el PDF modificado
$modifiedPdf = $this->processPdfData($request->pdf_data);
// Reemplazar el archivo original (sin crear nueva versión si no quieres)
$this->replaceOriginalPdf($document, $modifiedPdf);
// Opcional: también crear una nueva versión para historial
$newVersion = $this->createNewVersion($document, $modifiedPdf, $request->all());
return response()->json([
'success' => true,
'message' => 'PDF actualizado correctamente',
'version_id' => $newVersion->id ?? null,
]);
} catch (\Exception $e) {
\Log::error('Error updating PDF: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'Error al actualizar el PDF: ' . $e->getMessage()
], 500);
}
}
/**
* Procesar datos del PDF en base64
*/
private function processPdfData($pdfData)
{
// Eliminar el prefijo data:application/pdf;base64, si existe
$pdfData = preg_replace('/^data:application\/pdf;base64,/', '', $pdfData);
// Decodificar base64
$pdfContent = base64_decode($pdfData);
if (!$pdfContent) {
throw new \Exception('Datos PDF inválidos');
}
return $pdfContent;
}
/**
* Procesar PDF con anotaciones (método alternativo)
*/
private function processPdfWithAnnotations($document, $data)
{
// Aquí integrarías una librería PHP para PDF como spatie/pdf-to-image o setasign/fpdi
// Por ahora, devolvemos el contenido del archivo original
// En producción, implementarías la lógica de modificación
if ($document->currentVersion) {
$filePath = $document->currentVersion->file_path;
} else {
$filePath = $document->getFirstMedia('documents')->getPath();
}
if (!Storage::exists($filePath)) {
throw new \Exception('Archivo PDF no encontrado');
}
return Storage::get($filePath);
}
/**
* Reemplazar el PDF original
*/
private function replaceOriginalPdf($document, $pdfContent)
{
// Obtener la ruta del archivo original
$filePath = $document->file_path;
// Si el documento usa media library
if ($document->getFirstMedia('documents')) {
$media = $document->getFirstMedia('documents');
$media->update([
'file_name' => $document->name . '.pdf',
'size' => strlen($pdfContent),
]);
// Reemplazar el archivo
Storage::put($media->getPath(), $pdfContent);
} else {
// Si usas file_path directo
Storage::put($filePath, $pdfContent);
// Actualizar metadata del documento
$document->update([
'file_size' => strlen($pdfContent),
'updated_at' => now(),
]);
}
}
/**
* Crear nueva versión del documento
*/
private function createNewVersion($document, $pdfContent, $data = [])
{
$versionNumber = $document->versions()->count() + 1;
$fileName = "documents/{$document->id}/v{$versionNumber}.pdf";
// Guardar el nuevo PDF
Storage::put($fileName, $pdfContent);
// Crear registro de versión
$version = $document->versions()->create([
'version_number' => $versionNumber,
'file_path' => $fileName,
'file_size' => strlen($pdfContent),
'hash' => hash('sha256', $pdfContent),
'created_by' => auth()->id(),
'metadata' => [
'annotations_count' => count($data['annotations'] ?? []),
'signatures_count' => count($data['signatures'] ?? []),
'stamps_count' => count($data['stamps'] ?? []),
'edited_at' => now()->toISOString(),
'edited_by' => auth()->user()->name
]
]);
return $version;
}
/**
* Guardar metadatos de anotaciones
*/
private function saveAnnotationsMetadata($version, $data)
{
// Guardar anotaciones en la base de datos si es necesario
if (!empty($data['annotations'])) {
foreach ($data['annotations'] as $annotation) {
$version->annotations()->create([
'type' => $annotation['type'] ?? 'text',
'content' => $annotation['content'] ?? '',
'position' => $annotation['position'] ?? [],
'page' => $annotation['page'] ?? 1,
'created_by' => auth()->id()
]);
}
}
}
/**
* Subir firma
*/
public function uploadSignature(Request $request)
{
$request->validate([
'signature' => 'required|image|max:2048|mimes:png,jpg,jpeg'
]);
try {
$user = auth()->user();
$path = $request->file('signature')->store("signatures/{$user->id}", 'public');
// Opcional: Guardar en base de datos
$user->signatures()->create([
'file_path' => $path,
'file_name' => $request->file('signature')->getClientOriginalName()
]);
return response()->json([
'success' => true,
'path' => Storage::url($path),
'filename' => basename($path)
]);
} catch (\Exception $e) {
\Log::error('Error uploading signature: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'Error al subir la firma'
], 500);
}
}
/**
* Subir sello
*/
public function uploadStamp(Request $request)
{
$request->validate([
'stamp' => 'required|image|max:2048|mimes:png,jpg,jpeg'
]);
try {
$user = auth()->user();
$path = $request->file('stamp')->store("stamps/{$user->id}", 'public');
// Opcional: Guardar en base de datos
$user->stamps()->create([
'file_path' => $path,
'file_name' => $request->file('stamp')->getClientOriginalName(),
'type' => $request->type ?? 'custom'
]);
return response()->json([
'success' => true,
'path' => Storage::url($path),
'filename' => basename($path)
]);
} catch (\Exception $e) {
\Log::error('Error uploading stamp: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'Error al subir el sello'
], 500);
}
}
/**
* Obtener firmas del usuario
*/
public function getSignatures()
{
$user = auth()->user();
$signatures = $user->signatures()->get()->map(function($signature) {
return [
'id' => $signature->id,
'url' => Storage::url($signature->file_path),
'name' => $signature->file_name
];
});
return response()->json([
'success' => true,
'signatures' => $signatures
]);
}
/**
* Obtener sellos del usuario
*/
public function getStamps()
{
$user = auth()->user();
$stamps = $user->stamps()->get()->map(function($stamp) {
return [
'id' => $stamp->id,
'url' => Storage::url($stamp->file_path),
'name' => $stamp->file_name,
'type' => $stamp->type
];
});
return response()->json([
'success' => true,
'stamps' => $stamps
]);
}
/**
* Descargar documento
*/
public function download(Document $document, $versionId = null)
{
$this->authorize('view', $document);
$version = $versionId ?
$document->versions()->findOrFail($versionId) :
$document->currentVersion;
if (!$version || !Storage::exists($version->file_path)) {
abort(404);
}
return Storage::download($version->file_path, $document->name . '.pdf');
}
/**
* Obtener el PDF actual para edición
*/
public function getPdfForEditing(Document $document)
{
$this->authorize('view', $document);
try {
if ($document->getFirstMedia('documents')) {
$filePath = $document->getFirstMedia('documents')->getPath();
} else {
$filePath = $document->file_path;
}
if (!Storage::exists($filePath)) {
abort(404);
}
$pdfContent = Storage::get($filePath);
$base64Pdf = base64_encode($pdfContent);
return response()->json([
'success' => true,
'pdf_data' => $base64Pdf,
'document_name' => $document->name
]);
} catch (\Exception $e) {
\Log::error('Error getting PDF for editing: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'Error al cargar el PDF'
], 500);
}
}
}