Download intake/scripts/test_doi_license.py from ICSAC-Institute/editorial-system: direct link, hf CLI and curl.
- Browser
- Download file 8.1 kB
-
https://huggingface.co/spaces/ICSAC-Institute/editorial-system/resolve/main/intake/scripts/test_doi_license.py
- Command line
-
hf download hf://spaces/ICSAC-Institute/editorial-system/intake/scripts/test_doi_license.py
-
curl -L -o test_doi_license.py https://huggingface.co/spaces/ICSAC-Institute/editorial-system/resolve/main/intake/scripts/test_doi_license.py
8.1 kB
| #!/usr/bin/env python3 | |
| """Checks for the article licence on the DOI route (2026-09-29): the author | |
| chooses the published article's licence; the preprint keeps its own, recorded | |
| beside it. Offline: the arXiv and Zenodo fetches are replaced by canned | |
| records, no mail, no pings; every write lands in one temporary directory that | |
| is removed at the end, pass or fail. Run from the repo root with the venv: | |
| .venv/bin/python intake/scripts/test_doi_license.py | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import hmac | |
| import json | |
| import shutil | |
| import sys | |
| import tempfile | |
| import time | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[2] | |
| sys.path.insert(0, str(ROOT)) | |
| TEST_ORCID = "0000-0002-1825-0097" | |
| failures: list[str] = [] | |
| def check(cond: bool, name: str) -> None: | |
| print((" ok " if cond else " FAIL ") + name) | |
| if not cond: | |
| failures.append(name) | |
| tmp = Path(tempfile.mkdtemp(prefix="doilicence-")) | |
| try: | |
| print("1. /api/submit (T2, signed like the proxy)") | |
| import httpx | |
| from fastapi.testclient import TestClient | |
| from intake import intake_server as iss | |
| import preprint_check | |
| # The DOI route checks its preprint at submit (2026-09-29); offline, a canned | |
| # DataCite preprint record stands in for the registries. | |
| preprint_check._get = lambda url, timeout: ( | |
| [{"DOI": "10.5281/zenodo.1", "RA": "DataCite"}] if "/ra/" in url else | |
| {"data": {"attributes": {"types": {"resourceTypeGeneral": "Preprint"}, "publisher": "Zenodo", | |
| "titles": [{"title": "T"}], "relatedIdentifiers": []}}}) | |
| iss.HMAC_SECRET = b"licence-test-secret" | |
| iss.TEST_ORCID_WHITELIST = frozenset({TEST_ORCID}) | |
| subs = tmp / "subs" | |
| iss.SUBMISSIONS_ROOT = subs | |
| iss.QUEUE_DIR = subs / "queue" | |
| iss.COUNTER_FILE = subs / ".counter" | |
| iss.TEST_SUBMISSIONS_ROOT = subs / "test" | |
| iss.TEST_QUEUE_DIR = subs / "test" / "queue" | |
| iss._audit_append = lambda entry, test_mode=False: None | |
| _n = iter(range(1792000000, 1792000100)) | |
| iss._allocate_test_sub_id = lambda: f"ICSAC-SUB-TEST-{next(_n)}" | |
| client = TestClient(iss.app) | |
| def post(data: dict) -> tuple[int, dict]: | |
| req = httpx.Request("POST", "http://intake/api/submit", data=data) | |
| body = req.read() | |
| ts = str(int(time.time())) | |
| # Signature v2 (2026-09-29): ts, ORCID, name (none sent), tier, then the body. | |
| sig = hmac.new(iss.HMAC_SECRET, f"icsac-v2\n{ts}\n{TEST_ORCID}\n\nt2\n".encode() + body, | |
| hashlib.sha256).hexdigest() | |
| resp = client.post("/api/submit", content=body, headers={ | |
| "content-type": req.headers["content-type"], "x-icsac-signature": f"v2={sig}", | |
| "x-icsac-timestamp": ts, "x-icsac-auth-orcid": TEST_ORCID, "x-icsac-test-tier": "t2"}) | |
| try: | |
| return resp.status_code, resp.json() | |
| except Exception: | |
| return resp.status_code, {"raw": resp.text[:300]} | |
| def record(resp: dict) -> dict: | |
| sid = resp.get("sub_id") or "" | |
| return json.loads((subs / "test" / sid / "submission.json").read_text()) if sid else {} | |
| def dirs() -> int: | |
| t = subs / "test" | |
| return len([p for p in t.iterdir() if p.name.startswith("ICSAC-SUB-TEST-")]) if t.exists() else 0 | |
| doi = {"mode": "doi", "name": "Test Author", "email": "author@example.com", "orcid": TEST_ORCID, | |
| "coi": "true", "exclusivity_acknowledged": "true", "code_data_available": "no", | |
| "doi": "10.5281/zenodo.1"} | |
| st, resp = post(dict(doi, license="cc-by-sa-4.0")) | |
| rec = record(resp) | |
| check(st in (200, 202) and rec.get("license") == "cc-by-sa-4.0" and rec.get("article_license") == "cc-by-sa-4.0", | |
| f"DOI route + CC BY-SA: the choice is stored ({st})") | |
| st, resp = post(dict(doi, license="CC-BY-4.0 ")) | |
| check(st in (200, 202) and record(resp).get("article_license") == "cc-by-4.0", "case and spaces are normalised") | |
| before = dirs() | |
| st, resp = post(dict(doi, license="cc-by-nc-4.0")) | |
| check(st == 400 and "license must be one of" in json.dumps(resp), f"a licence ICSAC does not offer is refused ({st})") | |
| check(dirs() == before, "a refused licence leaves no submission behind") | |
| st, resp = post(dict(doi)) | |
| rec = record(resp) | |
| check(st in (200, 202) and rec.get("license") == "" and rec.get("article_license") is None, | |
| "no licence sent (an older page): the record is as before") | |
| print("2. the worker's DOI resolution") | |
| from intake import submission_worker as worker | |
| ing = worker.ingest | |
| real = {k: getattr(ing, k) for k in ("is_arxiv_ref", "arxiv_ref_to_id", "fetch_arxiv_metadata", | |
| "download_arxiv_pdf", "doi_to_record_id", "fetch_metadata", | |
| "download_pdf", "extract_review_data")} | |
| def fake_pdf(dest_dir: str, name: str) -> str: | |
| p = Path(dest_dir) / name | |
| p.write_bytes(b"%PDF-1.4 test\n") | |
| return str(p) | |
| ing.fetch_arxiv_metadata = lambda i: {"title": "A", "description": "d", "keywords": [], "license": {"id": ""}, | |
| "creators": [{"name": "X"}], "publication_date": "2026-01-01"} | |
| ing.download_arxiv_pdf = lambda i, dest_dir=None: fake_pdf(dest_dir, f"{i}.pdf") | |
| ing.fetch_metadata = lambda rid: {"rid": rid} | |
| ing.download_pdf = lambda m, dest_dir=None: fake_pdf(dest_dir, "z.pdf") | |
| ing.extract_review_data = lambda m: {"title": "Z", "description": "d", "keywords": [], | |
| "license": {"id": "cc-by-nc-4.0"}, "creators": [{"name": "Y"}]} | |
| try: | |
| cases = ( | |
| ("arXiv, author chose CC BY", {"doi": "2401.12345", "article_license": "cc-by-4.0"}, "cc-by-4.0", ""), | |
| ("Zenodo CC BY-NC, author chose CC BY-SA", {"doi": "10.5281/zenodo.1", "article_license": "cc-by-sa-4.0"}, | |
| "cc-by-sa-4.0", "cc-by-nc-4.0"), | |
| ("Zenodo, no choice (older record)", {"doi": "10.5281/zenodo.1"}, "cc-by-nc-4.0", "cc-by-nc-4.0"), | |
| ) | |
| for k, (name, fields, want_lic, want_pre) in enumerate(cases): | |
| d = tmp / f"w{k}" | |
| d.mkdir() | |
| s = dict({"sub_id": f"ICSAC-SUB-TEST-{k}", "source": "doi", "pending_pdf_fetch": True, | |
| "form": {"name": "T"}, "license": fields.get("article_license", "")}, **fields) | |
| (d / "submission.json").write_text(json.dumps(s)) | |
| ok, why = worker._resolve_pending_doi(s["sub_id"], d, s) | |
| on_disk = json.loads((d / "submission.json").read_text()) | |
| check(ok and on_disk["license"] == want_lic and on_disk["preprint_license"] == want_pre | |
| and (d / "paper.pdf").exists(), | |
| f"{name}: licence {on_disk.get('license')!r}, preprint's {on_disk.get('preprint_license')!r}") | |
| finally: | |
| for k, v in real.items(): | |
| setattr(ing, k, v) | |
| print("3. the deposit and the curator summary") | |
| import crossref_deposit as cd | |
| sub = {"sub_id": "ICSAC-SUB-00099", "title": "T", "abstract": "A.", "source": "doi", "doi": "2401.12345", | |
| "license": "cc-by-sa-4.0", "article_license": "cc-by-sa-4.0", "preprint_license": "", | |
| "creators": [{"name": "Test, Author"}]} | |
| xml = cd.build_deposit_xml(sub, doi="10.5555/icsac.2026.099", landing_url="https://icsacinstitute.org/publications/t", | |
| pdf_url=None, content_type="journal-article") | |
| cd.validate_xml(xml) | |
| check(b"creativecommons.org/licenses/by-sa/4.0" in xml and b"hasPreprint" in xml, | |
| "the deposit carries the chosen licence and the preprint link, and validates") | |
| check(cd.LICENSE_LABELS.get("cc-by-sa-4.0"), "the acceptance email has a label for the chosen licence") | |
| src = (ROOT / "intake" / "apply_decision.py").read_text() | |
| check("(the author's choice); the preprint's" in src, "the curator summary shows both licences") | |
| finally: | |
| shutil.rmtree(tmp, ignore_errors=True) | |
| print(f"\n{'ALL GREEN' if not failures else f'{len(failures)} FAILURE(S)'}") | |
| sys.exit(1 if failures else 0) | |