First commit
This commit is contained in:
214
app/Http/Controllers/Admin/DocumentController.php
Normal file
214
app/Http/Controllers/Admin/DocumentController.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Actions\Document\CreateDocumentAction;
|
||||
use App\Actions\Document\UploadNewVersionAction;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\StoreDocumentRequest;
|
||||
use App\Jobs\ReindexDocumentJob;
|
||||
use App\Models\Category;
|
||||
use App\Models\Document;
|
||||
use App\Models\DocumentVersion;
|
||||
use App\Services\KnowledgeBase\AuditService;
|
||||
use App\Services\KnowledgeBase\IngestionService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
use RuntimeException;
|
||||
|
||||
class DocumentController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AuditService $auditService,
|
||||
private readonly IngestionService $ingestionService,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$query = Document::with(['category', 'currentVersion'])
|
||||
->withCount('versions');
|
||||
|
||||
if ($request->filled('category_id')) {
|
||||
$query->where('category_id', $request->category_id);
|
||||
}
|
||||
|
||||
if ($request->filled('status')) {
|
||||
$query->where('status', $request->status);
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$query->where('title', 'like', '%' . $request->search . '%');
|
||||
}
|
||||
|
||||
$documents = $query->latest()->paginate(15)->withQueryString();
|
||||
$categories = Category::active()->ordered()->get();
|
||||
|
||||
return view('admin.documents.index', compact('documents', 'categories'));
|
||||
}
|
||||
|
||||
public function create(): View
|
||||
{
|
||||
$categories = Category::active()->ordered()->get();
|
||||
return view('admin.documents.create', compact('categories'));
|
||||
}
|
||||
|
||||
public function store(StoreDocumentRequest $request, CreateDocumentAction $action): RedirectResponse
|
||||
{
|
||||
try {
|
||||
$document = $action->execute(
|
||||
$request->validated(),
|
||||
$request->file('file')
|
||||
);
|
||||
|
||||
return redirect()
|
||||
->route('admin.documents.show', $document)
|
||||
->with('success', "Dokumen '{$document->title}' berjaya diupload dan sedang diproses.");
|
||||
} catch (RuntimeException $e) {
|
||||
return back()
|
||||
->withInput()
|
||||
->with('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show(Document $document): View
|
||||
{
|
||||
$document->load([
|
||||
'category',
|
||||
'versions.uploader',
|
||||
'currentVersion.chunks' => fn($q) => $q->limit(20),
|
||||
]);
|
||||
|
||||
return view('admin.documents.show', compact('document'));
|
||||
}
|
||||
|
||||
public function edit(Document $document): View
|
||||
{
|
||||
$categories = Category::active()->ordered()->get();
|
||||
return view('admin.documents.edit', compact('document', 'categories'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Document $document): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'title' => ['required', 'string', 'max:255'],
|
||||
'description' => ['nullable', 'string', 'max:1000'],
|
||||
'category_id' => ['required', 'exists:categories,id'],
|
||||
'effective_date' => ['nullable', 'date'],
|
||||
'expiry_date' => ['nullable', 'date'],
|
||||
'tags' => ['nullable', 'array'],
|
||||
'language' => ['nullable', 'in:ms,en'],
|
||||
]);
|
||||
|
||||
$validated['updated_by'] = auth()->id();
|
||||
$document->update($validated);
|
||||
|
||||
return redirect()
|
||||
->route('admin.documents.show', $document)
|
||||
->with('success', 'Maklumat dokumen berjaya dikemaskini.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload versi baru untuk dokumen yang sedia ada.
|
||||
*/
|
||||
public function uploadVersion(
|
||||
Request $request,
|
||||
Document $document,
|
||||
UploadNewVersionAction $action
|
||||
): RedirectResponse {
|
||||
$request->validate([
|
||||
'file' => ['required', 'file', 'mimes:pdf', 'max:' . config('knowledgebase.upload.max_file_size', 20480)],
|
||||
'change_notes' => ['nullable', 'string', 'max:500'],
|
||||
]);
|
||||
|
||||
try {
|
||||
$action->execute($document, $request->file('file'), $request->only('change_notes'));
|
||||
|
||||
return redirect()
|
||||
->route('admin.documents.show', $document)
|
||||
->with('success', 'Versi baru berjaya diupload dan sedang diproses.');
|
||||
} catch (RuntimeException $e) {
|
||||
return back()->with('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle status aktif/tidak aktif dokumen.
|
||||
* Apabila dinyahaktifkan, chunk dalam Qdrant juga dimatikan.
|
||||
*/
|
||||
public function toggleStatus(Document $document): RedirectResponse
|
||||
{
|
||||
$newStatus = !$document->is_active;
|
||||
|
||||
if ($newStatus) {
|
||||
// Aktifkan — versi semasa mesti sudah indexed
|
||||
$currentVersion = $document->currentVersion;
|
||||
if (!$currentVersion || !$currentVersion->isProcessed()) {
|
||||
return back()->with('error',
|
||||
'Dokumen tidak boleh diaktifkan kerana pemprosesan belum selesai.'
|
||||
);
|
||||
}
|
||||
|
||||
$document->update([
|
||||
'is_active' => true,
|
||||
'status' => Document::STATUS_ACTIVE,
|
||||
]);
|
||||
|
||||
$this->auditService->documentActivated($document);
|
||||
} else {
|
||||
// Deactivate — matikan juga dalam Qdrant
|
||||
$document->update([
|
||||
'is_active' => false,
|
||||
'status' => Document::STATUS_INACTIVE,
|
||||
]);
|
||||
|
||||
if ($currentVersion = $document->currentVersion) {
|
||||
$this->ingestionService->deactivateVersionInQdrant($currentVersion);
|
||||
}
|
||||
|
||||
$this->auditService->documentDeactivated($document);
|
||||
}
|
||||
|
||||
$status = $newStatus ? 'diaktifkan' : 'dinyahaktifkan';
|
||||
|
||||
return back()->with('success', "Dokumen '{$document->title}' telah {$status}.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger reindex untuk versi tertentu.
|
||||
*/
|
||||
public function reindex(Document $document): RedirectResponse
|
||||
{
|
||||
$currentVersion = $document->currentVersion;
|
||||
|
||||
if (!$currentVersion) {
|
||||
return back()->with('error', 'Tiada versi semasa untuk diindeks semula.');
|
||||
}
|
||||
|
||||
ReindexDocumentJob::dispatch($currentVersion->id);
|
||||
|
||||
$this->auditService->documentReindexed($document, $currentVersion);
|
||||
|
||||
return back()->with('success', 'Reindeks telah dimulakan. Sila semak semula sebentar lagi.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Download PDF asal.
|
||||
*/
|
||||
public function download(Document $document, DocumentVersion $version)
|
||||
{
|
||||
abort_if($version->document_id !== $document->id, 404);
|
||||
|
||||
$disk = config('knowledgebase.upload.storage_disk', 'local');
|
||||
|
||||
if (!Storage::disk($disk)->exists($version->stored_path)) {
|
||||
abort(404, 'Fail tidak dijumpai.');
|
||||
}
|
||||
|
||||
return Storage::disk($disk)->download(
|
||||
$version->stored_path,
|
||||
$version->original_filename
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user