暂存
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\Api;
|
||||
|
||||
use app\service\AdminAuthService;
|
||||
use InvalidArgumentException;
|
||||
use JsonException;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use Throwable;
|
||||
|
||||
class AdminAuthController
|
||||
{
|
||||
public function login(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$payload = $this->payload($request);
|
||||
$username = trim((string) ($payload['username'] ?? ''));
|
||||
$password = (string) ($payload['password'] ?? '');
|
||||
|
||||
if ($username === '' || $password === '') {
|
||||
throw new InvalidArgumentException('username and password are required.');
|
||||
}
|
||||
|
||||
$auth = new AdminAuthService();
|
||||
$user = $auth->authenticate($username, $password);
|
||||
if ($user === null) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 401,
|
||||
'message' => 'Admin login failed.',
|
||||
'errors' => ['auth' => 'invalid username or password.'],
|
||||
], 401);
|
||||
}
|
||||
|
||||
$auth->login($request, $user);
|
||||
} catch (JsonException $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 400,
|
||||
'message' => 'Invalid JSON body.',
|
||||
'errors' => ['body' => $exception->getMessage()],
|
||||
], 400);
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 422,
|
||||
'message' => 'Admin login validation failed.',
|
||||
'errors' => ['auth' => $exception->getMessage()],
|
||||
], 422);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Admin login failed.',
|
||||
'errors' => ['auth' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Admin login completed.',
|
||||
'data' => ['admin' => $user],
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function logout(Request $request): Response
|
||||
{
|
||||
try {
|
||||
(new AdminAuthService())->logout($request);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Admin logout failed.',
|
||||
'errors' => ['auth' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Admin logout completed.',
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function me(Request $request): Response
|
||||
{
|
||||
try {
|
||||
$admin = (new AdminAuthService())->current($request);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Admin session lookup failed.',
|
||||
'errors' => ['auth' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
if ($admin === null) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 401,
|
||||
'message' => 'Admin session not found.',
|
||||
], 401);
|
||||
}
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Admin session loaded.',
|
||||
'data' => ['admin' => $admin],
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
private function payload(Request $request): array
|
||||
{
|
||||
$rawBody = trim($request->rawBody());
|
||||
if ($rawBody === '') {
|
||||
return $request->post();
|
||||
}
|
||||
|
||||
$payload = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
|
||||
return is_array($payload) ? $payload : [];
|
||||
}
|
||||
|
||||
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']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\Api;
|
||||
|
||||
use app\service\AdminAuthService;
|
||||
use app\service\AdminConsole\AdminDocService;
|
||||
use app\service\AdminConsole\ArchiveAdminService;
|
||||
use app\service\AdminConsole\MaintenanceScriptService;
|
||||
use app\service\AdminConsole\OpenSearchAdminService;
|
||||
use app\service\AdminUserRepository;
|
||||
use InvalidArgumentException;
|
||||
use JsonException;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use Throwable;
|
||||
|
||||
class AdminConsoleController
|
||||
{
|
||||
public function archives(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = (new ArchiveAdminService())->list(
|
||||
trim((string) $request->get('query', '')),
|
||||
(int) $request->get('page', 1),
|
||||
(int) $request->get('page_size', 20),
|
||||
);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Archive list lookup failed.', ['archives' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('Archive list loaded.', $data);
|
||||
}
|
||||
|
||||
public function archive(Request $request, string $archiveUid): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$archive = (new ArchiveAdminService())->detail($archiveUid);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Archive lookup failed.', ['archive' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
if ($archive === null) {
|
||||
return $this->error(404, 'Archive not found.', ['archive_uid' => $archiveUid], 404);
|
||||
}
|
||||
|
||||
return $this->ok('Archive loaded.', $archive);
|
||||
}
|
||||
|
||||
public function updateArchive(Request $request, string $archiveUid): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$archive = (new ArchiveAdminService())->update($archiveUid, $this->payload($request));
|
||||
} catch (JsonException $exception) {
|
||||
return $this->error(400, 'Invalid JSON body.', ['body' => $exception->getMessage()], 400);
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
return $this->error(422, 'Archive update validation failed.', ['archive' => $exception->getMessage()], 422);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Archive update failed.', ['archive' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
if ($archive === null) {
|
||||
return $this->error(404, 'Archive not found.', ['archive_uid' => $archiveUid], 404);
|
||||
}
|
||||
|
||||
return $this->ok('Archive updated.', $archive);
|
||||
}
|
||||
|
||||
public function deleteArchive(Request $request, string $archiveUid): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$deleted = (new ArchiveAdminService())->delete($archiveUid);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Archive delete failed.', ['archive' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
if (!$deleted) {
|
||||
return $this->error(404, 'Archive not found.', ['archive_uid' => $archiveUid], 404);
|
||||
}
|
||||
|
||||
return $this->ok('Archive deleted.', ['archive_uid' => $archiveUid]);
|
||||
}
|
||||
|
||||
public function openSearchStatus(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$status = (new OpenSearchAdminService())->status();
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'OpenSearch status lookup failed.', ['opensearch' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('OpenSearch status loaded.', $status);
|
||||
}
|
||||
|
||||
public function openSearchDocuments(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$documents = (new OpenSearchAdminService())->documents(
|
||||
trim((string) $request->get('query', '')),
|
||||
(int) $request->get('size', 20),
|
||||
);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'OpenSearch document lookup failed.', ['opensearch' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('OpenSearch documents loaded.', $documents);
|
||||
}
|
||||
|
||||
public function users(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$users = (new AdminUserRepository())->listAll();
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Admin users lookup failed.', ['users' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('Admin users loaded.', ['items' => array_map(fn (array $user): array => $this->sanitizeUser($user), $users)]);
|
||||
}
|
||||
|
||||
public function createUser(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$payload = $this->payload($request);
|
||||
$username = trim((string) ($payload['username'] ?? ''));
|
||||
$password = trim((string) ($payload['password'] ?? ''));
|
||||
$displayName = trim((string) ($payload['display_name'] ?? ''));
|
||||
|
||||
if ($username === '' || $password === '') {
|
||||
throw new InvalidArgumentException('username and password are required.');
|
||||
}
|
||||
|
||||
$repository = new AdminUserRepository();
|
||||
if ($repository->findAnyByUsername($username)) {
|
||||
throw new InvalidArgumentException('username already exists.');
|
||||
}
|
||||
|
||||
$user = $repository->create($username, $password, $displayName !== '' ? $displayName : null);
|
||||
} catch (JsonException $exception) {
|
||||
return $this->error(400, 'Invalid JSON body.', ['body' => $exception->getMessage()], 400);
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
return $this->error(422, 'Admin user creation validation failed.', ['user' => $exception->getMessage()], 422);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Admin user creation failed.', ['user' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('Admin user created.', ['user' => $this->sanitizeUser($user)]);
|
||||
}
|
||||
|
||||
public function updateUser(Request $request, int $id): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$payload = $this->payload($request);
|
||||
$repository = new AdminUserRepository();
|
||||
if ($repository->findAnyById($id) === null) {
|
||||
return $this->error(404, 'Admin user not found.', ['id' => $id], 404);
|
||||
}
|
||||
|
||||
$updates = [];
|
||||
if (array_key_exists('display_name', $payload)) {
|
||||
$updates['display_name'] = $payload['display_name'];
|
||||
}
|
||||
if (array_key_exists('password', $payload)) {
|
||||
$updates['password'] = $payload['password'];
|
||||
}
|
||||
if (array_key_exists('is_active', $payload)) {
|
||||
$updates['is_active'] = (bool) $payload['is_active'];
|
||||
}
|
||||
|
||||
$user = $repository->updateUser($id, $updates);
|
||||
} catch (JsonException $exception) {
|
||||
return $this->error(400, 'Invalid JSON body.', ['body' => $exception->getMessage()], 400);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Admin user update failed.', ['user' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('Admin user updated.', ['user' => $this->sanitizeUser($user ?? [])]);
|
||||
}
|
||||
|
||||
public function docs(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$docs = (new AdminDocService())->list();
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'API docs lookup failed.', ['docs' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('API docs loaded.', ['items' => $docs]);
|
||||
}
|
||||
|
||||
public function doc(Request $request, string $name): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$doc = (new AdminDocService())->read($name);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(404, 'API doc not found.', ['doc' => $exception->getMessage()], 404);
|
||||
}
|
||||
|
||||
return $this->ok('API doc loaded.', $doc);
|
||||
}
|
||||
|
||||
public function scripts(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
return $this->ok('Maintenance scripts loaded.', ['items' => (new MaintenanceScriptService())->list()]);
|
||||
}
|
||||
|
||||
public function script(Request $request, string $name): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$script = (new MaintenanceScriptService())->describe($name);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(404, 'Maintenance script not found.', ['script' => $exception->getMessage()], 404);
|
||||
}
|
||||
|
||||
return $this->ok('Maintenance script loaded.', $script);
|
||||
}
|
||||
|
||||
public function runScript(Request $request): Response
|
||||
{
|
||||
if ($guard = $this->guard($request)) {
|
||||
return $guard;
|
||||
}
|
||||
|
||||
try {
|
||||
$payload = $this->payload($request);
|
||||
$scriptName = trim((string) ($payload['script_name'] ?? ''));
|
||||
$args = $payload['args'] ?? [];
|
||||
|
||||
if ($scriptName === '') {
|
||||
throw new InvalidArgumentException('script_name is required.');
|
||||
}
|
||||
if (!is_array($args)) {
|
||||
throw new InvalidArgumentException('args must be an array.');
|
||||
}
|
||||
|
||||
$result = (new MaintenanceScriptService())->run($scriptName, $args);
|
||||
} catch (JsonException $exception) {
|
||||
return $this->error(400, 'Invalid JSON body.', ['body' => $exception->getMessage()], 400);
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
return $this->error(422, 'Script execution validation failed.', ['script' => $exception->getMessage()], 422);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->error(500, 'Script execution failed.', ['script' => $exception->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->ok('Maintenance script finished.', $result);
|
||||
}
|
||||
|
||||
private function guard(Request $request): ?Response
|
||||
{
|
||||
return (new AdminAuthService())->current($request) === null
|
||||
? $this->error(401, 'Admin session not found.', [], 401)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
private function payload(Request $request): array
|
||||
{
|
||||
$rawBody = trim($request->rawBody());
|
||||
if ($rawBody === '') {
|
||||
return $request->post();
|
||||
}
|
||||
|
||||
$payload = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
|
||||
return is_array($payload) ? $payload : [];
|
||||
}
|
||||
|
||||
private function ok(string $message, array $data): Response
|
||||
{
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => $message,
|
||||
'data' => $data,
|
||||
], 200);
|
||||
}
|
||||
|
||||
private function error(int $code, string $message, array $errors = [], int $status = 500): Response
|
||||
{
|
||||
return $this->jsonResponse([
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
'errors' => $errors,
|
||||
], $status);
|
||||
}
|
||||
|
||||
private function sanitizeUser(array $user): array
|
||||
{
|
||||
unset($user['password_hash']);
|
||||
return $user;
|
||||
}
|
||||
|
||||
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']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\Api;
|
||||
|
||||
use app\service\ArchiveRepository;
|
||||
use support\Response;
|
||||
use Throwable;
|
||||
|
||||
class EvidenceController
|
||||
{
|
||||
public function archive(string $archiveUid): Response
|
||||
{
|
||||
try {
|
||||
$archive = (new ArchiveRepository())->findArchive($archiveUid);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Archive lookup failed.',
|
||||
'errors' => ['archive' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
if ($archive === null) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 404,
|
||||
'message' => 'Archive not found.',
|
||||
'errors' => ['archive_uid' => $archiveUid],
|
||||
], 404);
|
||||
}
|
||||
|
||||
$archive['chunk_count'] = is_array($archive['chunks'] ?? null) ? count($archive['chunks']) : 0;
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Archive loaded.',
|
||||
'data' => $archive,
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function chunk(string $chunkUid): Response
|
||||
{
|
||||
try {
|
||||
$chunk = (new ArchiveRepository())->findChunk($chunkUid);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Chunk lookup failed.',
|
||||
'errors' => ['chunk' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
if ($chunk === null) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 404,
|
||||
'message' => 'Chunk not found.',
|
||||
'errors' => ['chunk_uid' => $chunkUid],
|
||||
], 404);
|
||||
}
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Chunk loaded.',
|
||||
'data' => $chunk,
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function archiveChunks(string $archiveUid): Response
|
||||
{
|
||||
try {
|
||||
$repository = new ArchiveRepository();
|
||||
$archive = $repository->findArchive($archiveUid);
|
||||
$chunks = $archive === null ? [] : $repository->findArchiveChunks($archiveUid);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Archive chunks lookup failed.',
|
||||
'errors' => ['archive_chunks' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
if ($archive === null) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 404,
|
||||
'message' => 'Archive not found.',
|
||||
'errors' => ['archive_uid' => $archiveUid],
|
||||
], 404);
|
||||
}
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Archive chunks loaded.',
|
||||
'data' => [
|
||||
'archive_uid' => $archive['archive_uid'],
|
||||
'title' => $archive['title'],
|
||||
'summary' => $archive['summary'],
|
||||
'source' => $archive['source'],
|
||||
'author' => $archive['author'],
|
||||
'year' => $archive['year'],
|
||||
'series' => $archive['series'],
|
||||
'tags' => $archive['tags'],
|
||||
'chunk_count' => count($chunks),
|
||||
'chunks' => $chunks,
|
||||
],
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function evidence(string $chunkUid): Response
|
||||
{
|
||||
try {
|
||||
$chunk = (new ArchiveRepository())->findChunk($chunkUid);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Evidence lookup failed.',
|
||||
'errors' => ['evidence' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
if ($chunk === null) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 404,
|
||||
'message' => 'Evidence not found.',
|
||||
'errors' => ['chunk_uid' => $chunkUid],
|
||||
], 404);
|
||||
}
|
||||
|
||||
$archive = $chunk['archive'];
|
||||
$pages = $chunk['pages'];
|
||||
$pageLabel = $this->pageLabel($pages);
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Evidence loaded.',
|
||||
'data' => [
|
||||
'chunk_uid' => $chunk['chunk_uid'],
|
||||
'archive_uid' => $chunk['archive_uid'],
|
||||
'title' => $archive['title'] ?? null,
|
||||
'source' => $archive['source'] ?? null,
|
||||
'author' => $archive['author'] ?? null,
|
||||
'year' => $archive['year'] ?? null,
|
||||
'series' => $archive['series'] ?? null,
|
||||
'tags' => $archive['tags'] ?? [],
|
||||
'page_start' => $chunk['page_start'],
|
||||
'page_end' => $chunk['page_end'],
|
||||
'pages' => $pages,
|
||||
'page_label' => $pageLabel,
|
||||
'citation' => $this->citation($archive, $pageLabel),
|
||||
'quote' => $chunk['text'],
|
||||
'chunk' => [
|
||||
'chunk_index' => $chunk['chunk_index'],
|
||||
'length' => $chunk['length'],
|
||||
'embedding_model' => $chunk['embedding_model'],
|
||||
'embedding_status' => $chunk['embedding_status'],
|
||||
'search_index_status' => $chunk['search_index_status'],
|
||||
],
|
||||
],
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function archiveEvidence(string $archiveUid): Response
|
||||
{
|
||||
try {
|
||||
$repository = new ArchiveRepository();
|
||||
$archive = $repository->findArchive($archiveUid);
|
||||
$chunks = $archive === null ? [] : $repository->findArchiveChunks($archiveUid);
|
||||
} catch (Throwable $exception) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 500,
|
||||
'message' => 'Archive evidence lookup failed.',
|
||||
'errors' => ['archive_evidence' => $exception->getMessage()],
|
||||
], 500);
|
||||
}
|
||||
|
||||
if ($archive === null) {
|
||||
return $this->jsonResponse([
|
||||
'code' => 404,
|
||||
'message' => 'Archive not found.',
|
||||
'errors' => ['archive_uid' => $archiveUid],
|
||||
], 404);
|
||||
}
|
||||
|
||||
$evidence = array_map(function (array $chunk): array {
|
||||
$archive = $chunk['archive'];
|
||||
$pages = $chunk['pages'];
|
||||
$pageLabel = $this->pageLabel($pages);
|
||||
|
||||
return [
|
||||
'chunk_uid' => $chunk['chunk_uid'],
|
||||
'chunk_index' => $chunk['chunk_index'],
|
||||
'page_start' => $chunk['page_start'],
|
||||
'page_end' => $chunk['page_end'],
|
||||
'pages' => $pages,
|
||||
'page_label' => $pageLabel,
|
||||
'citation' => $this->citation($archive, $pageLabel),
|
||||
'quote' => $chunk['text'],
|
||||
'length' => $chunk['length'],
|
||||
'embedding_model' => $chunk['embedding_model'],
|
||||
'embedding_status' => $chunk['embedding_status'],
|
||||
'search_index_status' => $chunk['search_index_status'],
|
||||
];
|
||||
}, $chunks);
|
||||
|
||||
return $this->jsonResponse([
|
||||
'code' => 0,
|
||||
'message' => 'Archive evidence loaded.',
|
||||
'data' => [
|
||||
'archive_uid' => $archive['archive_uid'],
|
||||
'title' => $archive['title'],
|
||||
'summary' => $archive['summary'],
|
||||
'source' => $archive['source'],
|
||||
'author' => $archive['author'],
|
||||
'year' => $archive['year'],
|
||||
'series' => $archive['series'],
|
||||
'tags' => $archive['tags'],
|
||||
'chunk_count' => count($evidence),
|
||||
'evidence' => $evidence,
|
||||
],
|
||||
], 200);
|
||||
}
|
||||
|
||||
private function citation(array $archive, string $pageLabel): string
|
||||
{
|
||||
$parts = array_values(array_filter([
|
||||
$archive['title'] ?? null,
|
||||
$archive['author'] ?? null,
|
||||
isset($archive['year']) ? (string) $archive['year'] : null,
|
||||
$pageLabel === '' ? null : $pageLabel,
|
||||
$archive['source'] ?? null,
|
||||
], static fn ($value): bool => $value !== null && trim((string) $value) !== ''));
|
||||
|
||||
return implode(' | ', $parts);
|
||||
}
|
||||
|
||||
private function pageLabel(array $pages): string
|
||||
{
|
||||
if ($pages === []) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (count($pages) === 1) {
|
||||
return 'p. ' . (string) $pages[0];
|
||||
}
|
||||
|
||||
return 'pp. ' . (string) $pages[0] . '-' . (string) $pages[count($pages) - 1];
|
||||
}
|
||||
|
||||
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']
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user