Coverage for src / ptf_tools / doaj.py: 61%
197 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-07-07 12:08 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-07-07 12:08 +0000
1import json
2import re
3from typing import TYPE_CHECKING
5import requests
6from django.conf import settings
7from django.db.models import Q
8from django.http import Http404
9from ptf import model_helpers
10from ptf.cmds.xml.xml_utils import remove_html
11from ptf.models import Container
12from ptf.utils import is_cr
14from mersenne_tools.models import DOAJBatch
16if TYPE_CHECKING:
17 from ptf.models import Resource
20def has_date_online_first(document):
21 return hasattr(document, "date_online_first") and document.date_online_first
24def has_date_published(document):
25 return hasattr(document, "date_published") and document.date_published
28def has_publication_date(document):
29 return has_date_online_first(document) or has_date_published(document)
32def is_published(document):
33 if not hasattr(document, "do_not_publish"): 33 ↛ 34line 33 didn't jump to line 34 because the condition on line 33 was never true
34 return True
35 return not document.do_not_publish
38def get_names(resource, role):
39 names = []
40 for contribution in resource.contributions.all():
41 if contribution.role == role: 41 ↛ 40line 41 didn't jump to line 40 because the condition on line 41 was always true
42 person = {"name": str(contribution)}
43 addresses = contribution.contribaddress_set.all()
44 if addresses: 44 ↛ 45line 44 didn't jump to line 45 because the condition on line 44 was never true
45 person["affiliation"] = "; ".join([c.address for c in addresses if c.address])
46 if contribution.orcid: 46 ↛ 51line 46 didn't jump to line 51 because the condition on line 46 was always true
47 orcid = contribution.orcid.strip()
48 orcid = orcid.encode("ascii", "ignore").decode("utf-8")
49 if re.match(r"^\d{4}-\d{4}-\d{4}-\d{3}(\d|X)$", orcid): 49 ↛ 51line 49 didn't jump to line 51 because the condition on line 49 was always true
50 person["orcid_id"] = "https://orcid.org/" + orcid
51 names.append(person)
52 return names
55def get_token(colid):
56 token = None
57 if colid == "PCJ": 57 ↛ 58line 57 didn't jump to line 58 because the condition on line 57 was never true
58 token = settings.DOAJ_TOKEN_PCJ
59 elif colid == "OJMO": 59 ↛ 60line 59 didn't jump to line 60 because the condition on line 59 was never true
60 token = settings.DOAJ_TOKEN_OJMO
61 elif colid.startswith("CR") and len(colid) > 2: 61 ↛ 63line 61 didn't jump to line 63 because the condition on line 61 was always true
62 token = settings.DOAJ_TOKEN_CR
63 return token
66def doaj_pid_register(pid):
67 resource = model_helpers.get_resource(pid)
68 if not resource: 68 ↛ 69line 68 didn't jump to line 69 because the condition on line 68 was never true
69 raise Http404
71 container = None
72 if resource.classname == "Container": 72 ↛ 75line 72 didn't jump to line 75 because the condition on line 72 was always true
73 container = resource.container
75 if not container: 75 ↛ 76line 75 didn't jump to line 76 because the condition on line 75 was never true
76 raise Http404
78 collection = container.get_collection()
79 if not collection: 79 ↛ 80line 79 didn't jump to line 80 because the condition on line 79 was never true
80 raise Http404
82 results = []
83 data, response = None, None
84 token = get_token(collection.pid)
85 if token: 85 ↛ 92line 85 didn't jump to line 92 because the condition on line 85 was always true
86 for article in resource.container.article_set.all():
87 if is_published(article) and has_publication_date(article): 87 ↛ 86line 87 didn't jump to line 86 because the condition on line 87 was always true
88 data = doaj_resource_register(article)
89 if data:
90 results.append(data)
92 if results:
93 url = f"https://doaj.org/api/bulk/articles?api_key={token}"
94 response = requests.post(url, json=results)
95 container_batch = DOAJBatch.objects.get_or_create(resource=resource)[0]
96 if response.status_code == 201: 96 ↛ 97line 96 didn't jump to line 97 because the condition on line 96 was never true
97 container_batch.status = DOAJBatch.REGISTERED
98 results = response.json()
99 data = {
100 "doaj_status": response.status_code,
101 "doaj_message": [r["status"] for r in results],
102 "doaj_id": [r["id"] for r in results],
103 "doaj_location": [r["location"] for r in results],
104 }
105 for article in resource.container.article_set.all():
106 if is_published(article) and has_publication_date(article):
107 article_batch = DOAJBatch.objects.get_or_create(resource=article)[0]
108 article_batch.status = DOAJBatch.REGISTERED
109 article_batch.save()
110 else:
111 container_batch.status = DOAJBatch.ERROR
112 if response.text: 112 ↛ 114line 112 didn't jump to line 114 because the condition on line 112 was always true
113 container_batch.log = response.text
114 container_batch.save()
115 return data, response
118def doaj_resource_register(resource: "Resource"):
119 container = None
120 document = None
121 if resource.classname == "Article":
122 document = resource.article
123 container = document.my_container
124 fpage = document.fpage
125 lpage = document.lpage
126 elif resource.classname == "Container": 126 ↛ 131line 126 didn't jump to line 131 because the condition on line 126 was always true
127 document = resource.container
128 container = document
129 fpage = lpage = ""
130 else:
131 return None
133 doi = resource.doi
134 collection = container.get_collection()
135 if not doi or not collection: 135 ↛ 136line 135 didn't jump to line 136 because the condition on line 135 was never true
136 return None
138 if collection.pid.startswith("CR") and not doi.startswith("10.5802/cr"):
139 return None
141 month = year = ""
142 year = container.fyear
143 if container.lyear is not None: 143 ↛ 144line 143 didn't jump to line 144 because the condition on line 143 was never true
144 year = container.lyear
146 if has_date_online_first(document):
147 month = document.date_online_first.strftime("%B")
148 year = document.date_online_first.strftime("%Y")
149 elif has_date_published(document): 149 ↛ 150line 149 didn't jump to line 150 because the condition on line 149 was never true
150 month = document.date_published.strftime("%B")
151 year = document.date_published.strftime("%Y")
153 volume = number = ""
154 if not container.to_appear(): 154 ↛ 160line 154 didn't jump to line 160 because the condition on line 154 was always true
155 if container.volume: 155 ↛ 156line 155 didn't jump to line 156 because the condition on line 155 was never true
156 volume = container.volume
157 if container.number and not (is_cr() and container.number[0] == "G"): 157 ↛ 160line 157 didn't jump to line 160 because the condition on line 157 was always true
158 number = container.number
160 eissn = collection.e_issn
161 pissn = "" # collection.issn
162 colid = collection.pid.lower()
163 domain = settings.SITE_REGISTER[colid]["site_domain"]
164 if colid == "pcj": 164 ↛ 165line 164 didn't jump to line 165 because the condition on line 164 was never true
165 domain = "peercommunityjournal.org"
167 url = f"https://{domain}/articles/{doi}/"
168 lang = resource.lang if resource.lang and resource.lang != "und" else ""
169 authors = get_names(resource, "author")
170 publisher = container.my_publisher
171 pub_name = publisher.pub_name if publisher and publisher.pub_name else ""
173 data = {"admin": {}, "bibjson": {"journal": {}}}
174 data["admin"]["publisher_record_id"] = doi
175 data["bibjson"]["title"] = remove_html(document.title_tex)
176 data["bibjson"]["month"] = month
177 data["bibjson"]["year"] = str(year)
179 keywords = [
180 kwd.value for kwd in document.kwd_set.all() if kwd.type != "msc" and kwd.lang == lang
181 ]
183 abstract = (
184 document.abstract_set.all().filter(Q(lang="en") | Q(lang="und")).order_by("lang").first()
185 )
186 data["bibjson"]["abstract"] = remove_html(abstract.value_tex) if abstract else ""
187 data["bibjson"]["author"] = authors
188 data["bibjson"]["keywords"] = keywords
189 data["bibjson"]["link"] = [{"url": url, "type": "fulltext", "content_type": "HTML"}]
191 data["bibjson"]["identifier"] = [{"type": "doi", "id": doi}]
192 if eissn: 192 ↛ 193line 192 didn't jump to line 193 because the condition on line 192 was never true
193 data["bibjson"]["identifier"].append({"type": "eissn", "id": eissn})
194 if pissn: 194 ↛ 195line 194 didn't jump to line 195 because the condition on line 194 was never true
195 data["bibjson"]["identifier"].append({"type": "pissn", "id": pissn})
196 if not eissn and colid == "pcj": 196 ↛ 197line 196 didn't jump to line 197 because the condition on line 196 was never true
197 data["bibjson"]["identifier"].append({"type": "eissn", "id": "2804-3871"})
199 data["bibjson"]["journal"]["country"] = "FR"
200 data["bibjson"]["journal"]["title"] = collection.title_tex
201 data["bibjson"]["journal"]["start_page"] = fpage
202 data["bibjson"]["journal"]["end_page"] = lpage
203 data["bibjson"]["journal"]["language"] = [lang]
204 data["bibjson"]["journal"]["number"] = number
205 data["bibjson"]["journal"]["volume"] = volume
206 data["bibjson"]["journal"]["publisher"] = pub_name
207 return data
210def doaj_delete_article(doi):
211 colid = ""
212 resource = model_helpers.get_resource_by_doi(doi)
213 if resource:
214 colid = resource.article.my_container.get_collection().pid
216 token = get_token(colid)
217 url = f"https://doaj.org/api/search/articles/{doi}"
218 response = requests.get(url)
219 if response.status_code == 200:
220 results = response.json().get("results")
221 if results:
222 article_id = results[0].get("id", "")
223 url = f"https://doaj.org/api/articles/{article_id}?api_key={token}"
224 response = requests.delete(url)
225 if response.status_code == 204:
226 return doi + " deleted"
227 else:
228 return doi + " not found or article already deleted"
229 return doi + " deletion failed"
232def doaj_delete_articles_in_collection(colid, check_published=True):
233 for container in Container.objects.filter(pid__startswith=colid):
234 print(container)
235 for article in container.article_set.all():
236 try:
237 if check_published:
238 if is_published(article) and has_publication_date(article):
239 doaj_delete_article(article.doi)
240 else:
241 doaj_delete_article(article.doi)
242 except Exception as ex:
243 print(ex)
246def doaj_retrieve_applications():
247 application_ids = [
248 "798d4f21a22d43579cea322bed8a560e",
249 "7a0889a89de64979a3d5e26aace31db7",
250 "0e30bf1ac2514bcda8d1cc0855237cd4",
251 "4bcd45d13d23475bb246cbce9eaed9ee",
252 "d85467c6c5914759886aa29481cce4b4",
253 "11b60f2f3dd64ec087510dff3d82e0ab",
254 "71951ece12524e45abac7628de6a8d22",
255 ]
257 for app_id in application_ids:
258 response = requests.get("https://doaj.org/api/search/journals/" + app_id)
259 if response.status_code == 200:
260 results = response.json().get("results")
261 if results:
262 filename = results[0]["bibjson"]["title"] + ".json"
263 with open(filename, "w") as fio:
264 json.dump(results, fio)