feat(backend): rendimiento ORCID y autosync configurable

Reutiliza cliente HTTP ORCID, reduce consultas DB al sincronizar works y añade SYNC_* en settings y scheduler (cron mensual o intervalo). Actualiza backend/.env, frontend/.env y .env.example para despliegue.
This commit is contained in:
Mireya Cueto Garrido
2026-05-20 12:25:20 +02:00
parent 5e0b5c4289
commit 238742bda4
5 changed files with 114 additions and 50 deletions
+32 -26
View File
@@ -37,6 +37,7 @@ class ORCIDClient:
self.client_id = settings.ORCID_CLIENT_ID
self.client_secret = settings.ORCID_CLIENT_SECRET
self._token_cache: Optional[str] = None
self._http = httpx.Client(timeout=20.0)
self.token_url = endpoints["token_url"]
self.authorization_url = endpoints["authorization_url"]
self.base_url = endpoints["api_base_url"]
@@ -55,12 +56,11 @@ class ORCIDClient:
"scope": "/read-public",
}
with httpx.Client(timeout=20.0) as client:
response = client.post(self.token_url, data=data)
response.raise_for_status()
token = response.json()["access_token"]
self._token_cache = token
return token
response = self._http.post(self.token_url, data=data)
response.raise_for_status()
token = response.json()["access_token"]
self._token_cache = token
return token
# ---------------------------------------------------------
# Headers comunes
@@ -77,31 +77,28 @@ class ORCIDClient:
# ---------------------------------------------------------
def fetch_record(self, orcid_id: str) -> dict:
url = f"{self.base_url}/{orcid_id}/record"
with httpx.Client(timeout=20.0) as client:
response = client.get(url, headers=self._headers())
response.raise_for_status()
return response.json()
response = self._http.get(url, headers=self._headers())
response.raise_for_status()
return response.json()
# ---------------------------------------------------------
# 3. Consultar /works (summary)
# ---------------------------------------------------------
def fetch_works(self, orcid_id: str) -> dict:
url = f"{self.base_url}/{orcid_id}/works"
with httpx.Client(timeout=20.0) as client:
response = client.get(url, headers=self._headers())
response.raise_for_status()
return response.json()
response = self._http.get(url, headers=self._headers())
response.raise_for_status()
return response.json()
# ---------------------------------------------------------
# 4. Consultar /work/{put_code} (detalle)
# ---------------------------------------------------------
def fetch_work_detail(self, orcid_id: str, put_code: int) -> dict | None:
url = f"{self.base_url}/{orcid_id}/work/{put_code}"
with httpx.Client(timeout=20.0) as client:
response = client.get(url, headers=self._headers())
if response.status_code != 200:
return None
return response.json()
response = self._http.get(url, headers=self._headers())
if response.status_code != 200:
return None
return response.json()
# ---------------------------------------------------------
# OAuth 3-legged (authorization code)
@@ -147,27 +144,36 @@ class ORCIDClient:
"code": code,
"redirect_uri": redirect_uri,
}
with httpx.Client(timeout=20.0) as client:
response = client.post(self.token_url, data=data, headers={"Accept": "application/json"})
response.raise_for_status()
return response.json()
response = self._http.post(self.token_url, data=data, headers={"Accept": "application/json"})
response.raise_for_status()
return response.json()
# -------------------------------------------------------------------
# Funciones de módulo usadas en researchers.py
# -------------------------------------------------------------------
_shared_client: ORCIDClient | None = None
def get_orcid_client() -> ORCIDClient:
global _shared_client
if _shared_client is None:
_shared_client = ORCIDClient()
return _shared_client
def get_works_summary(orcid_id: str) -> dict:
client = ORCIDClient()
client = get_orcid_client()
return client.fetch_works(orcid_id)
def get_work_detail(orcid_id: str, put_code: int) -> dict | None:
client = ORCIDClient()
client = get_orcid_client()
return client.fetch_work_detail(orcid_id, put_code)
def get_record(orcid_id: str) -> dict:
client = ORCIDClient()
client = get_orcid_client()
return client.fetch_record(orcid_id)