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

1import json 

2import re 

3from typing import TYPE_CHECKING 

4 

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 

13 

14from mersenne_tools.models import DOAJBatch 

15 

16if TYPE_CHECKING: 

17 from ptf.models import Resource 

18 

19 

20def has_date_online_first(document): 

21 return hasattr(document, "date_online_first") and document.date_online_first 

22 

23 

24def has_date_published(document): 

25 return hasattr(document, "date_published") and document.date_published 

26 

27 

28def has_publication_date(document): 

29 return has_date_online_first(document) or has_date_published(document) 

30 

31 

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 

36 

37 

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 

53 

54 

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 

64 

65 

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 

70 

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 

74 

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 

77 

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 

81 

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) 

91 

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 

116 

117 

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 

132 

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 

137 

138 if collection.pid.startswith("CR") and not doi.startswith("10.5802/cr"): 

139 return None 

140 

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 

145 

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") 

152 

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 

159 

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" 

166 

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 "" 

172 

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) 

178 

179 keywords = [ 

180 kwd.value for kwd in document.kwd_set.all() if kwd.type != "msc" and kwd.lang == lang 

181 ] 

182 

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"}] 

190 

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"}) 

198 

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 

208 

209 

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 

215 

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" 

230 

231 

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) 

244 

245 

246def doaj_retrieve_applications(): 

247 application_ids = [ 

248 "798d4f21a22d43579cea322bed8a560e", 

249 "7a0889a89de64979a3d5e26aace31db7", 

250 "0e30bf1ac2514bcda8d1cc0855237cd4", 

251 "4bcd45d13d23475bb246cbce9eaed9ee", 

252 "d85467c6c5914759886aa29481cce4b4", 

253 "11b60f2f3dd64ec087510dff3d82e0ab", 

254 "71951ece12524e45abac7628de6a8d22", 

255 ] 

256 

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)