134 lines
4.3 KiB
PHP
134 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace app\controller\Api;
|
|
|
|
use app\service\ArticleImportService;
|
|
use JsonException;
|
|
use support\Request;
|
|
use support\Response;
|
|
use Webman\Http\UploadFile;
|
|
use Throwable;
|
|
|
|
class ArticleImportController
|
|
{
|
|
public function import(Request $request): Response
|
|
{
|
|
try {
|
|
$payload = $this->payload($request);
|
|
} catch (JsonException $exception) {
|
|
return $this->jsonResponse([
|
|
'code' => 400,
|
|
'message' => 'Invalid JSON body.',
|
|
'errors' => ['body' => $exception->getMessage()],
|
|
], 400);
|
|
}
|
|
|
|
$service = new ArticleImportService();
|
|
$result = $service->import($payload);
|
|
|
|
if (!$result['ok']) {
|
|
return $this->jsonResponse([
|
|
'code' => 422,
|
|
'message' => 'Archive import validation failed.',
|
|
'errors' => $result['errors'],
|
|
], 422);
|
|
}
|
|
|
|
try {
|
|
$service->persistSnapshot($result['data']);
|
|
(new \app\service\ArchiveRepository())->saveImport($result['data']);
|
|
if (($result['data']['queue']['needs_ai_metadata'] ?? false) === true) {
|
|
(new \app\service\AiMetadataQueue())->push($result['data']['archive']['archive_uid']);
|
|
$result['data']['queue']['ai_metadata_enqueued'] = true;
|
|
}
|
|
} catch (Throwable $exception) {
|
|
return $this->jsonResponse([
|
|
'code' => 500,
|
|
'message' => 'Archive import data could not be saved.',
|
|
'errors' => ['storage' => $exception->getMessage()],
|
|
], 500);
|
|
}
|
|
|
|
return $this->jsonResponse([
|
|
'code' => 0,
|
|
'message' => 'Archive imported.',
|
|
'data' => $result['data'],
|
|
], 201);
|
|
}
|
|
|
|
/**
|
|
* @throws JsonException
|
|
*/
|
|
private function payload(Request $request): array
|
|
{
|
|
$payload = array_merge($request->get(), $request->post());
|
|
$file = $request->file('file');
|
|
|
|
if ($file instanceof UploadFile) {
|
|
if (!$file->isValid()) {
|
|
return $payload + ['file_error' => $file->getUploadErrorCode()];
|
|
}
|
|
|
|
$payload['content'] = file_get_contents($file->getPathname()) ?: '';
|
|
$payload['source'] = $payload['source'] ?? $file->getUploadName();
|
|
$payload['title'] = $payload['title'] ?? pathinfo($file->getUploadName() ?? '', PATHINFO_FILENAME);
|
|
$payload['metadata'] = $this->metadata($payload['metadata'] ?? null);
|
|
return $payload;
|
|
}
|
|
|
|
$rawBody = trim($request->rawBody());
|
|
if ($rawBody === '') {
|
|
$payload['metadata'] = $this->metadata($payload['metadata'] ?? null);
|
|
return $payload;
|
|
}
|
|
|
|
if ($this->isJsonRequest($request)) {
|
|
$jsonPayload = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
|
|
if (!is_array($jsonPayload)) {
|
|
return [];
|
|
}
|
|
|
|
$jsonPayload['metadata'] = $this->metadata($jsonPayload['metadata'] ?? null);
|
|
return $jsonPayload;
|
|
}
|
|
|
|
$payload['content'] = $rawBody;
|
|
$payload['source'] = $payload['source'] ?? 'raw-markdown';
|
|
$payload['metadata'] = $this->metadata($payload['metadata'] ?? null);
|
|
return $payload;
|
|
}
|
|
|
|
private function isJsonRequest(Request $request): bool
|
|
{
|
|
$contentType = strtolower($request->header('content-type', ''));
|
|
return str_contains($contentType, 'application/json') || str_contains($contentType, '+json');
|
|
}
|
|
|
|
private function metadata(mixed $metadata): array
|
|
{
|
|
if (is_array($metadata)) {
|
|
return $metadata;
|
|
}
|
|
|
|
if (!is_string($metadata) || trim($metadata) === '') {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
$decoded = json_decode($metadata, true, 512, JSON_THROW_ON_ERROR);
|
|
return is_array($decoded) ? $decoded : [];
|
|
} catch (JsonException) {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
private function jsonResponse(array $data, int $status): Response
|
|
{
|
|
return response(
|
|
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR),
|
|
$status,
|
|
['Content-Type' => 'application/json']
|
|
);
|
|
}
|
|
}
|