Coverage for heritrace/apis/orcid.py: 100%
51 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-18 11:10 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-18 11:10 +0000
1from functools import lru_cache
2from urllib.parse import urlparse
4import requests
7def is_orcid_url(url):
8 """Check if a URL is an ORCID URL."""
9 try:
10 parsed = urlparse(url)
11 return parsed.netloc == "orcid.org" or parsed.netloc == "https://orcid.org"
12 except:
13 return False
16def extract_orcid_id(url):
17 """Extract ORCID ID from URL."""
18 try:
19 parsed = urlparse(url)
20 path = parsed.path.strip("/")
21 if path.startswith("https://orcid.org/"):
22 path = path[len("https://orcid.org/") :]
23 return path
24 except:
25 return None
28@lru_cache(maxsize=1000)
29def get_orcid_data(orcid_id):
30 """
31 Fetch researcher data from ORCID API with caching.
33 Args:
34 orcid_id (str): The ORCID identifier
36 Returns:
37 dict: Researcher data including name and other details
38 """
39 headers = {"Accept": "application/json"}
41 try:
42 response = requests.get(
43 f"https://pub.orcid.org/v3.0/{orcid_id}/person", headers=headers, timeout=5
44 )
46 if response.status_code == 200:
47 data = response.json()
49 # Extract relevant information
50 result = {
51 "name": None,
52 "other_names": [],
53 "biography": None,
54 "orcid": orcid_id,
55 }
57 # Get main name
58 if "name" in data:
59 given_name = data["name"].get("given-names", {}).get("value", "")
60 family_name = data["name"].get("family-name", {}).get("value", "")
61 if given_name or family_name:
62 result["name"] = f"{given_name} {family_name}".strip()
64 # Get other names
65 if "other-names" in data and "other-name" in data["other-names"]:
66 result["other_names"] = [
67 name.get("content", "")
68 for name in data["other-names"]["other-name"]
69 if "content" in name
70 ]
72 # Get biography
73 if "biography" in data and data["biography"]:
74 result["biography"] = data["biography"].get("content", "")
76 return result
78 except Exception:
79 return None
81 return None
84def format_orcid_attribution(url):
85 """
86 Format ORCID attribution for display.
88 Args:
89 url (str): The ORCID URL
91 Returns:
92 str: Formatted HTML for displaying ORCID attribution
93 """
95 orcid_id = extract_orcid_id(url)
96 if not orcid_id:
97 return f'<a href="{url}" target="_blank">{url}</a>'
99 researcher_data = get_orcid_data(orcid_id)
100 if not researcher_data:
101 return f'<a href="{url}" target="_blank">{url}</a>'
103 name = researcher_data["name"] or url
105 html = f'<a href="{url}" target="_blank" class="orcid-attribution">'
106 html += f'<img src="/static/images/orcid-logo.png" alt="ORCID iD" class="orcid-icon mx-1 mb-1" style="width: 16px; height: 16px;">'
107 html += f"{name} [orcid:{orcid_id}]</a>"
109 return html