fixed import #42
3 changed files with 23 additions and 5 deletions
|
|
@ -19,7 +19,11 @@
|
||||||
"Bash(git add app/api/routers/runs.py app/services/arxiv/rate_limit.py tests/integration/test_run_lifecycle_consistency.py docs/website/package-lock.json)",
|
"Bash(git add app/api/routers/runs.py app/services/arxiv/rate_limit.py tests/integration/test_run_lifecycle_consistency.py docs/website/package-lock.json)",
|
||||||
"Bash(git push)",
|
"Bash(git push)",
|
||||||
"Bash(uvx ruff format --check app/api/routers/runs.py app/services/arxiv/rate_limit.py tests/integration/test_run_lifecycle_consistency.py)",
|
"Bash(uvx ruff format --check app/api/routers/runs.py app/services/arxiv/rate_limit.py tests/integration/test_run_lifecycle_consistency.py)",
|
||||||
"Bash(test -f docs/website/package-lock.json)"
|
"Bash(test -f docs/website/package-lock.json)",
|
||||||
|
"Bash(gh run list --branch openalex-size-reduction-scholar-hydration --limit 3 --json databaseId,status,conclusion,name,event)",
|
||||||
|
"Bash(gh run list --limit 10 --json databaseId,status,conclusion,name,event,headBranch)",
|
||||||
|
"Bash(gh run view 22554585841 --log-failed)",
|
||||||
|
"Bash(gh run rerun 22554585841 --failed)"
|
||||||
],
|
],
|
||||||
"additionalDirectories": [
|
"additionalDirectories": [
|
||||||
"/home/jv/src/personal/playground/scholar_scraper/scholar-scraper/frontend/src"
|
"/home/jv/src/personal/playground/scholar_scraper/scholar-scraper/frontend/src"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||||
|
|
||||||
from app.api.schemas.common import ApiMeta
|
from app.api.schemas.common import ApiMeta
|
||||||
|
|
||||||
|
|
@ -128,11 +128,20 @@ class DataExportEnvelope(BaseModel):
|
||||||
|
|
||||||
class DataImportRequest(BaseModel):
|
class DataImportRequest(BaseModel):
|
||||||
schema_version: int | None = None
|
schema_version: int | None = None
|
||||||
|
exported_at: str | None = None
|
||||||
scholars: list[ScholarExportItemData] = Field(default_factory=list)
|
scholars: list[ScholarExportItemData] = Field(default_factory=list)
|
||||||
publications: list[PublicationExportItemData] = Field(default_factory=list)
|
publications: list[PublicationExportItemData] = Field(default_factory=list)
|
||||||
|
|
||||||
model_config = ConfigDict(extra="forbid")
|
model_config = ConfigDict(extra="forbid")
|
||||||
|
|
||||||
|
@model_validator(mode="before")
|
||||||
|
@classmethod
|
||||||
|
def unwrap_export_envelope(cls, values: dict) -> dict: # type: ignore[override]
|
||||||
|
"""Accept the full export envelope format (with data/meta wrapper)."""
|
||||||
|
if isinstance(values, dict) and "data" in values and isinstance(values["data"], dict):
|
||||||
|
return values["data"]
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
class DataImportResultData(BaseModel):
|
class DataImportResultData(BaseModel):
|
||||||
scholars_created: int
|
scholars_created: int
|
||||||
|
|
|
||||||
|
|
@ -394,11 +394,16 @@ async function onImportFileSelected(event: Event): Promise<void> {
|
||||||
clearMessages();
|
clearMessages();
|
||||||
try {
|
try {
|
||||||
const raw = await file.text();
|
const raw = await file.text();
|
||||||
const parsed = JSON.parse(raw) as DataImportPayload;
|
let parsed = JSON.parse(raw);
|
||||||
if (!parsed || !Array.isArray(parsed.scholars) || !Array.isArray(parsed.publications)) {
|
// Accept the full export envelope (with data/meta wrapper)
|
||||||
|
if (parsed?.data && Array.isArray(parsed.data.scholars)) {
|
||||||
|
parsed = parsed.data;
|
||||||
|
}
|
||||||
|
const payload = parsed as DataImportPayload;
|
||||||
|
if (!payload || !Array.isArray(payload.scholars) || !Array.isArray(payload.publications)) {
|
||||||
throw new Error("Invalid import file: expected scholars[] and publications[] arrays.");
|
throw new Error("Invalid import file: expected scholars[] and publications[] arrays.");
|
||||||
}
|
}
|
||||||
const result = await importScholarData(parsed);
|
const result = await importScholarData(payload);
|
||||||
successMessage.value = importSummary(result);
|
successMessage.value = importSummary(result);
|
||||||
await loadScholars();
|
await loadScholars();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue