Coverage for src/ptf/views/base_views.py: 49%

1588 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-05 09:56 +0000

1import csv 

2import html 

3import json 

4import os 

5import re 

6import string 

7import urllib.parse 

8from itertools import chain 

9from operator import itemgetter 

10 

11from bs4 import BeautifulSoup 

12from django_sendfile import sendfile 

13from munch import Munch 

14from requests.exceptions import RequestException 

15from requests.exceptions import Timeout 

16 

17from django.conf import settings 

18from django.contrib.syndication.views import Feed 

19from django.core.cache import cache 

20from django.core.exceptions import SuspiciousOperation 

21from django.core.files.temp import NamedTemporaryFile 

22from django.core.paginator import EmptyPage 

23from django.core.paginator import Paginator 

24from django.db.models import F 

25from django.db.models import Q 

26from django.db.models import Value 

27from django.db.models.functions import Greatest 

28from django.http import Http404 

29from django.http import HttpResponse 

30from django.http import HttpResponseBadRequest 

31from django.http import HttpResponseRedirect 

32from django.http import HttpResponseServerError 

33from django.http import JsonResponse 

34from django.shortcuts import get_object_or_404 

35from django.shortcuts import render 

36from django.urls import reverse 

37from django.utils import timezone 

38from django.utils.decorators import method_decorator 

39from django.utils.translation import get_language 

40from django.utils.translation import gettext_lazy as _ 

41from django.views.decorators.csrf import csrf_exempt 

42from django.views.decorators.http import require_http_methods 

43from django.views.generic import TemplateView 

44from django.views.generic import View 

45 

46from ..constants import PARAM_PREVIEW 

47from matching import crossref 

48from matching import matching 

49from ptf import citedby 

50from ptf import exceptions 

51from ptf import model_data 

52from ptf import model_data_converter 

53from ptf import model_helpers 

54from ptf import models 

55from ptf.cmds import ptf_cmds 

56from ptf.cmds import solr_cmds 

57from ptf.cmds import xml_cmds 

58from ptf.cmds.xml import xml_utils 

59from ptf.cmds.xml.ckeditor.ckeditor_parser import CkeditorParser 

60from ptf.cmds.xml.jats.builder.issue import get_title_xml 

61from ptf.cmds.xml.jats.jats_parser import get_tex_from_xml 

62from ptf.display import resolver 

63from ptf.display import utils 

64from ptf.model_data_converter import jats_from_abstract 

65from ptf.models import Article 

66from ptf.solr.search_helpers import CleanSearchURL 

67from ptf.templatetags.helpers import decode_query_string 

68from ptf.url_utils import format_url_with_params 

69from ptf.utils import highlight_diff 

70from ptf.views.components import breadcrumb 

71 

72# from django.utils.crypto import md5 

73# from django.utils import cache 

74# 

75# def ptf_generate_cache_key(request, method, headerlist, key_prefix): 

76# """Return a cache key from the headers given in the header list.""" 

77# url = md5(request.build_absolute_uri().encode("ascii"), usedforsecurity=False) 

78# cache_key = "views.decorators.cache.cache_page.%s.%s.%s" % ( 

79# key_prefix, 

80# method, 

81# url.hexdigest(), 

82# ) 

83# return cache_key 

84# 

85# 

86# def ptf_generate_cache_header_key(key_prefix, request): 

87# """Return a cache key for the header cache.""" 

88# url = md5(request.build_absolute_uri().encode("ascii"), usedforsecurity=False) 

89# cache_key = "views.decorators.cache.cache_header.%s.%s" % ( 

90# key_prefix, 

91# url.hexdigest(), 

92# ) 

93# return cache_key 

94# 

95# 

96# cache._generate_cache_key = ptf_generate_cache_key 

97# cache._generate_cache_header_key = ptf_generate_cache_header_key 

98 

99 

100def update_context_with_desc(context): 

101 online_first_cr = context.get("online_first_cr", False) 

102 context[ 

103 "online_first_desc_fr" 

104 ] = """<p>Les articles en « Première publication » ont été évalués par les pairs, acceptés et édités. Ils ont été mis en page et finalisés avec les corrections des auteurs et des relecteurs.</p>""" 

105 context[ 

106 "online_first_desc_fr" 

107 ] += """<p>Ces articles sont donc publiés dans leur forme finale et ont reçu un DOI (digital object identifier). Par conséquent, ils ne peuvent plus être modifiés après leur publication électronique. Toute correction qui pourrait être nécessaire doit être effectuée ultérieurement dans un erratum.</p>""" 

108 if not online_first_cr: 

109 context[ 

110 "online_first_desc_fr" 

111 ] += """<p>Dès que les articles sont affectés à un numéro de la revue, ils sont retirés de cette page.</p>""" 

112 

113 context[ 

114 "online_first_desc_en" 

115 ] = """<p>Online First articles have been peer-reviewed, accepted and edited. They have been formatted and finalized with corrections from authors and proofreaders.</p>""" 

116 context[ 

117 "online_first_desc_en" 

118 ] += """<p>These articles appear in their final form and have been assigned a digital object identifier (DOI). Therefore, papers cannot be changed after electronic publication. Any corrections that might be necessary have to be made in an erratum.</p>""" 

119 if not online_first_cr: 

120 context[ 

121 "online_first_desc_en" 

122 ] += """<p>When the articles are assigned to an issue, they will be removed from this page.</p>""" 

123 

124 

125@require_http_methods(["POST"]) 

126def set_formula_display(request): 

127 next = request.headers.get("referer") 

128 # if formula-display is not in POST, then mathml is choosen 

129 formula_display = request.POST.get("formula-display", "mathml") 

130 request.session["formula_display"] = formula_display 

131 # redis session needs to save item in state 

132 request.session.save() 

133 

134 # to read session with redis-django-sessions 

135 # rdata = request.session.load() 

136 return HttpResponseRedirect(next) 

137 

138 

139# def views_get_collection(request, collection, api=False, *args, **kwargs): 

140# if not collection: 

141# raise Http404 

142# 

143# if collection.coltype in ['journal', 'acta']: 

144# return IssuesView.as_view()(request, jid=collection.pid) 

145# elif collection.coltype == 'these': 

146# return thesis(request) 

147# else: 

148# # en theorie: coltype=book-series TODO: check lectures 

149# url = ('series/"%s"/' % collection.title_html) + "p" 

150# path, queryDict = CleanSearchURL.decode(url) 

151# request.GET = queryDict 

152# request.path = path 

153# request.path_info = path 

154# return sorted_books(request) 

155 

156 

157# @require_http_methods(["GET"]) 

158# def container(request, pid, api=False): 

159# cont = model_helpers.get_container(pid) 

160# return views_get_container(request, cont, api) 

161 

162 

163def views_update_container_context(request, container, context, display_lang): 

164 if container is None: 164 ↛ 165line 164 didn't jump to line 165 because the condition on line 164 was never true

165 raise Http404 

166 

167 articles_to_appear = is_cr = False 

168 if hasattr(settings, "ISSUE_TO_APPEAR_PID") and settings.ISSUE_TO_APPEAR_PID == container.pid: 168 ↛ 169line 168 didn't jump to line 169 because the condition on line 168 was never true

169 context["articles_to_appear"] = articles_to_appear = True 

170 

171 if ( 

172 hasattr(settings, "SITE_NAME") 

173 and len(settings.SITE_NAME) == 6 

174 and settings.SITE_NAME[0:2] == "cr" 

175 ): 

176 context["is_cr"] = is_cr = True 

177 

178 context["online_first_cr"] = False 

179 if container.with_online_first and is_cr: 

180 context["articles_to_appear"] = articles_to_appear = True 

181 context["online_first_cr"] = True 

182 

183 collection = container.my_collection 

184 context["citing_articles"] = container.citations() 

185 context["source"] = request.GET.get("source", None) 

186 

187 context["breadcrumb"] = breadcrumb.get_breadcrumb(container) 

188 context["btn_show_tex"] = settings.SHOW_TEX if hasattr(settings, "SHOW_TEX") else False 

189 

190 if container.ctype.startswith("book") or container.ctype == "lecture-notes": 

191 book_parts = container.article_set.filter(sites__id=settings.SITE_ID).all().order_by("seq") 

192 

193 references = False 

194 if container.ctype == "book-monograph": 

195 # on regarde si il y a au moins une bibliographie 

196 for art in container.article_set.all(): 196 ↛ 197line 196 didn't jump to line 197 because the loop on line 196 never started

197 if art.bibitem_set.count() > 0: 

198 references = True 

199 context["references"] = references 

200 

201 context["book"] = container 

202 context["book_parts"] = list(book_parts) 

203 context["template"] = "blocks/book.html" 

204 

205 else: 

206 if articles_to_appear and is_cr: 

207 articles = container.article_set.all().order_by( 

208 F("date_online_first").desc(nulls_last=True), "-seq" 

209 ) 

210 

211 else: 

212 articles = container.article_set.all().order_by("seq") 

213 # TODO next_issue, previous_issue 

214 

215 context["issue"] = container 

216 context["articles"] = articles 

217 context["template"] = "blocks/issue-items.html" 

218 

219 # commun article ? 

220 context["coltype"] = collection.coltype 

221 context["supplementary_materials"] = models.SupplementaryMaterial.objects.filter( 

222 relatedobject_ptr__resource__pk=container.pk, 

223 ).filter(rel="supplementary-material") 

224 context["reviews"] = models.SupplementaryMaterial.objects.filter( 

225 relatedobject_ptr__resource__pk=container.pk, 

226 ).filter(rel="review") 

227 context["bibtex"] = container.get_bibtex(request) 

228 context["ris"] = container.get_ris(request) 

229 context["enw"] = container.get_endnote(request) 

230 context["howtocite"] = container.get_citation(request) 

231 # context['bibtex'] = article.get_bibtex(request.get_host()) pas la meme signature que pour article ? 

232 # context['howtocite'] = article.get_citation(request) 

233 

234 if collection.pid == "ART": 234 ↛ 235line 234 didn't jump to line 235 because the condition on line 234 was never true

235 qs = collection.content.filter(sites__id=settings.SITE_ID).order_by( 

236 "-vseries_int", "-year", "-volume_int", "number_int" 

237 ) 

238 if qs.exists(): 

239 last_issue = qs.first() 

240 if container.pid == last_issue.pid: 

241 context["last_issue"] = True 

242 

243 context["bs_version"] = ( 

244 settings.BOOTSTRAP_VERSION if hasattr(settings, "BOOTSTRAP_VERSION") else 3 

245 ) 

246 if container.ctype == "issue_special" and container.resources_in_special_issue: 246 ↛ 247line 246 didn't jump to line 247 because the condition on line 246 was never true

247 context["resource_in_special_issue"] = [ 

248 r.resource for r in container.resources_in_special_issue.all() 

249 ] 

250 

251 update_context_with_desc(context) 

252 

253 

254# def views_get_container(request, container, api=False, *args, **kwargs): 

255# context = {} 

256# views_update_container_context(request, container, context) 

257# template = context['template'] 

258# return render(request, template, context) 

259 

260 

261# class ContainerView(TemplateView): 

262# template_name = '' 

263# 

264# def get_context_data(self, **kwargs): 

265# context = super(ContainerView, self).get_context_data(**kwargs) 

266# 

267# if 'pid' in kwargs: 

268# pid = kwargs['pid'] 

269# else: 

270# pid = self.kwargs.get('pid') 

271# container = model_helpers.get_container(pid) 

272# if pid == getattr(settings, 'ISSUE_TO_APPEAR_PID', 'XXX') and not container: 

273# self.template_name = 'blocks/issue_detail_empty.html' 

274# else: 

275# views_update_container_context(self.request, container, context) 

276# self.template_name = context['template'] 

277# 

278# return context 

279 

280 

281# def views_get_article( 

282# request: HttpRequest, 

283# article: Optional[Article], 

284# api=False, 

285# lang=None, 

286# *args, 

287# **kwargs 

288# ): 

289# 

290# 

291# return render(request, template, context) 

292 

293 

294# @require_http_methods(["GET"]) 

295# def article(request: HttpRequest, aid: str, api=False): 

296# return ItemView.as_view()(request) 

297# 

298# 

299# @require_http_methods(["GET"]) 

300# def article_lang(request, lang, aid, api=False): 

301# return ItemView.as_view()(request) 

302 

303 

304class ItemView(TemplateView): 

305 def __init__(self, *args, **kwargs): 

306 super().__init__(*args, **kwargs) 

307 self.template_name = "" 

308 self.obj = None 

309 self.pid = None 

310 self.display_lang = None 

311 

312 def get_obj(self, **kwargs): 

313 self.pid = self.kwargs.get("aid", None) 

314 if self.pid is None: 

315 self.pid = self.kwargs.get("pid", None) 

316 if self.pid is None: 316 ↛ 317line 316 didn't jump to line 317 because the condition on line 316 was never true

317 self.pid = self.request.GET.get("id", "").replace("/", "") 

318 if "\x00" in self.pid: 318 ↛ 319line 318 didn't jump to line 319 because the condition on line 318 was never true

319 raise Http404 

320 

321 if "/" in self.pid: 

322 # If someone types /articles/10.5802/crgeos.150-fr, we set the display lang and get 10.5802/crgeos.150 

323 if not self.display_lang and self.pid[-3] == "-" and not self.pid[-2:].isdigit(): 323 ↛ 324line 323 didn't jump to line 324 because the condition on line 323 was never true

324 self.display_lang = self.pid[-2:] 

325 self.pid = self.pid[:-3] 

326 

327 obj = model_helpers.get_article_by_doi(self.pid, prefetch=True) 

328 else: 

329 obj = model_helpers.get_resource(self.pid, prefetch=True) 

330 if obj is not None: 

331 obj = obj.cast() 

332 fct = getattr(model_helpers, "get_" + obj.classname.lower()) 

333 if fct and callable(fct): 333 ↛ 336line 333 didn't jump to line 336 because the condition on line 333 was always true

334 obj = fct(self.pid, prefetch=True) 

335 

336 if obj is None and self.pid != getattr(settings, "ISSUE_TO_APPEAR_PID", "XXX"): 

337 raise Http404 

338 

339 self.obj = obj 

340 

341 def get_context_data(self, **kwargs): 

342 context = super().get_context_data(**kwargs) 

343 context["journal"] = self.obj.get_collection() 

344 context["obj"] = self.obj 

345 return context 

346 

347 def get(self, request, *args, **kwargs): 

348 if "obj" in kwargs: 

349 self.obj = kwargs["obj"] 

350 if "lang" in kwargs: 350 ↛ 351line 350 didn't jump to line 351 because the condition on line 350 was never true

351 self.display_lang = kwargs["lang"] 

352 

353 if ( 

354 self.obj is not None 

355 ): # ItemView may call ArticleView. Avoid infinite loop is self.obj is set 

356 return super().get(request, *args, **kwargs) 

357 

358 self.get_obj(**kwargs) 

359 if not self.display_lang: 359 ↛ 361line 359 didn't jump to line 361 because the condition on line 359 was always true

360 self.display_lang = self.kwargs.get("lang", None) 

361 view_cls = ItemViewClassFactory().get_resource_view(self.obj.classname) 

362 if view_cls is not None: 362 ↛ 367line 362 didn't jump to line 367 because the condition on line 362 was always true

363 kwargs["obj"] = self.obj 

364 if self.display_lang is not None: 364 ↛ 365line 364 didn't jump to line 365 because the condition on line 364 was never true

365 kwargs["lang"] = self.display_lang 

366 return view_cls.as_view()(request, *args, **kwargs) 

367 return super().get(request, *args, **kwargs) 

368 

369 

370class ArticleView(ItemView): 

371 def get_context_data(self, **kwargs): 

372 context = super().get_context_data(**kwargs) 

373 request = self.request 

374 display_lang = self.display_lang 

375 article = self.obj 

376 

377 article.title_tex = article.title_tex.strip() 

378 source = request.GET.get("source", None) 

379 container = article.my_container 

380 collection = container.my_collection 

381 citing_articles = article.citations() 

382 

383 with_tex = ( 

384 "formula_display" in request.session and request.session["formula_display"] == "tex" 

385 ) 

386 

387 if display_lang is not None and len(display_lang) == 2: 387 ↛ 388line 387 didn't jump to line 388 because the condition on line 387 was never true

388 context["display_lang"] = display_lang 

389 else: 

390 display_lang = context["display_lang"] = article.lang 

391 

392 context["collection"] = collection 

393 context["journal"] = collection 

394 context["is_translation"] = False 

395 context["full_translation"] = False 

396 context["needs_translation"] = True 

397 context["start_translation_url"] = os.path.join( 

398 settings.TRANSLATION_URL, f"translation/new?doi={article.doi}" 

399 ) 

400 langs = [article.lang] if (article.lang and article.lang != "und") else [] 

401 # if article.trans_lang and article.trans_lang != 'und': 

402 # langs.append(article.trans_lang) 

403 for translated_article in article.translations.all(): 403 ↛ 404line 403 didn't jump to line 404 because the loop on line 403 never started

404 if translated_article.lang not in langs: 

405 langs.append(translated_article.lang) 

406 if display_lang == translated_article.lang: 

407 context["is_translation"] = True 

408 context["needs_translation"] = False 

409 context["translated_article"] = translated_article 

410 context["body_html"] = translated_article.body_html 

411 

412 context["languages"] = langs 

413 

414 if display_lang == article.lang or ( 414 ↛ 424line 414 didn't jump to line 424 because the condition on line 414 was always true

415 not context["is_translation"] and display_lang != article.trans_lang 

416 ): 

417 context["article_title"] = article.title_tex if with_tex else article.title_html 

418 context["body_html"] = article.body_html 

419 if display_lang == article.lang: 419 ↛ 421line 419 didn't jump to line 421 because the condition on line 419 was always true

420 context["needs_translation"] = False 

421 for abstract in article.get_abstracts(): 421 ↛ 422line 421 didn't jump to line 422 because the loop on line 421 never started

422 if abstract.lang == display_lang: 

423 context["abstract"] = abstract 

424 elif display_lang == article.trans_lang or not context["is_translation"]: 

425 context["article_title"] = ( 

426 article.trans_title_tex if with_tex else article.trans_title_html 

427 ) 

428 context["article_original_title"] = ( 

429 article.title_tex if with_tex else article.title_html 

430 ) 

431 if "body_html" not in context or not context["body_html"]: 

432 # The full text is not available in the display_lang. Use the original version. 

433 context["body_html"] = article.body_html 

434 for abstract in article.get_abstracts(): 

435 if abstract.lang == display_lang: 

436 context["abstract"] = abstract 

437 else: 

438 context["full_translation"] = True 

439 context["article_original_title"] = ( 

440 article.title_tex if with_tex else article.title_html 

441 ) 

442 for translated_article in article.translations.all(): 

443 if display_lang == translated_article.lang: 

444 context["article_title"] = ( 

445 translated_article.title_tex if with_tex else translated_article.title_html 

446 ) 

447 context["abstract"] = translated_article.get_abstracts().first() 

448 

449 if context["is_translation"]: 449 ↛ 450line 449 didn't jump to line 450 because the condition on line 449 was never true

450 context["howtocite"] = translated_article.get_citation(request) 

451 else: 

452 context["howtocite"] = article.get_citation(request) 

453 

454 if ( 454 ↛ 458line 454 didn't jump to line 458

455 hasattr(settings, "ISSUE_TO_APPEAR_PID") 

456 and settings.ISSUE_TO_APPEAR_PID == container.pid 

457 ): 

458 context["articles_to_appear"] = True 

459 

460 # Format comment URL if comments are activated 

461 if getattr(settings, "COMMENTS_VIEWS_ARTICLE_COMMENTS", False) is True: 461 ↛ 462line 461 didn't jump to line 462 because the condition on line 461 was never true

462 current_url = f"{request.build_absolute_uri()}#article-comments-section" 

463 query_params = {"redirect_url": current_url} 

464 # Forward some query parameters if present 

465 preview_id = request.GET.get(PARAM_PREVIEW) 

466 if preview_id: 

467 query_params[PARAM_PREVIEW] = preview_id 

468 comment_reply_to = request.GET.get("commentReplyTo") 

469 if comment_reply_to: 

470 query_params["commentReplyTo"] = comment_reply_to 

471 

472 context["comments_url"] = format_url_with_params( 

473 reverse("article_comments", kwargs={"doi": article.doi}), query_params 

474 ) 

475 

476 is_cr = False 

477 if ( 477 ↛ 485line 477 didn't jump to line 485

478 hasattr(settings, "SITE_NAME") 

479 and len(settings.SITE_NAME) == 6 

480 and settings.SITE_NAME[0:2] == "cr" 

481 ): 

482 context["is_cr"] = is_cr = True 

483 context["related_articles"] = get_suggested_articles(article) 

484 

485 context["online_first_cr"] = False 

486 if container.with_online_first and is_cr: 

487 context["articles_to_appear"] = True 

488 context["online_first_cr"] = True 

489 

490 if hasattr(settings, "SHOW_BODY") and settings.SHOW_BODY: 490 ↛ 491line 490 didn't jump to line 491 because the condition on line 490 was never true

491 context["article_show_body"] = True 

492 

493 context["breadcrumb"] = breadcrumb.get_breadcrumb(article) 

494 context["btn_show_tex"] = settings.SHOW_TEX if hasattr(settings, "SHOW_TEX") else False 

495 

496 # pour les livres du centre Mersenne, on remplace la collection principale par collectionmembership 

497 if collection.pid == "MBK": 497 ↛ 498line 497 didn't jump to line 498 because the condition on line 497 was never true

498 for collection_membership in container.collectionmembership_set.all(): 

499 collection = collection_membership.collection 

500 container.my_collection = collection 

501 

502 if container.ctype == "issue": 502 ↛ 512line 502 didn't jump to line 512 because the condition on line 502 was always true

503 context.update( 

504 { 

505 "article": article, 

506 "citing_articles": citing_articles, 

507 "source": source, 

508 } 

509 ) 

510 context["template"] = "blocks/article.html" 

511 else: 

512 context.update( 

513 {"book_part": article, "citing_articles": citing_articles, "source": source} 

514 ) 

515 context["template"] = "blocks/book-part.html" 

516 

517 if hasattr(settings, "SITE_REGISTER"): 517 ↛ 535line 517 didn't jump to line 535 because the condition on line 517 was always true

518 site_entry = settings.SITE_REGISTER[settings.SITE_NAME] 

519 

520 licence = None 

521 try: 

522 year = int(article.my_container.year) 

523 except ValueError: 

524 year = 0 

525 

526 if "licences" in site_entry: 526 ↛ 533line 526 didn't jump to line 533 because the condition on line 526 was always true

527 licences = site_entry["licences"] 

528 i = len(licences) - 1 

529 while not licence and i >= 0: 

530 if year >= licences[i][0]: 

531 licence = licences[i][1] 

532 i -= 1 

533 context["licence"] = licence 

534 

535 context["coltype"] = collection.coltype 

536 context["supplementary_materials"] = models.SupplementaryMaterial.objects.filter( 

537 relatedobject_ptr__resource__pk=article.pk, 

538 ).filter(rel="supplementary-material") 

539 context["reviews"] = models.SupplementaryMaterial.objects.filter( 

540 relatedobject_ptr__resource__pk=article.pk, 

541 ).filter(rel="review") 

542 context["bibtex"] = article.get_bibtex(request) 

543 context["ris"] = article.get_ris(request) 

544 context["enw"] = article.get_endnote(request) 

545 link = model_helpers.get_extlink(resource=collection, rel="test_website") 

546 context["test_website"] = link.location if link else None 

547 link = model_helpers.get_extlink(resource=collection, rel="website") 

548 context["prod_website"] = link.location if link else None 

549 context["bs_version"] = ( 

550 settings.BOOTSTRAP_VERSION if hasattr(settings, "BOOTSTRAP_VERSION") else 3 

551 ) 

552 context["recommendations"] = article.extid_set.filter(id_type="rdoi") 

553 if article.used_in_special_issues.all(): 553 ↛ 554line 553 didn't jump to line 554 because the condition on line 553 was never true

554 context["special_issues"] = [ 

555 si.my_container for si in article.used_in_special_issues.all() 

556 ] 

557 # context["virtual_issues"] = container 

558 self.template_name = context["template"] 

559 

560 return context 

561 

562 

563class ContainerView(ItemView): 

564 def get_context_data(self, **kwargs): 

565 context = super().get_context_data(**kwargs) 

566 

567 if self.pid == getattr(settings, "ISSUE_TO_APPEAR_PID", "XXX") and not self.obj: 567 ↛ 568line 567 didn't jump to line 568 because the condition on line 567 was never true

568 self.template_name = "blocks/issue_detail_empty.html" 

569 else: 

570 container = self.obj 

571 if container is None: 571 ↛ 572line 571 didn't jump to line 572 because the condition on line 571 was never true

572 raise Http404 

573 

574 views_update_container_context(self.request, container, context, self.display_lang) 

575 

576 self.template_name = context["template"] 

577 

578 return context 

579 

580 

581class CollectionView(ItemView): 

582 def get(self, request, *args, **kwargs): 

583 if "obj" in kwargs: 583 ↛ 586line 583 didn't jump to line 586 because the condition on line 583 was always true

584 self.obj = kwargs["obj"] 

585 

586 collection = self.obj 

587 if collection.coltype in ["journal", "acta"]: 

588 return IssuesView.as_view()(request, jid=collection.pid) 

589 elif collection.coltype in ["lecture-notes"]: 589 ↛ 590line 589 didn't jump to line 590 because the condition on line 589 was never true

590 request.META["QUERY_STRING"] = '"' + collection.title_html + '"-p' 

591 return sorted_lectures_detailed_view(request) 

592 elif collection.coltype == "proceeding": 592 ↛ 593line 592 didn't jump to line 593 because the condition on line 592 was never true

593 url = reverse("proceeding-issues", kwargs={"jid": collection.pid}) 

594 return HttpResponseRedirect(url) 

595 # return proceedings(request, jid=collection.pid) 

596 else: 

597 # en theorie: coltype=book-series TODO: check lectures 

598 request.META["QUERY_STRING"] = '"' + collection.title_html + '"-p' 

599 return sorted_books(request) 

600 

601 

602class VolumeDetailView(TemplateView): 

603 template_name = "blocks/volume-items.html" 

604 

605 def get_context_data(self, **kwargs): 

606 # TODO next_volume, previous_volume 

607 context = super().get_context_data(**kwargs) 

608 

609 context["group_issues"] = False 

610 is_cr = ( 

611 hasattr(settings, "SITE_NAME") 

612 and len(settings.SITE_NAME) == 6 

613 and settings.SITE_NAME[0:2] == "cr" 

614 ) 

615 context["is_cr"] = is_cr 

616 

617 issues_articles, collection = model_helpers.get_issues_in_volume(kwargs.get("vid"), is_cr) 

618 year = int(issues_articles[0]["issue"].year.split("-")[0]) 

619 context["year"] = year 

620 

621 if is_cr: 

622 context["group_issues"] = (settings.SITE_NAME != "crbiol" and year > 2020) or ( 

623 settings.SITE_NAME == "crbiol" and year > 2022 

624 ) 

625 

626 with_thematic = ( 

627 len(issues_articles) > 1 and len(issues_articles[1]["issue"].title_html) > 0 

628 ) 

629 context["with_thematic"] = with_thematic 

630 

631 # Olivier 7/30/2020. Le code suivant crash lorsque fpage n'est pas un entier mais un chiffre romain 

632 # Il faut rediscuter des specs. Ordonner par 'seq' semble plus simple. 

633 # Il faut peut-être juste s'assurer que 'seq' soit bien mis à l'import ? 

634 

635 # Ex: /volume/WBLN_2018__5/ 

636 # issues_articles = [] 

637 # for issue in issues: 

638 # articles = issue.article_set.all().annotate( 

639 # fpage_int=Cast( 

640 # Case(When(~Q(fpage=''), then='fpage'), default=Value('0')), 

641 # IntegerField() 

642 # ) 

643 # ).order_by('seq', 'fpage_int') 

644 # 

645 # issues_articles.append({'issue': issue, 'articles': articles}) 

646 

647 context["issues_articles"] = issues_articles 

648 context["collection"] = collection 

649 context["journal"] = collection 

650 context["coltype"] = collection.coltype 

651 context["breadcrumb"] = breadcrumb.get_breadcrumb( 

652 issues_articles[-1].get("issue"), is_volume=True 

653 ) 

654 context["btn_show_tex"] = settings.SHOW_TEX if hasattr(settings, "SHOW_TEX") else False 

655 

656 if collection.pid == "ART": 656 ↛ 657line 656 didn't jump to line 657 because the condition on line 656 was never true

657 now = timezone.now() 

658 curyear = now.year 

659 context["volume_in_progress"] = year == curyear 

660 

661 return context 

662 

663 

664class VolumeGeneralDetailView(TemplateView): 

665 template_name = "blocks/volume-general-items.html" 

666 

667 def get_context_data(self, **kwargs): 

668 # TODO next_volume, previous_volume 

669 context = super().get_context_data(**kwargs) 

670 

671 context["group_issues"] = False 

672 is_cr = ( 

673 hasattr(settings, "SITE_NAME") 

674 and len(settings.SITE_NAME) == 6 

675 and settings.SITE_NAME[0:2] == "cr" 

676 ) 

677 context["is_cr"] = is_cr 

678 

679 issues_articles, collection = model_helpers.get_issues_in_volume( 

680 kwargs.get("vid"), is_cr, general_articles=True 

681 ) 

682 

683 if is_cr: 

684 year = int(issues_articles[0]["issue"].year) 

685 context["group_issues"] = (settings.SITE_NAME != "crbiol" and year > 2020) or ( 

686 settings.SITE_NAME == "crbiol" and year > 2022 

687 ) 

688 

689 with_thematic = ( 

690 len(issues_articles) > 1 and len(issues_articles[1]["issue"].title_html) > 0 

691 ) 

692 context["with_thematic"] = with_thematic 

693 

694 context["issues_articles"] = issues_articles 

695 context["collection"] = collection 

696 context["journal"] = collection 

697 context["coltype"] = collection.coltype 

698 context["breadcrumb"] = breadcrumb.get_breadcrumb(issues_articles[-1].get("issue")) 

699 context["btn_show_tex"] = settings.SHOW_TEX if hasattr(settings, "SHOW_TEX") else False 

700 context["vid"] = kwargs.get("vid") 

701 # for article in issues_articles: 

702 # for a in article["articles"]: 

703 # special = a.used_in_special_issues.all() 

704 # for s in special: 

705 # context["in_special"] = vars(s) 

706 # pass 

707 # pass 

708 context["request"] = self.request 

709 

710 return context 

711 

712 

713class ItemViewClassFactory: 

714 views = { 

715 "article": ArticleView, 

716 "container": ContainerView, 

717 "collection": CollectionView, 

718 "volume": VolumeDetailView, 

719 } 

720 

721 def get_resource_view(self, classname): 

722 classname = classname.lower() 

723 if classname in self.views: 723 ↛ 725line 723 didn't jump to line 725 because the condition on line 723 was always true

724 return self.views[classname] 

725 return None 

726 

727 

728@require_http_methods(["GET"]) 

729def journals(request, api=False): 

730 journals = model_helpers.get_journals().filter(parent=None).order_by("title_tex") 

731 

732 context = {"journals": journals, "coltype": "journal"} 

733 context["journal"] = model_helpers.get_collection(settings.COLLECTION_PID) 

734 

735 return render(request, "blocks/journal-list.html", context) 

736 

737 

738@require_http_methods(["GET"]) 

739def actas(request, api=False): 

740 journals = model_helpers.get_actas().filter(parent=None) 

741 context = {"journals": journals, "coltype": "acta"} 

742 

743 return render(request, "blocks/journal-list.html", context) 

744 

745 

746@require_http_methods(["GET"]) 

747def books(request, api=False): 

748 books = model_helpers.get_collection_of_books().order_by("title_tex") 

749 context = {"journals": books, "coltype": "book"} 

750 

751 return render(request, "blocks/journal-list.html", context) 

752 

753 

754@require_http_methods(["GET"]) 

755def proceedings(request): 

756 proceedings = model_helpers.get_proceedings().order_by("title_tex") 

757 context = {"journals": proceedings, "coltype": "proceeding"} 

758 

759 return render(request, "blocks/journal-list.html", context) 

760 

761 

762@require_http_methods(["GET"]) 

763def thesis(request): 

764 if request.GET: # i.e. /thesis?<search_term> 

765 return thesis_detailed_view(request) 

766 else: # /thesis 

767 thesis = model_helpers.get_collection_of_thesis().order_by("title_tex") 

768 context = {"journals": thesis, "coltype": "thesis"} 

769 

770 return render(request, "blocks/journal-list.html", context) 

771 

772 

773@require_http_methods(["GET"]) 

774def sorted_lectures(request): # i.e. /lectures?<search_term> 

775 if request.GET: 

776 return sorted_lectures_detailed_view(request) 

777 else: # /lectures 

778 lectures = model_helpers.get_lectures().order_by("title_tex") 

779 context = {"journals": lectures, "coltype": "lectures"} 

780 

781 return render(request, "blocks/journal-list.html", context) 

782 

783 

784@require_http_methods(["GET"]) 

785def thesis_detailed_view(request, sorted_by="fau", order_by="asc", api=False): 

786 # request.path like : thesis?C-"Thèses de l'entre-deux-guerres"-rp/ 

787 

788 decoded_query_string = decode_query_string(request) 

789 

790 path, queryDict = CleanSearchURL.decode(decoded_query_string, "/thesis") 

791 

792 request.GET = queryDict 

793 request.path = path 

794 request.path_info = path 

795 

796 filters = [] 

797 filters = request.GET.getlist("f") 

798 

799 path = request.path 

800 search_path = path + "?" 

801 

802 try: 

803 page = int(request.GET.get("page", 1)) 

804 except ValueError: 

805 page = 1 

806 

807 params = { 

808 "q": '(classname:"Thèse")', 

809 "sorted_by": sorted_by, 

810 "order_by": order_by, 

811 "page": page, 

812 "filters": filters, 

813 "path": path, 

814 "search_path": search_path, 

815 "facet_fields": ["firstLetter", "year_facet", "collection_title_facet"], 

816 "query": decoded_query_string, 

817 } 

818 

819 return generic_books(request, "thesis", params) 

820 

821 

822@require_http_methods(["GET"]) 

823def sorted_lectures_detailed_view( 

824 request, collection=None, sorted_by="fau title_sort_key", order_by="asc", api=False 

825): 

826 decoded_query_string = decode_query_string(request) 

827 

828 path, queryDict = CleanSearchURL.decode(decoded_query_string, "/lectures") 

829 

830 request.GET = queryDict 

831 request.path = path 

832 request.path_info = path 

833 

834 filters = [] 

835 filters = request.GET.getlist("f") 

836 

837 collection = model_helpers.get_collection(collection) 

838 

839 path = request.path 

840 search_path = path + "?" 

841 

842 try: 

843 page = int(request.GET.get("page", 1)) 

844 except ValueError: 

845 page = 1 

846 

847 params = { 

848 "q": '(classname:"Notes de cours")', 

849 "sorted_by": sorted_by, 

850 "order_by": order_by, 

851 "page": page, 

852 "filters": filters, 

853 "path": path, 

854 "search_path": search_path, 

855 "facet_fields": ["firstLetter", "year_facet", "collection_title_facet"], 

856 "query": decoded_query_string, 

857 } 

858 return generic_books(request, "lectures", params) 

859 

860 

861class IssuesView(TemplateView): 

862 template_name = "blocks/issue-list.html" 

863 

864 def get_context_data(self, **kwargs): 

865 context = super().get_context_data(**kwargs) 

866 

867 journal = model_helpers.get_collection(self.kwargs.get("jid"), sites="") 

868 

869 if journal is None: 869 ↛ 870line 869 didn't jump to line 870 because the condition on line 869 was never true

870 raise Http404 

871 try: 

872 current_edition = journal.extlink_set.get(rel="website").location 

873 if "numdam.org" in current_edition: 

874 current_edition = None 

875 except models.ExtLink.DoesNotExist: 

876 current_edition = None 

877 

878 result = model_helpers.get_volumes_in_collection(journal) 

879 volume_count = result["volume_count"] 

880 collections = [] 

881 for ancestor in journal.ancestors.all(): 881 ↛ 882line 881 didn't jump to line 882 because the loop on line 881 never started

882 item = model_helpers.get_volumes_in_collection(ancestor) 

883 volume_count = max(0, volume_count) 

884 item.update({"journal": ancestor}) 

885 collections.append(item) 

886 

887 # add the parent collection to its children list and sort it by date 

888 result.update({"journal": journal}) 

889 collections.append(result) 

890 if len(collections) > 1: 890 ↛ 891line 890 didn't jump to line 891 because the condition on line 890 was never true

891 collections.sort( 

892 key=lambda ancestor: ancestor["sorted_issues"][0]["volumes"][0]["lyear"], 

893 reverse=True, 

894 ) 

895 

896 is_cr = False 

897 if ( 897 ↛ 902line 897 didn't jump to line 902

898 hasattr(settings, "SITE_NAME") 

899 and len(settings.SITE_NAME) == 6 

900 and settings.SITE_NAME[0:2] == "cr" 

901 ): 

902 is_cr = True 

903 

904 display_with_titles = True 

905 i = 0 

906 while display_with_titles and i < len(collections): 

907 col = collections[i] 

908 if len(col["sorted_issues"]) != 1: 908 ↛ 909line 908 didn't jump to line 909 because the condition on line 908 was never true

909 display_with_titles = False 

910 else: 

911 j = 0 

912 volumes = col["sorted_issues"][0]["volumes"] 

913 while display_with_titles and j < len(volumes): 

914 vol = volumes[j] 

915 display_with_titles = len(vol["issues"]) == 1 

916 if display_with_titles: 916 ↛ 919line 916 didn't jump to line 919 because the condition on line 916 was always true

917 issue = vol["issues"][0] 

918 display_with_titles = issue.title_tex != "" 

919 j += 1 

920 i += 1 

921 # for vserie in result["sorted_issues"]: 

922 # for volume in vserie["volumes"]: 

923 # print(volume["issues"][0]) 

924 # if volume["issues"][0].ctype == "issue_special": 

925 # volume["issues"].reverse() 

926 # continue 

927 

928 context.update( 

929 { 

930 "obj": journal, 

931 "journal": journal, 

932 "sorted_issues": result["sorted_issues"], 

933 "coltype": journal.coltype, 

934 "volume_count": volume_count, 

935 "max_width": result["max_width"], 

936 "to_appear": models.Article.objects.filter(pid__startswith=f"{journal.pid}_0"), 

937 "show_issues": True, 

938 "is_cr": is_cr, 

939 "current_edition": current_edition, 

940 "collections": collections, 

941 "display_with_titles": display_with_titles, 

942 } 

943 ) 

944 update_context_with_desc(context) 

945 

946 return context 

947 

948 

949def generic_books(request, coltype, params): 

950 rows = 20 

951 start = (params["page"] - 1) * rows 

952 

953 params["rows"] = 20 

954 params["start"] = start 

955 if " " in params["sorted_by"]: 955 ↛ 959line 955 didn't jump to line 959 because the condition on line 955 was always true

956 sorts = params["sorted_by"].split() 

957 params["sort"] = ",".join([f"{item} {params['order_by']}" for item in sorts]) 

958 else: 

959 params["sort"] = params["sorted_by"] + " " + params["order_by"] 

960 

961 cmd = solr_cmds.solrInternalSearchCmd(params) 

962 results = cmd.do() 

963 # si len(results.facets['collection_title_facets']) == 1, 

964 # on est dans le cas où une collection est choisie 

965 

966 context = {"results": results, "coltype": coltype} 

967 

968 if results is not None: 968 ↛ 995line 968 didn't jump to line 995 because the condition on line 968 was always true

969 if results.facets["collection_title_facets"]: 969 ↛ 970line 969 didn't jump to line 970 because the condition on line 969 was never true

970 has_one_collection_filter = False 

971 collection_title_filter = "" 

972 if "filters" in params: 

973 for filter_ in params["filters"]: 

974 if filter_.find("collection_title_facet:") > -1: 

975 has_one_collection_filter = ( 

976 True if not has_one_collection_filter else False 

977 ) 

978 collection_title_filter = filter_.split('"')[1] 

979 

980 if has_one_collection_filter: 

981 obj = model_helpers.get_resource(results.docs[0]["pid"]) 

982 if obj: 

983 book = obj.cast() 

984 container = book.get_container() 

985 collection = container.get_collection() 

986 if collection.title_tex == collection_title_filter: 

987 context["collection"] = collection 

988 else: 

989 for other_collection in container.my_other_collections.all(): 

990 if other_collection.title_tex == collection_title_filter: 

991 context["collection"] = other_collection 

992 

993 context.update(utils.paginate_from_request(request, params, results.hits)) 

994 

995 context["query"] = params["query"] 

996 if settings.SITE_NAME == "numdam": 996 ↛ 997line 996 didn't jump to line 997 because the condition on line 996 was never true

997 context["numdam"] = True 

998 return render(request, "blocks/sorted-books.html", context) 

999 

1000 

1001@require_http_methods(["GET"]) 

1002def sorted_books(request, sorted_by="fau title_sort_key", order_by="asc", api=False): 

1003 decoded_query_string = decode_query_string(request) 

1004 path, queryDict = CleanSearchURL.decode(decoded_query_string, "/series") 

1005 

1006 request.GET = queryDict 

1007 request.path = path 

1008 request.path_info = path 

1009 

1010 filters = [] 

1011 filters = request.GET.getlist("f") 

1012 

1013 path = request.path 

1014 search_path = path + "?" 

1015 

1016 try: 

1017 page = int(request.GET.get("page", 1)) 

1018 except ValueError: 

1019 page = 1 

1020 

1021 params = { 

1022 "q": '(classname:"Livre")', 

1023 "sorted_by": sorted_by, 

1024 "order_by": order_by, 

1025 "page": page, 

1026 "filters": filters, 

1027 "path": path, 

1028 "search_path": search_path, 

1029 "facet_fields": ["firstLetter", "year_facet", "collection_title_facet"], 

1030 "query": decoded_query_string, 

1031 } 

1032 return generic_books(request, "book-series", params) 

1033 

1034 

1035@method_decorator(csrf_exempt, name="dispatch") 

1036class SearchView(TemplateView): 

1037 template_name = "blocks/search-results.html" 

1038 GET = None 

1039 path = None 

1040 

1041 def get(self, request, *args, **kwargs): 

1042 decoded_query_string = decode_query_string(request) 

1043 path = self.kwargs.get("path") 

1044 # query like test-"aitre, -ert"-qa 

1045 path, queryDict = CleanSearchURL.decode(decoded_query_string, path) 

1046 self.GET = queryDict 

1047 self.path = path 

1048 try: 

1049 result = super().get(request, *args, **kwargs) 

1050 except SuspiciousOperation: 

1051 result = HttpResponseBadRequest("Bad request") 

1052 

1053 return result 

1054 

1055 def post(self, request, *args, **kwargs): 

1056 if request.POST.get("q0", "") == "": 

1057 return HttpResponseRedirect(reverse("help")) 

1058 

1059 show_eprint = request.POST.get("show_eprint", False) 

1060 show_eprint = True if show_eprint == "on" else show_eprint 

1061 path = CleanSearchURL.encode(request.POST, request.path) 

1062 path += "&" + urllib.parse.urlencode({"eprint": show_eprint}) 

1063 

1064 return HttpResponseRedirect(path) 

1065 

1066 def get_context_data(self, **kwargs): 

1067 context = super().get_context_data(**kwargs) 

1068 

1069 raw_query_string = self.request.META.get("QUERY_STRING", "") 

1070 if raw_query_string: 

1071 decoded_query_string = urllib.parse.unquote(raw_query_string) 

1072 parse = urllib.parse.parse_qs(decoded_query_string) 

1073 context["query"] = decoded_query_string 

1074 eprint = False 

1075 

1076 try: 

1077 if "eprint" in parse: 

1078 eprint = eval(parse["eprint"][0]) 

1079 cache.set("eprint", eprint, 60 * 60 * 24 * 2) 

1080 except: 

1081 value = cache.get("eprint") 

1082 eprint = False if not value else value 

1083 finally: 

1084 cache.close() 

1085 

1086 filters = self.GET.getlist("f") 

1087 

1088 if eprint is False: 1088 ↛ 1091line 1088 didn't jump to line 1091 because the condition on line 1088 was always true

1089 filters.append('!dt:"e-print"') 

1090 

1091 search_path = self.path + "?" 

1092 qs = [] 

1093 

1094 keep_qs_in_display = True 

1095 i = 0 

1096 qti = self.GET.get("qt" + str(i), None) 

1097 

1098 while qti: 

1099 if i > 0: 

1100 search_path += "&" 

1101 search_path += "qt" + str(i) + "=" + qti 

1102 

1103 if qti == "date": 

1104 qfi = self.GET.get("q-f-" + str(i), None) 

1105 qli = self.GET.get("q-l-" + str(i), None) 

1106 

1107 if qfi or qli: 1107 ↛ 1132line 1107 didn't jump to line 1132 because the condition on line 1107 was always true

1108 qs.append({"name": qti, "first": qfi, "last": qli, "value": "", "not": False}) 

1109 

1110 search_path += "&q-f-" + str(i) + "=" + qfi 

1111 search_path += "&q-l-" + str(i) + "=" + qli 

1112 else: 

1113 if qti == "author_ref": 

1114 keep_qs_in_display = False 

1115 

1116 qi = self.GET.get("q" + str(i), None) 

1117 

1118 if qi or i == 0: 1118 ↛ 1132line 1118 didn't jump to line 1132 because the condition on line 1118 was always true

1119 noti = self.GET.get("not" + str(i), None) 

1120 if noti == "on": 

1121 noti = True 

1122 else: 

1123 noti = False 

1124 

1125 qs.append({"name": qti, "value": qi, "not": noti, "first": "", "last": ""}) 

1126 

1127 search_path += "&q" + str(i) + "=" + qi 

1128 

1129 if noti: 

1130 search_path += "&not" + str(i) + "=on" 

1131 

1132 i += 1 

1133 qti = self.GET.get("qt" + str(i), None) 

1134 

1135 try: 

1136 page = int(self.GET.get("page", 1)) 

1137 except ValueError: 

1138 page = 1 

1139 

1140 if len(qs) < 1: 

1141 # 400.html is used only if DEBUG is False 

1142 # (see get_response in django.core.handlers.base) 

1143 raise SuspiciousOperation("Bad request") 

1144 

1145 rows = 20 

1146 start = (page - 1) * rows 

1147 

1148 params = { 

1149 "filters": filters, 

1150 "qs": qs, 

1151 "page": page, 

1152 "start": start, 

1153 "rows": rows, 

1154 "search_path": search_path, 

1155 "path": self.path, 

1156 } 

1157 

1158 sort = self.GET.get("order_by") 

1159 if sort: 1159 ↛ 1160line 1159 didn't jump to line 1160 because the condition on line 1159 was never true

1160 params["sort"] = sort 

1161 

1162 cmd = solr_cmds.solrSearchCmd(params) 

1163 results = cmd.do() 

1164 

1165 if not keep_qs_in_display: 

1166 qs = [] 

1167 

1168 context.update({"results": results, "qs": qs, "eprint": eprint}) 

1169 

1170 if results is not None: 1170 ↛ 1173line 1170 didn't jump to line 1173 because the condition on line 1170 was always true

1171 context.update(utils.paginate_from_request(self, params, results.hits)) 

1172 

1173 context["journal"] = model_helpers.get_collection(settings.COLLECTION_PID) 

1174 

1175 return context 

1176 

1177 

1178@require_http_methods(["GET"]) 

1179def authors(request, api=False): 

1180 """ 

1181 @param request: like /authors?q=M+r 

1182 @param api: 

1183 @return: 

1184 """ 

1185 

1186 decoded_query_string = decode_query_string(request) 

1187 path, queryDict = CleanSearchURL.decode(decoded_query_string, "/authors") 

1188 

1189 request.GET = queryDict 

1190 request.path = path 

1191 request.path_info = path 

1192 

1193 # to set default value on letter 

1194 letter = request.GET.get("letter", "A")[0] 

1195 filters = request.GET.getlist("f") 

1196 for filter_ in filters: 1196 ↛ 1197line 1196 didn't jump to line 1197 because the loop on line 1196 never started

1197 if filter_.startswith("{!tag=firstletter}firstNameFacetLetter:"): 

1198 letter = filter_[39] 

1199 

1200 try: 

1201 page = int(request.GET.get("page", 1)) 

1202 except ValueError: 

1203 page = 1 

1204 

1205 rows = 60 

1206 

1207 all_authors = model_helpers.get_authors_by_letter(letter) 

1208 paginator = Paginator(all_authors, rows) 

1209 try: 

1210 authors = paginator.page(page) 

1211 except EmptyPage: 

1212 raise Http404 

1213 

1214 context = { 

1215 "authors": authors, 

1216 "letters": string.ascii_uppercase, 

1217 "letter_active": letter, 

1218 "query": decoded_query_string, 

1219 } 

1220 

1221 params = {"rows": rows, "page": page, "path": path} 

1222 context.update(utils.paginate_from_request(request, params, paginator.count)) 

1223 

1224 return render(request, "blocks/authors.html", context) 

1225 

1226 

1227@require_http_methods(["GET"]) 

1228def citations(request, aid, api=False): 

1229 resource = model_helpers.get_resource(aid) 

1230 if resource is None or (resource.classname != "Article" and resource.classname != "Container"): 

1231 raise Http404 

1232 # a priori les citations ne sont que sur les articles/book 

1233 # resource.classname != 'Article'-part : et ben non ! 

1234 item = resource.cast() 

1235 citing = item.citations() 

1236 context = {"resource": item} 

1237 context["citing"] = citing 

1238 return render(request, "blocks/resource-citations.html", context) 

1239 

1240 

1241@require_http_methods(["GET"]) 

1242def get_pdf(request, pid, binary_file_type, extension, relative_path): 

1243 """ 

1244 return PDF file of an Resource or of a RelatedObject for Container if embargo not present 

1245 si l'item n'existe pas : 404 

1246 si il est protege par barriere mobile : alors on renvoie vers 

1247 une page qui redirige apres un delai vers la notice de l'objet 

1248 """ 

1249 

1250 return get_binary_file(request, pid, binary_file_type, extension, relative_path) 

1251 

1252 

1253@require_http_methods(["GET"]) 

1254def get_binary_file(request, pid, binary_file_type, extension, relative_path): 

1255 """ 

1256 return tex file of a Resource if embargo not present 

1257 return 404 if the file or the resource does not exist 

1258 If there is an embargo redirect to the resource page 

1259 """ 

1260 

1261 if len(relative_path) > 0: 1261 ↛ 1262line 1261 didn't jump to line 1262 because the condition on line 1261 was never true

1262 extension = relative_path.split(".")[-1] 

1263 

1264 type_extension = { 

1265 "pdf": "application/pdf", 

1266 "djvu": "image/x.djvu", 

1267 "tex": "application/x-tex", 

1268 "png": "image/png", 

1269 "jpg": "image/jpeg", 

1270 "html": "text/html", 

1271 } 

1272 mimetype = type_extension.get(extension, "") 

1273 

1274 # binary_file_type: 'toc', 'frontmatter', 'backmatter', or 'self' for 

1275 # the article/issue binary file 

1276 if not binary_file_type: 

1277 binary_file_type = "self" 

1278 

1279 if "/" in pid: 1279 ↛ 1280line 1279 didn't jump to line 1280 because the condition on line 1279 was never true

1280 resource = model_helpers.get_resource_by_doi(pid) 

1281 else: 

1282 resource = model_helpers.get_resource(pid) 

1283 

1284 if resource is not None: 1284 ↛ 1287line 1284 didn't jump to line 1287 because the condition on line 1284 was always true

1285 resource = resource.cast() 

1286 

1287 filename, status = get_binary_filename(resource, relative_path, binary_file_type, mimetype) 

1288 return render_binary_file(request, resource, status, filename) 

1289 

1290 

1291def get_binary_filename(resource, relative_path, binary_file_type, mimetype): 

1292 """ 

1293 get the filename from the database 

1294 returns the filename and the status 200, 404 (not found) or 403 (embargo) 

1295 """ 

1296 if resource is None: 1296 ↛ 1297line 1296 didn't jump to line 1297 because the condition on line 1296 was never true

1297 return None, 404 

1298 

1299 allow_local_pdf = not hasattr(settings, "ALLOW_LOCAL_PDF") or settings.ALLOW_LOCAL_PDF 

1300 if not allow_local_pdf: 1300 ↛ 1301line 1300 didn't jump to line 1301 because the condition on line 1300 was never true

1301 return None, 404 

1302 

1303 filename = None 

1304 status = 200 

1305 

1306 try: 

1307 # May return None if there is an embargo 

1308 filename = resource.get_binary_disk_location(binary_file_type, mimetype, relative_path) 

1309 except exceptions.ResourceDoesNotExist: 

1310 status = 404 

1311 

1312 # File is protected 

1313 if filename is None: 

1314 status = 403 

1315 

1316 return filename, status 

1317 

1318 

1319def render_binary_file(request, resource, status, filename): 

1320 if status == 404: 1320 ↛ 1321line 1320 didn't jump to line 1321 because the condition on line 1320 was never true

1321 raise Http404 

1322 elif status == 403: 

1323 template_name = "403withRedirect.html" 

1324 response = render(request, template_name, {"pid": resource.pid}, status=403) 

1325 else: 

1326 full_filename = os.path.join(settings.RESOURCES_ROOT, filename) 

1327 

1328 try: 

1329 file_ = open(full_filename, "rb") 

1330 except OSError: 

1331 print("cannot open ", full_filename) 

1332 raise Http404 

1333 else: 

1334 response = sendfile(request, full_filename) 

1335 response["Accept-Ranges"] = "bytes" 

1336 file_.close() 

1337 return response 

1338 

1339 

1340########################################################################## 

1341# 

1342# Views that update model objects (besides import/upload) 

1343# 

1344########################################################################## 

1345class APILookupView(View): 

1346 def get(self, request): 

1347 title = request.GET["title"] 

1348 year = request.GET.get("year", False) 

1349 authors = request.GET.get("authors", False) 

1350 params = { 

1351 "qs": [ 

1352 {"name": "title", "value": title, "not": False, "first": "", "last": ""}, 

1353 ], 

1354 } 

1355 if year: 

1356 params["qs"].append( 

1357 {"name": "date", "value": None, "not": False, "first": year, "last": year}, 

1358 ) 

1359 if authors: 

1360 params["qs"].append( 

1361 {"name": "author", "value": authors, "not": False, "first": "", "last": ""}, 

1362 ) 

1363 cmd = solr_cmds.solrSearchCmd(params) 

1364 results = cmd.do() 

1365 if len(results.docs): 

1366 data = {"pid": results.docs[0]["pid"]} 

1367 else: 

1368 data = {} 

1369 return JsonResponse(data) 

1370 

1371 

1372class APIFetchView(View): 

1373 def get(self, request): 

1374 data = "" 

1375 pid = request.GET["pid"] 

1376 if pid: 

1377 article = get_object_or_404(models.Article, pid=pid) 

1378 data = article.get_citation(with_formatting=True) 

1379 return HttpResponse(data) 

1380 

1381 

1382class ArticlesAPIView(View): 

1383 def get(self, request): 

1384 # values_list returns queryset in format [('id',) ('id',)] 

1385 nested_article_pids = models.Article.objects.values_list("pid") 

1386 # We flatten it to a normal list ['id', 'id'] 

1387 article_pids = list(chain.from_iterable(nested_article_pids)) 

1388 return JsonResponse( 

1389 {"articles": {"ids": article_pids, "total": nested_article_pids.count()}} 

1390 ) 

1391 

1392 

1393class ArticleDumpAPIView(View): 

1394 def get(self, request, *args, **kwargs): 

1395 pid = kwargs.get("pid", None) 

1396 

1397 if "/" in pid: 1397 ↛ 1398line 1397 didn't jump to line 1398 because the condition on line 1397 was never true

1398 article = model_helpers.get_article_by_doi(pid, prefetch=True) 

1399 else: 

1400 article = model_helpers.get_article(pid, prefetch=True) 

1401 if not article: 1401 ↛ 1402line 1401 didn't jump to line 1402 because the condition on line 1401 was never true

1402 raise Http404 

1403 

1404 date_accepted = date_published = date_online_first = None 

1405 if article.date_accepted: 1405 ↛ 1407line 1405 didn't jump to line 1407 because the condition on line 1405 was always true

1406 date_accepted = article.date_accepted.strftime("%Y-%m-%d") 

1407 if article.date_online_first: 1407 ↛ 1409line 1407 didn't jump to line 1409 because the condition on line 1407 was always true

1408 date_online_first = article.date_online_first.strftime("%Y-%m-%d") 

1409 if article.date_published: 1409 ↛ 1411line 1409 didn't jump to line 1411

1410 date_published = article.date_published.strftime("%Y-%m-%d") 

1411 date_received = ( 

1412 article.date_received.strftime("%Y-%m-%d") if article.date_received else None 

1413 ) 

1414 date_revised = article.date_revised.strftime("%Y-%m-%d") if article.date_revised else None 

1415 

1416 author_names = models.get_names(article, "author") 

1417 if author_names: 1417 ↛ 1420line 1417 didn't jump to line 1420 because the condition on line 1417 was always true

1418 authors = "; ".join(author_names) 

1419 else: 

1420 author_names = models.get_names(article, "editor") 

1421 if author_names: 

1422 authors = "; ".join(author_names) + " (" + str(_("éd.")) + ")" 

1423 else: 

1424 authors = None 

1425 

1426 page_count = article.get_article_page_count() 

1427 

1428 result = { 

1429 "title_tex": article.title_tex, 

1430 "title_html": article.title_html, 

1431 "trans_title_tex": article.trans_title_tex, 

1432 "trans_title_html": article.trans_title_html, 

1433 "lang": article.lang, 

1434 "doi": article.doi or None, 

1435 "pid": article.pid, 

1436 "authors": authors, 

1437 "issue_pid": article.my_container.pid, 

1438 "colid": article.my_container.my_collection.pid, 

1439 "volume": article.my_container.volume, 

1440 "number": article.my_container.number, 

1441 "year": article.my_container.year, 

1442 "issue_title": article.my_container.title_tex, 

1443 "citation": article.get_citation(request), 

1444 "date_accepted": date_accepted, 

1445 "date_online_first": date_online_first, 

1446 "date_published": date_published, 

1447 "date_received": date_received, 

1448 "date_revised": date_revised, 

1449 "page_count": page_count, 

1450 "body_html": article.body_html, 

1451 "pci_section": article.get_pci_section(), 

1452 } 

1453 

1454 extids = [] 

1455 for extid in article.extid_set.all(): 

1456 extids.append([extid.id_type, extid.id_value]) 

1457 result["extids"] = extids 

1458 

1459 result["kwds"] = [ 

1460 {"type": kwd.type, "lang": kwd.lang, "value": kwd.value} 

1461 for kwd in article.kwd_set.all() 

1462 ] 

1463 

1464 awards = [] 

1465 for award in article.award_set.all(): 

1466 awards.append([award.abbrev, award.award_id]) 

1467 result["awards"] = awards 

1468 

1469 abstracts = [] 

1470 for abstract in article.abstract_set.all(): 

1471 abstracts.append( 

1472 { 

1473 "lang": abstract.lang, 

1474 "value_tex": abstract.value_tex, 

1475 "value_html": abstract.value_html, 

1476 } 

1477 ) 

1478 result["abstracts"] = abstracts 

1479 

1480 bibitems = [] 

1481 for bib in article.bibitem_set.all(): 

1482 bibitems.append(bib.citation_html) 

1483 result["bibitems"] = bibitems 

1484 

1485 return JsonResponse(result) 

1486 

1487 

1488class BookDumpAPIView(View): 

1489 def get(self, request, *args, **kwargs): 

1490 pid = kwargs.get("pid", None) 

1491 

1492 book = model_helpers.get_container(pid) 

1493 if not book: 1493 ↛ 1494line 1493 didn't jump to line 1494 because the condition on line 1493 was never true

1494 raise Http404 

1495 

1496 result = { 

1497 "title_tex": book.title_tex, 

1498 "title_html": book.title_html, 

1499 "doi": book.doi or "", 

1500 "citation": book.get_citation(request), 

1501 } 

1502 

1503 extids = [] 

1504 for extid in book.extid_set.all(): 

1505 extids.append([extid.id_type, extid.id_value]) 

1506 result["extids"] = extids 

1507 

1508 result["kwds"] = [ 

1509 {"type": kwd.type, "lang": kwd.lang, "value": kwd.value} for kwd in book.kwd_set.all() 

1510 ] 

1511 

1512 abstracts = [] 

1513 for abstract in book.abstract_set.all(): 

1514 abstracts.append( 

1515 { 

1516 "lang": abstract.lang, 

1517 "value_tex": abstract.value_tex, 

1518 "value_html": abstract.value_html, 

1519 } 

1520 ) 

1521 result["abstracts"] = abstracts 

1522 

1523 bibitems = [] 

1524 for bib in book.bibitem_set.all(): 

1525 bibitems.append(bib.citation_html) 

1526 result["bibitems"] = bibitems 

1527 

1528 return JsonResponse(result) 

1529 

1530 

1531class AllIssuesAPIView(View): 

1532 def get(self, request): 

1533 issues_pids = list(models.Container.objects.values_list("pid", flat=True).order_by("pid")) 

1534 return JsonResponse({"issues": issues_pids}) 

1535 

1536 

1537class CollectionIssnAPIView(View): 

1538 def get(self, request, *args, **kwargs): 

1539 collection = get_object_or_404( 

1540 models.Collection, 

1541 resourceid__id_value=kwargs.get("issn"), 

1542 ) 

1543 if collection.parent: 

1544 url = ( 

1545 "" 

1546 if collection.parent.pid == collection.pid 

1547 else collection.parent.get_absolute_url() 

1548 ) 

1549 url += f"#{collection.pid}" 

1550 return JsonResponse({"url": url}) 

1551 return JsonResponse({"url": collection.get_absolute_url()}) 

1552 

1553 

1554class CollectionsAPIView(View): 

1555 def get(self, request): 

1556 collections_pids = list( 

1557 models.Collection.objects.filter(parent__isnull=True).values_list("pid", flat=True) 

1558 ) 

1559 return JsonResponse({"collections": collections_pids}) 

1560 

1561 

1562class CollectionExportCSV(View): 

1563 def get(self, request, *args, **kwargs): 

1564 colid = kwargs.get("colid") 

1565 collection = get_object_or_404(models.Collection, pid=colid) 

1566 

1567 response = HttpResponse(content_type="text/csv") 

1568 response["Content-Disposition"] = f'attachment; filename="{collection.pid}.csv"' 

1569 

1570 csv_header = [ 

1571 "doi", 

1572 "title", 

1573 "date_accepted", 

1574 "date_first_publication", 

1575 ] 

1576 

1577 writer = csv.writer(response, delimiter="\t") 

1578 writer.writerow(csv_header) 

1579 

1580 for article in models.Article.objects.filter( 

1581 my_container__my_collection__pid=colid 

1582 ).order_by("-date_accepted"): 

1583 if article.date_published is not None or article.date_online_first is not None: 1583 ↛ 1580line 1583 didn't jump to line 1580 because the condition on line 1583 was always true

1584 first_online = ( 

1585 article.date_online_first 

1586 if (article.date_online_first is not None and colid.lower()[0:2] == "cr") 

1587 else article.date_published 

1588 ) 

1589 writer.writerow( 

1590 [ 

1591 f'=LIEN.HYPERTEXTE("https://doi.org/{article.doi}"; "{article.doi}")', 

1592 xml_utils.normalise_span(article.title_tex), 

1593 article.date_accepted.strftime("%Y-%m-%d") 

1594 if article.date_accepted is not None 

1595 else "", 

1596 first_online.strftime("%Y-%m-%d"), 

1597 ] 

1598 ) 

1599 

1600 return response 

1601 

1602 

1603class IssuesAPIView(View): 

1604 def get(self, request, *args, **kwargs): 

1605 colid = kwargs.get("colid", None) 

1606 issues_pids = list( 

1607 models.Container.objects.filter( 

1608 Q(my_collection__pid=colid) | Q(my_collection__parent__pid=colid) 

1609 ) 

1610 .values_list("pid", flat=True) 

1611 .order_by("pid") 

1612 ) 

1613 return JsonResponse({"issues": issues_pids}) 

1614 

1615 

1616class IssueListAPIView(View): 

1617 def get(self, request, *args, **kwargs): 

1618 pid = kwargs.get("pid", None) 

1619 articles_pids = list( 

1620 models.Article.objects.filter(my_container__pid=pid) 

1621 .values_list("pid", flat=True) 

1622 .order_by("pid") 

1623 ) 

1624 return JsonResponse({"articles": articles_pids}) 

1625 

1626 

1627class ItemXMLView(View): 

1628 def get(self, request, *args, **kwargs): 

1629 pid = kwargs.get("pid", None) 

1630 full_xml = self.request.GET.get("full_xml", "1") 

1631 

1632 full_xml = False if full_xml == "0" or full_xml == "false" else True 

1633 if pid.find(".") > 0: 

1634 # The id given is a DOI 

1635 article = model_helpers.get_article_by_doi(pid) 

1636 if article: 1636 ↛ 1639line 1636 didn't jump to line 1639 because the condition on line 1636 was always true

1637 pid = article.pid 

1638 else: 

1639 raise Http404 

1640 

1641 xml_body = ptf_cmds.exportPtfCmd( 

1642 { 

1643 "pid": pid, 

1644 "with_internal_data": False, 

1645 "with_binary_files": False, 

1646 "for_archive": True, 

1647 "full_xml": full_xml, 

1648 } 

1649 ).do() 

1650 

1651 return HttpResponse(xml_body, content_type="application/xml") 

1652 

1653 

1654class ItemFileListAPIView(View): 

1655 def get(self, request, *args, **kwargs): 

1656 pid = kwargs.get("pid", None) 

1657 

1658 resource = model_helpers.get_resource(pid) 

1659 if not resource: 1659 ↛ 1660line 1659 didn't jump to line 1660 because the condition on line 1659 was never true

1660 raise Http404 

1661 

1662 obj = resource.cast() 

1663 binary_files = obj.get_binary_files_location() 

1664 

1665 result = {"files": binary_files} 

1666 

1667 if obj.classname == "Container": 1667 ↛ 1668line 1667 didn't jump to line 1668 because the condition on line 1667 was never true

1668 articles = [] 

1669 for article in obj.article_set.all(): 

1670 article_files = article.get_binary_files_location() 

1671 articles.append({"pid": article.pid, "files": article_files}) 

1672 result["articles"] = articles 

1673 

1674 return JsonResponse(result) 

1675 

1676 

1677class APIMatchOneView(View): 

1678 def get(self, request, *args, **kwargs): 

1679 pid = kwargs.get("pid", None) 

1680 seq = kwargs.get("seq", 0) 

1681 what = kwargs.get("what", "") 

1682 

1683 resource = model_helpers.get_resource(pid) 

1684 if not resource: 

1685 raise Http404 

1686 

1687 if what not in ["zbl-item-id", "mr-item-id", "doi", "numdam-id", "pmid"]: 

1688 return HttpResponseBadRequest( 

1689 "Bad request: 'what' has to be one" 

1690 "of {zbl-item-id, mr-item-id, doi, numdam-id, pmid}" 

1691 ) 

1692 result = "" 

1693 

1694 status = 200 

1695 message = "" 

1696 

1697 try: 

1698 obj = resource.cast() 

1699 seq = int(seq) 

1700 if seq == 0: 

1701 # Article, Book or Book part match 

1702 if obj.classname.lower() == "article": 

1703 result = matching.match_article(obj, what) 

1704 else: 

1705 # TODO match book 

1706 pass 

1707 else: 

1708 bibitem = model_helpers.get_bibitem_by_seq(obj, seq) 

1709 if not bibitem: 

1710 raise Http404 

1711 result = matching.match_bibitem(bibitem, what) 

1712 

1713 message = pid + " " + str(seq) + " " + what + " : " + result 

1714 except Timeout as exception: 

1715 return HttpResponse(exception, status=408) 

1716 except Exception as exception: 

1717 return HttpResponseServerError(exception) 

1718 

1719 data = {"message": message, "status": status} 

1720 return JsonResponse(data) 

1721 

1722 

1723class APIMatchAllView(View): 

1724 @staticmethod 

1725 def get_existing_ids(pid, what, force): 

1726 query_bibitemids = ( 

1727 models.BibItemId.objects.filter( 

1728 bibitem__resource__pid__contains=pid, 

1729 id_type__in=what, 

1730 ) 

1731 .select_related( 

1732 "bibitem", 

1733 "bibitem__resource", 

1734 ) 

1735 .only("bibitem__resource__pid", "bibitem__sequence", "id_type") 

1736 ) 

1737 query_extids = models.ExtId.objects.filter( 

1738 resource__pid__contains=pid, 

1739 id_type__in=what, 

1740 ).select_related("resource") 

1741 if force == "1": 

1742 query_bibitemids = query_bibitemids.exclude(checked=False, false_positive=False) 

1743 query_extids = query_extids.exclude(checked=False, false_positive=False) 

1744 if force == "2": 

1745 query_bibitemids = models.BibItemId.objects.none() 

1746 query_extids = models.ExtId.objects.none() 

1747 bibitemids = { 

1748 (bibitemid.bibitem.resource.pid, bibitemid.bibitem.sequence, bibitemid.id_type) 

1749 for bibitemid in query_bibitemids 

1750 } 

1751 extids = {(extid.resource.pid, 0, extid.id_type) for extid in query_extids} 

1752 return bibitemids.union(extids) 

1753 

1754 @staticmethod 

1755 def get_possible_ids(pid, what): 

1756 bibitems = models.BibItem.objects.filter(resource__pid__contains=pid).select_related( 

1757 "resource" 

1758 ) 

1759 articles = models.Article.objects.filter(pid__contains=pid).exclude( 

1760 classname="TranslatedArticle" 

1761 ) 

1762 bibitemids = { 

1763 (item.resource.pid, item.sequence, type_) 

1764 for type_ in what 

1765 for item in bibitems 

1766 if type_ != "pmid" 

1767 } 

1768 # we remove doi from possible extids 

1769 if "doi" in what: 

1770 what.remove("doi") 

1771 extids = {(article.pid, 0, type_) for type_ in what for article in articles} 

1772 return bibitemids.union(extids) 

1773 

1774 @staticmethod 

1775 def delete_ids_if_necessary(pid, what, force): 

1776 if force == "1": 

1777 models.BibItemId.objects.filter( 

1778 bibitem__resource__pid__contains=pid, 

1779 id_type__in=what, 

1780 checked=False, 

1781 false_positive=False, 

1782 ).delete() 

1783 models.ExtId.objects.filter( 

1784 resource__pid__contains=pid, 

1785 id_type__in=what, 

1786 checked=False, 

1787 false_positive=False, 

1788 ).delete() 

1789 if force == "2": 

1790 models.BibItemId.objects.filter( 

1791 bibitem__resource__pid__contains=pid, id_type__in=what 

1792 ).delete() 

1793 models.ExtId.objects.filter(resource__pid__contains=pid, id_type__in=what).delete() 

1794 

1795 def get(self, request, *args, **kwargs): 

1796 pid = kwargs.get("pid", None) 

1797 what = kwargs.get("what", "all") 

1798 force = kwargs.get("force", "0") 

1799 # if what contains several targets, they are separated with an underscore 

1800 what = what.split("_") 

1801 if force != "0": 

1802 self.delete_ids_if_necessary(pid, what, force) 

1803 existing = self.get_existing_ids(pid, what, force) 

1804 possible = self.get_possible_ids(pid, what) 

1805 ids = list(possible - existing) 

1806 ids.sort(key=itemgetter(0, 1, 2)) 

1807 final = [f"{pid}/{number}/{what}" for pid, number, what in ids] 

1808 return JsonResponse({"ids": final}) 

1809 

1810 

1811class UpdateMatchingView(View): 

1812 resource = None 

1813 

1814 def post_update(self): 

1815 model_helpers.post_resource_updated(self.resource) 

1816 

1817 def update_obj(self, action): 

1818 if action == "delete": 

1819 models.ExtId.objects.filter(resource=self.resource).delete() 

1820 models.BibItemId.objects.filter(bibitem__resource=self.resource).delete() 

1821 elif action == "mark-checked": 

1822 models.ExtId.objects.filter(resource=self.resource).update(checked=True) 

1823 models.BibItemId.objects.filter(bibitem__resource=self.resource).update(checked=True) 

1824 elif action == "mark-unchecked": 

1825 models.ExtId.objects.filter(resource=self.resource).update(checked=False) 

1826 models.BibItemId.objects.filter(bibitem__resource=self.resource).update(checked=False) 

1827 

1828 for bibitem in models.BibItem.objects.filter(resource=self.resource): 

1829 cmd = xml_cmds.updateBibitemCitationXmlCmd() 

1830 cmd.set_bibitem(bibitem) 

1831 cmd.do() 

1832 

1833 self.post_update() 

1834 

1835 def get(self, request, *args, **kwargs): 

1836 pid = kwargs.get("pid", None) 

1837 action = kwargs.get("action", None) 

1838 

1839 self.resource = model_helpers.get_resource(pid) 

1840 if not self.resource: 

1841 raise Http404 

1842 

1843 self.update_obj(action) 

1844 

1845 url = reverse("article", kwargs={"aid": self.resource.pid}) 

1846 return HttpResponseRedirect(url) 

1847 

1848 

1849class UpdateExtIdView(View): 

1850 obj = None 

1851 resource = None 

1852 parent = None 

1853 

1854 def get_obj(self, pk): 

1855 try: 

1856 extid = models.ExtId.objects.get(pk=pk) 

1857 except models.ExtId.DoesNotExist: 

1858 raise Http404 

1859 

1860 self.obj = extid 

1861 self.resource = extid.resource 

1862 

1863 def post_update(self): 

1864 model_helpers.post_resource_updated(self.resource) 

1865 

1866 def update_obj(self, action): 

1867 if not self.obj: 

1868 raise Http404 

1869 

1870 if action == "delete": 

1871 self.obj.delete() 

1872 elif action == "toggle-checked": 

1873 self.obj.checked = False if self.obj.checked else True 

1874 self.obj.save() 

1875 elif action == "toggle-false-positive": 

1876 self.obj.false_positive = False if self.obj.false_positive else True 

1877 self.obj.save() 

1878 

1879 self.post_update() 

1880 

1881 def get(self, request, *args, **kwargs): 

1882 pk = kwargs.get("pk", None) 

1883 action = kwargs.get("action", None) 

1884 

1885 self.get_obj(pk) 

1886 self.update_obj(action) 

1887 

1888 if action == "delete": 

1889 url = reverse("article", kwargs={"aid": self.resource.pid}) 

1890 return HttpResponseRedirect(url) 

1891 return JsonResponse({}) 

1892 

1893 

1894class UpdateBibItemIdView(UpdateExtIdView): 

1895 def get_obj(self, pk): 

1896 try: 

1897 bibitemid = models.BibItemId.objects.get(pk=pk) 

1898 except models.BibItemId.DoesNotExist: 

1899 raise Http404 

1900 

1901 self.obj = bibitemid 

1902 self.parent = bibitemid.bibitem 

1903 self.resource = bibitemid.bibitem.resource 

1904 

1905 def post_update(self): 

1906 cmd = xml_cmds.updateBibitemCitationXmlCmd() 

1907 cmd.set_bibitem(self.parent) 

1908 cmd.do() 

1909 

1910 model_helpers.post_resource_updated(self.resource) 

1911 

1912 

1913class APIFetchId(View): 

1914 def get(self, request, *args, **kwargs): 

1915 id_ = kwargs.get("id", None) 

1916 what = kwargs.get("what", None) 

1917 pk = kwargs.get("pk") 

1918 resource = kwargs["resource"] 

1919 

1920 if what == "pmid": 

1921 data = {"result": "", "status": 200} 

1922 return JsonResponse(data) 

1923 

1924 if not id_: 

1925 return HttpResponseBadRequest("Bad request: 'id' is none") 

1926 

1927 if what not in ["zbl-item-id", "mr-item-id", "doi", "numdam-id"]: 

1928 return HttpResponseBadRequest( 

1929 "Bad request: 'what' has to be one" "of {zbl-item-id, mr-item-id, doi, numdam-id}" 

1930 ) 

1931 

1932 try: 

1933 result = matching.fetch_id(id_, what) 

1934 except (IndexError, RequestException) as exception: 

1935 return HttpResponseServerError(exception) 

1936 

1937 if resource == "bibitemid": 

1938 bibitem = models.BibItem.objects.get(pk=pk) 

1939 raw = bibitem.citation_html 

1940 else: 

1941 article = models.Article.objects.get(pk=pk) 

1942 raw = article.get_citation(request) 

1943 result = highlight_diff(raw, result) 

1944 

1945 data = {"result": result, "status": 200} 

1946 return JsonResponse(data) 

1947 

1948 

1949class APIFetchAllView(View): 

1950 def get(self, request, *args, **kwargs): 

1951 pid = kwargs.get("pid", None) 

1952 

1953 article = model_helpers.get_article(pid) 

1954 if not article: 

1955 raise Http404 

1956 

1957 ids = matching.get_all_fetch_ids(article) 

1958 

1959 data = {"ids": ids} 

1960 return JsonResponse(data) 

1961 

1962 

1963@require_http_methods(["GET"]) 

1964def malsm_books(request, pid="MALSM", api=False): 

1965 template = "malsm.html" 

1966 context = { 

1967 "journal": model_helpers.get_collection(pid), 

1968 "coltype": "book", 

1969 "template": template, 

1970 } 

1971 

1972 return render(request, template, context) 

1973 

1974 

1975class LatestArticlesFeed(Feed): 

1976 link = "" 

1977 ttl = 120 

1978 

1979 def get_feed(self, obj, request): 

1980 feed = super().get_feed(obj, request) 

1981 feed.feed["language"] = get_language() 

1982 return feed 

1983 

1984 def get_object(self, request, name, jid=""): 

1985 """ 

1986 Select the site whose RSS feed is requested. 

1987 It is annotated with an optional `requested_col_id` for sites with multiple collections (ex: proceedings). 

1988 """ 

1989 self.request = request 

1990 return models.Site.objects.annotate(requested_col_id=Value(jid)).get(name=name) 

1991 

1992 def title(self, obj): 

1993 if obj.requested_col_id: 

1994 collection = get_object_or_404( 

1995 models.Collection, sites__name=obj.name, pid=obj.requested_col_id 

1996 ) 

1997 else: 

1998 collection = get_object_or_404(models.Collection, sites__name=obj.name) 

1999 return collection.title_sort 

2000 

2001 def description(self): 

2002 return _("Flux RSS des derniers articles parus") 

2003 

2004 def items(self, obj): 

2005 qs = models.Article.objects.filter(sites=obj.pk) 

2006 if obj.requested_col_id: 

2007 qs = qs.filter(my_container__my_collection__pid=obj.requested_col_id) 

2008 return qs.exclude(classname="TranslatedArticle").order_by( 

2009 Greatest("date_online_first", "date_published").desc(nulls_last=True), "-seq" 

2010 )[:20] 

2011 

2012 def item_title(self, item): 

2013 return f"{item.get_authors_short()} - {item.title_html}" 

2014 

2015 def item_description(self, item): 

2016 language = get_language() 

2017 abstracts = item.get_abstracts() 

2018 if not abstracts: 

2019 return self.item_title(item) 

2020 try: 

2021 return abstracts.get(lang=language).value_html 

2022 except models.Abstract.DoesNotExist: 

2023 return abstracts.first().value_html 

2024 

2025 def item_pubdate(self, item): 

2026 if item.date_published: 

2027 return item.date_published 

2028 return item.date_online_first 

2029 

2030 def item_link(self, item): 

2031 if item.doi: 

2032 return f"{settings.DOI_BASE_URL}{item.doi}" 

2033 return item.get_absolute_url() 

2034 

2035 

2036class LatestIssue(ItemView): 

2037 def get(self, request, *args, **kwargs): 

2038 pid = kwargs.get("pid") 

2039 if pid is None: 2039 ↛ 2040line 2039 didn't jump to line 2040 because the condition on line 2039 was never true

2040 return HttpResponse(status=404) 

2041 

2042 container_issues = ( 

2043 models.Container.objects.filter(my_collection__pid=pid) 

2044 .all() 

2045 .order_by("-vseries_int", "-year", "-volume_int", "-number_int") 

2046 ) 

2047 if container_issues is None: 2047 ↛ 2048line 2047 didn't jump to line 2048 because the condition on line 2047 was never true

2048 return HttpResponse(status=404) 

2049 

2050 container = container_issues.first() 

2051 url = container.get_absolute_url() 

2052 return HttpResponseRedirect(url) 

2053 

2054 

2055class RSSTemplate(TemplateView): 

2056 template_name = "blocks/syndication_feed.html" 

2057 

2058 def dispatch(self, request, *args, **kwargs): 

2059 # Numdam does not have an rss feed for now 

2060 if settings.SITE_ID == 3: 

2061 raise Http404 

2062 return super().dispatch(request, *args, **kwargs) 

2063 

2064 def get_context_data(self, **kwargs): 

2065 context = super().get_context_data(**kwargs) 

2066 

2067 context["journal"] = model_helpers.get_collection(settings.COLLECTION_PID) 

2068 

2069 return context 

2070 

2071 

2072class ArticleEditAPIView(View): 

2073 def __init__(self, *args, **kwargs): 

2074 super().__init__(*args, **kwargs) 

2075 self.doi = None 

2076 self.colid = None 

2077 self.edit_all_fields = False 

2078 self.fields_to_update = ( 

2079 [] 

2080 ) # Must be used to specify the fields to update (title, authors, references...) 

2081 

2082 @method_decorator(csrf_exempt) 

2083 def dispatch(self, request, *args, **kwargs): 

2084 return super().dispatch(request, *args, **kwargs) 

2085 

2086 def save_data(self, data_article): 

2087 pass 

2088 

2089 def restore_data(self, article): 

2090 pass 

2091 

2092 def convert_data_for_editor(self, data_article): 

2093 data_article.trans_title_formulas = [] 

2094 data_article.title_formulas = [] 

2095 data_article.abstract_formulas = [] 

2096 data_article.trans_abstract_formulas = [] 

2097 

2098 data_article.title_tex, data_article.trans_title_tex = get_tex_from_xml( 

2099 data_article.title_xml, "title", add_span_around_tex_formula=True 

2100 ) 

2101 

2102 for contrib in data_article.contributors: 

2103 contrib["address_text"] = "\n".join([address for address in contrib["addresses"]]) 

2104 

2105 if len(data_article.abstracts) == 0: 

2106 data_article.abstracts = [ 

2107 { 

2108 "tag": "abstract", 

2109 "lang": data_article.lang, 

2110 "value_html": "", 

2111 "value_tex": "", 

2112 "value_xml": "", 

2113 } 

2114 ] 

2115 

2116 for abstract in data_article.abstracts: 

2117 if abstract["value_xml"]: 

2118 value_tex = get_tex_from_xml( 

2119 abstract["value_xml"], "abstract", add_span_around_tex_formula=True 

2120 ) 

2121 else: 

2122 value_tex = "" 

2123 abstract["value_tex"] = value_tex 

2124 

2125 data_article.conference = ", ".join( 

2126 [subj["value"] for subj in data_article.subjs if subj["type"] == "conference"] 

2127 ) 

2128 data_article.topics = [ 

2129 subj["value"] for subj in data_article.subjs if subj["type"] == "topic" 

2130 ] 

2131 

2132 data_article.pci_section = "".join( 

2133 [subj["value"] for subj in data_article.subjs if subj["type"] == "pci"] 

2134 ) 

2135 

2136 data_article.subjs = [ 

2137 subj 

2138 for subj in data_article.subjs 

2139 if subj["type"] not in ["conference", "topic", "pci"] 

2140 ] 

2141 

2142 with_ordered_label = True 

2143 for i, ref in enumerate(data_article.bibitems, start=1): 

2144 model_data_converter.convert_refdata_for_editor(ref) 

2145 if ref.label != f"[{str(i)}]": 

2146 with_ordered_label = False 

2147 data_article.bibitems_with_ordered_label = with_ordered_label 

2148 

2149 ext_link = model_data.get_extlink(data_article, "icon") 

2150 data_article.icon_url = None 

2151 if ext_link: 

2152 data_article.icon_url = resolver.get_icon_url(None, ext_link["location"]) 

2153 

2154 def convert_data_from_editor(self, data_article): 

2155 xtitle = CkeditorParser( 

2156 html_value=data_article.title_tex, 

2157 mml_formulas=data_article.title_formulas, 

2158 ignore_p=True, 

2159 ) 

2160 data_article.title_html = xtitle.value_html 

2161 data_article.title_tex = xtitle.value_tex 

2162 

2163 trans_title_xml = "" 

2164 if data_article.trans_title_tex: 

2165 xtranstitle = CkeditorParser( 

2166 html_value=data_article.trans_title_tex, 

2167 mml_formulas=data_article.trans_title_formulas, 

2168 ignore_p=True, 

2169 ) 

2170 data_article.trans_title_html = xtranstitle.value_html 

2171 data_article.trans_title_tex = xtranstitle.value_tex 

2172 trans_title_xml = xtranstitle.value_xml 

2173 

2174 data_article.title_xml = get_title_xml( 

2175 xtitle.value_xml, trans_title_xml, data_article.trans_lang, with_tex_values=False 

2176 ) 

2177 

2178 for contrib in data_article.contributors: 

2179 contrib["addresses"] = [] 

2180 if "address_text" in contrib: 

2181 contrib["addresses"] = contrib["address_text"].split("\n") 

2182 

2183 for i, abstract in enumerate(data_article.abstracts): 

2184 if i > 0: 

2185 xabstract = CkeditorParser( 

2186 html_value=abstract["value_tex"], 

2187 mml_formulas=data_article.trans_abstract_formulas, 

2188 ) 

2189 else: 

2190 xabstract = CkeditorParser( 

2191 html_value=abstract["value_tex"], mml_formulas=data_article.abstract_formulas 

2192 ) 

2193 abstract["value_html"] = xabstract.value_html 

2194 abstract["value_tex"] = xabstract.value_tex 

2195 abstract["value_xml"] = jats_from_abstract( 

2196 abstract["lang"], data_article.lang, xabstract 

2197 ) 

2198 

2199 data_article.subjs = [ 

2200 subj for subj in data_article.subjs if subj["type"] not in ["conference", "topic"] 

2201 ] 

2202 if data_article.topics: 

2203 data_article.subjs.extend( 

2204 [{"type": "topic", "lang": "en", "value": topic} for topic in data_article.topics] 

2205 ) 

2206 if data_article.conference: 

2207 data_article.subjs.append( 

2208 {"type": "conference", "lang": "en", "value": data_article.conference} 

2209 ) 

2210 if data_article.pci_section: 

2211 data_article.subjs.append( 

2212 {"type": "pci", "lang": "en", "value": data_article.pci_section} 

2213 ) 

2214 

2215 if self.edit_all_fields or "bibitems" in self.fields_to_update: 

2216 for i, ref in enumerate(data_article.bibitems, start=1): 

2217 if data_article.bibitems_with_ordered_label and ref["type"] != "unknown": 

2218 ref["label"] = f"[{str(i)}]" 

2219 if "doi" in ref and len(ref["doi"]) > 0: 

2220 doi = xml_utils.clean_doi(ref["doi"]) 

2221 ref["doi"] = doi 

2222 ref["extids"] = [["doi", doi]] 

2223 else: 

2224 ref["extids"] = [] 

2225 # URLs are in <comment> 

2226 # if 'url' in ref and len(ref['url']) > 0: 

2227 # ref['ext_links'] = [{'rel': '', 

2228 # 'mimetype': '', 

2229 # 'location': ref['url'], 

2230 # 'base': '', 

2231 # 'metadata': ''}] 

2232 # else: 

2233 # ref['ext_links'] = [] 

2234 

2235 author_array = ref["contribs_text"].split("\n") 

2236 contribs = [] 

2237 for author_txt in author_array: 

2238 if author_txt: 

2239 lastname = firstname = "" 

2240 pos = author_txt.find(", ") 

2241 if pos > 0: 

2242 lastname = author_txt[0:pos] 

2243 firstname = author_txt[pos + 2 :] 

2244 else: 

2245 lastname = author_txt 

2246 

2247 contrib = model_data.create_contributor() 

2248 contrib["first_name"] = firstname 

2249 contrib["last_name"] = lastname 

2250 contrib["role"] = "author" 

2251 contrib["contrib_xml"] = xml_utils.get_contrib_xml(contrib) 

2252 contribs.append(contrib) 

2253 ref["contributors"] = contribs 

2254 

2255 def replace_p(self, obj, key): 

2256 text = obj[key].replace("</p>", "") 

2257 pos = text.find("<p>") 

2258 if pos > -1: 

2259 text = text[0:pos] + text[pos + 3 :] 

2260 text = text.replace("<p>", "\n") 

2261 obj[key] = text 

2262 

2263 def replace_return(self, obj, key): 

2264 text_array = obj[key].split("\n") 

2265 text = "<br>".join([s for s in text_array]) 

2266 obj[key] = text 

2267 

2268 def get(self, request, *args, **kwargs): 

2269 doi = kwargs.get("doi", None) 

2270 # colid = kwargs.get("colid", None) 

2271 

2272 article = model_helpers.get_article_by_doi(doi, prefetch=True) 

2273 if not article: 

2274 raise Http404 

2275 

2276 data_article = model_data_converter.db_to_article_data(article) 

2277 self.convert_data_for_editor(data_article) 

2278 

2279 def obj_to_dict(obj): 

2280 return obj.__dict__ 

2281 

2282 dump = json.dumps(data_article, default=obj_to_dict) 

2283 

2284 return HttpResponse(dump, content_type="application/json") 

2285 

2286 def update_article(self, article_data, icon_file): 

2287 self.save_data(article_data) 

2288 

2289 collection = model_helpers.get_collection(self.colid) 

2290 

2291 model_data_converter.update_data_for_jats(article_data) 

2292 

2293 issue = None 

2294 existing_article = model_helpers.get_article_by_doi(article_data.doi) 

2295 new_data_article = None 

2296 

2297 if existing_article is not None: 

2298 issue = existing_article.my_container 

2299 new_data_article = model_data_converter.db_to_article_data(existing_article) 

2300 else: 

2301 new_data_article = model_data.create_articledata() 

2302 new_data_article.pid = article_data.pid 

2303 new_data_article.doi = article_data.doi 

2304 

2305 if self.edit_all_fields: 

2306 new_data_article = article_data 

2307 else: 

2308 for field in self.fields_to_update: 

2309 value = getattr(article_data, field) 

2310 setattr(new_data_article, field, value) 

2311 

2312 if self.edit_all_fields or "ext_links" in self.fields_to_update: 

2313 # New icon 

2314 if icon_file and issue: 

2315 relative_file_name = resolver.copy_file_obj_to_article_folder( 

2316 icon_file, self.colid, issue.pid, article_data.pid 

2317 ) 

2318 ext_link = model_data.get_extlink(new_data_article, "icon") 

2319 if ext_link is None: 

2320 ext_link = model_data.create_extlink() 

2321 ext_link["rel"] = "icon" 

2322 ext_link["location"] = relative_file_name 

2323 new_data_article.ext_links.append(ext_link) 

2324 

2325 # No or removed icon 

2326 if not icon_file and hasattr(article_data, "icon_url") and not article_data.icon_url: 

2327 new_data_article.ext_links = [ 

2328 e for e in new_data_article.ext_links if e["rel"] != "icon" 

2329 ] 

2330 

2331 cmd = xml_cmds.addArticleXmlCmd( 

2332 {"xarticle": new_data_article, "use_body": False, "issue": issue, "standalone": True} 

2333 ) 

2334 cmd.set_collection(collection) 

2335 article = cmd.do() 

2336 

2337 self.restore_data(article) 

2338 

2339 def post(self, request, *args, **kwargs): 

2340 self.colid = kwargs.get("colid", None) 

2341 self.doi = kwargs.get("doi", None) 

2342 

2343 body_unicode = request.POST.get("data", "") 

2344 body = json.loads(body_unicode) 

2345 

2346 article_data = Munch(body) 

2347 new_bibitems = [] 

2348 for bib in article_data.bibitems: 

2349 new_bibitems.append(Munch(bib)) 

2350 article_data.bibitems = new_bibitems 

2351 

2352 new_relations = [] 

2353 for relation in article_data.relations: 

2354 new_relations.append(Munch(relation)) 

2355 article_data.relations = new_relations 

2356 

2357 new_translations = [] 

2358 for translation in article_data.translations: 

2359 new_translations.append(Munch(translation)) 

2360 article_data.translations = new_translations 

2361 

2362 self.convert_data_from_editor(article_data) 

2363 

2364 icon_file = None 

2365 if "icon" in request.FILES: 

2366 icon_file = request.FILES["icon"] 

2367 

2368 self.update_article(article_data, icon_file) 

2369 

2370 return JsonResponse({"message": "OK"}) 

2371 

2372 

2373class CollectionEditAPIView(View): 

2374 def __init__(self, *args, **kwargs): 

2375 super().__init__(*args, **kwargs) 

2376 self.colid = None 

2377 self.collection = None 

2378 self.edit_all_fields = True 

2379 self.fields_to_update = ( 

2380 [] 

2381 ) # Must be used to specify the fields to update (title, wall, periods...) 

2382 

2383 @method_decorator(csrf_exempt) 

2384 def dispatch(self, request, *args, **kwargs): 

2385 return super().dispatch(request, *args, **kwargs) 

2386 

2387 def save_data(self, data): 

2388 pass 

2389 

2390 def restore_data(self, collection): 

2391 pass 

2392 

2393 def convert_data_for_editor(self, data): 

2394 data.title, data.trans_title = get_tex_from_xml( 

2395 data.title_xml, "title", add_span_around_tex_formula=True 

2396 ) 

2397 # TODO: move periods inside GDML 

2398 data.periods = [] 

2399 

2400 def convert_data_from_editor(self, data): 

2401 xtitle = CkeditorParser(html_value=data.title_tex, mml_formulas=[], ignore_p=True) 

2402 data.title_html = xtitle.value_html 

2403 data.title_tex = xtitle.value_tex 

2404 

2405 # TODO: get_title_xml for Collections 

2406 data.title_xml = get_title_xml(xtitle.value_xml, with_tex_values=False) 

2407 

2408 ids = [] 

2409 if data.issn: 

2410 ids.append(["issn", data.issn]) 

2411 if data.e_issn: 

2412 ids.append(["e-issn", data.e_issn]) 

2413 data.ids = ids 

2414 

2415 def replace_p(self, obj, key): 

2416 text = obj[key].replace("</p>", "") 

2417 pos = text.find("<p>") 

2418 if pos > -1: 

2419 text = text[0:pos] + text[pos + 3 :] 

2420 text = text.replace("<p>", "\n") 

2421 obj[key] = text 

2422 

2423 def replace_return(self, obj, key): 

2424 text_array = obj[key].split("\n") 

2425 text = "<br>".join([s for s in text_array]) 

2426 obj[key] = text 

2427 

2428 def get(self, request, *args, **kwargs): 

2429 colid = kwargs.get("colid", None) 

2430 

2431 self.collection = collection = model_helpers.get_collection(colid, sites=False) 

2432 if not collection: 

2433 raise Http404 

2434 

2435 data = model_data_converter.db_to_publication_data(collection) 

2436 self.convert_data_for_editor(data) 

2437 

2438 def obj_to_dict(obj): 

2439 return obj.__dict__ 

2440 

2441 dump = json.dumps(data, default=obj_to_dict) 

2442 

2443 return HttpResponse(dump, content_type="application/json") 

2444 

2445 def update_collection(self, data): 

2446 self.save_data(data) 

2447 

2448 existing_collection = model_helpers.get_collection(self.colid, sites=False) 

2449 if existing_collection is None: 

2450 cls = ptf_cmds.addCollectionPtfCmd 

2451 new_data = data 

2452 else: 

2453 cls = ptf_cmds.updateCollectionPtfCmd 

2454 

2455 if self.edit_all_fields: 

2456 new_data = data 

2457 else: 

2458 new_data = model_data_converter.db_to_publication_data(existing_collection) 

2459 

2460 for field in self.fields_to_update: 

2461 value = getattr(data, field) 

2462 setattr(new_data, field, value) 

2463 

2464 params = {"xobj": new_data, "solr_commit": False} 

2465 cmd = cls(params) 

2466 if new_data.provider: 

2467 provider = model_helpers.get_provider_by_name(new_data.provider) 

2468 else: 

2469 provider = model_helpers.get_provider("mathdoc-id") 

2470 cmd.set_provider(provider) 

2471 collection = cmd.do() 

2472 

2473 # TODO: Move xml_cmds add_objects_with_location inside ptf_cmds 

2474 # self.add_objects_with_location(xcol.ext_links, collection, "ExtLink") 

2475 

2476 self.restore_data(collection) 

2477 

2478 return collection 

2479 

2480 def post(self, request, *args, **kwargs): 

2481 self.colid = kwargs.get("colid", None) 

2482 

2483 body_unicode = request.body.decode("utf-8") 

2484 # POST.get('data') has to be used with a VueJS FormData 

2485 # body_unicode = request.POST.get('data', '') 

2486 body = json.loads(body_unicode) 

2487 

2488 data = Munch(body) 

2489 self.convert_data_from_editor(data) 

2490 

2491 self.update_collection(data) 

2492 

2493 return JsonResponse({"message": "OK"}) 

2494 

2495 

2496class ArticleCitedByView(View): 

2497 def get(self, request, *args, **kwargs): 

2498 doi = self.kwargs.get("doi", "").strip("/") 

2499 

2500 if "/" in doi: 2500 ↛ 2503line 2500 didn't jump to line 2503 because the condition on line 2500 was always true

2501 resource = model_helpers.get_resource_by_doi(doi) 

2502 else: 

2503 resource = model_helpers.get_resource(doi) 

2504 

2505 if not resource: 2505 ↛ 2506line 2505 didn't jump to line 2506 because the condition on line 2505 was never true

2506 raise Http404 

2507 

2508 citations, sources, for_stats = citedby.get_citations(resource) 

2509 if citations: 2509 ↛ 2510line 2509 didn't jump to line 2510 because the condition on line 2509 was never true

2510 status_code = 200 

2511 else: 

2512 status_code = 204 

2513 

2514 data = { 

2515 "result": {"citations": citations, "sources": sources, "doi": doi, "json": for_stats}, 

2516 "status": status_code, 

2517 } 

2518 return JsonResponse(data) 

2519 

2520 

2521def export_citation(request, **kwargs): 

2522 data = "" 

2523 pid = kwargs.get("pid", "") 

2524 ext = kwargs.get("ext", "") 

2525 

2526 if "/" in pid: 2526 ↛ 2527line 2526 didn't jump to line 2527 because the condition on line 2526 was never true

2527 resource = model_helpers.get_resource_by_doi(pid) 

2528 else: 

2529 resource = model_helpers.get_resource(pid) 

2530 

2531 if not resource: 2531 ↛ 2532line 2531 didn't jump to line 2532 because the condition on line 2531 was never true

2532 return HttpResponse(status=404) 

2533 

2534 if hasattr(resource, "article"): 

2535 document = resource.article 

2536 else: 

2537 document = model_helpers.get_container(resource.pid) 

2538 

2539 filename = "citation." + ext 

2540 if ext == "bib": 

2541 data = document.get_bibtex(request) 

2542 elif ext == "ris": 

2543 data = document.get_ris(request) 

2544 elif ext == "enw": 2544 ↛ 2547line 2544 didn't jump to line 2547 because the condition on line 2544 was always true

2545 data = document.get_endnote(request) 

2546 

2547 if data: 2547 ↛ 2551line 2547 didn't jump to line 2551 because the condition on line 2547 was always true

2548 response = HttpResponse(data, content_type="text/html; charset=UTF-8") 

2549 response["Content-Disposition"] = "attachment; filename=%s" % filename 

2550 else: 

2551 response = HttpResponse(status=204) 

2552 return response 

2553 

2554 

2555def get_tokenized(body): 

2556 soup = BeautifulSoup(body, "html.parser") 

2557 math_symbols = {} 

2558 i = 0 

2559 

2560 for tag in soup.select("span.mathjax-formula"): 

2561 if tag.name == "span": 

2562 math_symbols[i] = tag.decode_contents() 

2563 tag.string = "[math_symbol_" + str(i) + "]" 

2564 i += 1 

2565 # else: 

2566 # links[j] = tag.decode_contents() 

2567 # tag.string = '$link_' + str(j) + '$' 

2568 # j += 1 

2569 

2570 body = str(soup) 

2571 

2572 return {"body": body, "tokens": {"math": math_symbols}} 

2573 

2574 

2575def detokenize(body, tokens): 

2576 soup = BeautifulSoup(body, "html.parser") 

2577 

2578 for tag in soup.select("span.mathjax-formula"): 

2579 token_name = re.sub(r"\[|\]", "", tag.string) 

2580 id_list = re.findall(r"\d+", token_name) 

2581 if id_list: 

2582 tag_id = int(id_list[0]) 

2583 if tag_id in tokens["math"]: 

2584 tag.string = tokens["math"][tag_id] 

2585 

2586 body = html.unescape(str(soup)) 

2587 

2588 return body 

2589 

2590 

2591class ExportArticleHtml(View): 

2592 def get(self, request, **kwargs): 

2593 doi = kwargs.get("doi", None) 

2594 if doi[-1] == "/": 2594 ↛ 2595line 2594 didn't jump to line 2595 because the condition on line 2594 was never true

2595 doi = doi[:-1] 

2596 tokenize = kwargs.get("tokenize", None) 

2597 a = Article.objects.get(doi=doi) 

2598 body = a.body_html 

2599 pid = a.__str__() 

2600 

2601 if tokenize is not None: 2601 ↛ 2604line 2601 didn't jump to line 2604 because the condition on line 2601 was never true

2602 # tokenize = int(tokenize) 

2603 

2604 tokens_infos = get_tokenized(body) 

2605 body = tokens_infos["body"] 

2606 # tokens = tokens_infos["tokens"] 

2607 

2608 with NamedTemporaryFile("a+", encoding="utf-8") as html_article: 

2609 html_article.write(body) 

2610 html_article.seek(0) 

2611 response = HttpResponse(html_article, content_type="text/html; charset=utf-8") 

2612 response["Content-Disposition"] = "attachment; filename=" + pid + ".html" 

2613 

2614 return response 

2615 

2616 

2617class RecentArticlesPublished(View): 

2618 # La méthode permet de retourner 3 articles récents au format JSON avec pour informations : 

2619 # - titre de l'article 

2620 # - le(s) auteur(s) de l'article 

2621 # - collection de l'article 

2622 # - doi 

2623 # - Infos sur l'article 

2624 # - url 

2625 

2626 def get(self, request): 

2627 articles = models.Article.objects.all().order_by( 

2628 Greatest("date_online_first", "date_published").desc(nulls_last=True) 

2629 )[:100] 

2630 articles_infos = [] 

2631 container_pids = [] 

2632 nb_articles = articles.count() 

2633 i = 0 

2634 while i < nb_articles and len(articles_infos) < 3: 

2635 article = articles[i] 

2636 if article.my_container is not None and article.my_container.pid not in container_pids: 2636 ↛ 2648line 2636 didn't jump to line 2648 because the condition on line 2636 was always true

2637 container_pids.append(article.my_container.pid) 

2638 if article.date_published: 2638 ↛ 2648line 2638 didn't jump to line 2648 because the condition on line 2638 was always true

2639 item = { 

2640 "title": article.title_html, 

2641 "authors": article.get_authors_short(), 

2642 "collection": article.my_container.my_collection.title_tex, 

2643 "doi": article.doi, 

2644 "citation_source": article.get_citation_base(), 

2645 "url": resolver.get_doi_url(article.doi), 

2646 } 

2647 articles_infos.append(item) 

2648 i += 1 

2649 return JsonResponse({"articles": articles_infos}) 

2650 

2651 

2652def get_first_n_authors(authors, n=3): 

2653 if len(authors) > n: 

2654 authors = authors[0:n] 

2655 authors.append("...") 

2656 return "; ".join(authors) 

2657 

2658 

2659def get_suggested_articles(article): 

2660 documents = [] 

2661 obj, created = models.RelatedArticles.objects.get_or_create(resource=article) 

2662 solr_cmds.auto_suggest_doi(obj, article) 

2663 

2664 if obj.doi_list: 2664 ↛ 2665line 2664 didn't jump to line 2665 because the condition on line 2664 was never true

2665 exclusion = obj.exclusion_list.split() if obj.exclusion_list else [] 

2666 # Filter the articles in the exclusion list and that have a DOI that includes the article DOI (translations) 

2667 dois = [ 

2668 doi 

2669 for doi in obj.doi_list.split() 

2670 if doi not in exclusion and doi.find(article.doi) != 0 

2671 ] 

2672 for doi in dois: 

2673 suggest = Article.objects.filter(doi=doi).first() 

2674 doc = {} 

2675 base_url = "" 

2676 if suggest: 

2677 doc = vars(suggest) 

2678 doc["authors"] = models.get_names(suggest, "author") 

2679 if suggest.my_container: 

2680 collection = suggest.my_container.my_collection 

2681 base_url = collection.website() or "" 

2682 doc["year"] = suggest.my_container.year 

2683 doc["journal_abbrev"] = collection.abbrev 

2684 else: 

2685 try: 

2686 doc = crossref.crossref_request(doi) 

2687 except: 

2688 continue 

2689 doc["title_html"] = doc.get("title", "") 

2690 doc["journal_abbrev"] = doc.get("journal", "") 

2691 authors = doc.get("authors", ";").split(";") 

2692 doc["authors"] = [" ".join(au.split(",")).title() for au in authors] 

2693 

2694 if doc: 

2695 doc["authors"] = get_first_n_authors(doc.get("authors", [])) 

2696 if base_url and suggest: 

2697 doc["url"] = base_url + "/articles/" + doi 

2698 else: 

2699 doc["url"] = resolver.get_doi_url(doi) 

2700 documents.append(doc) 

2701 return documents 

2702 

2703 

2704@csrf_exempt 

2705def update_suggest(request, doi): 

2706 if request.method == "POST": 2706 ↛ exitline 2706 didn't return from function 'update_suggest' because the condition on line 2706 was always true

2707 article = Article.objects.filter(doi=doi).first() 

2708 if not article: 

2709 return JsonResponse({"message": "No article found"}) 

2710 obj, created = models.RelatedArticles.objects.get_or_create(resource=article) 

2711 obj.resource_doi = article.doi 

2712 obj.doi_list = request.POST.get("doi_list") 

2713 obj.date_modified = request.POST.get("date_modified") 

2714 obj.exclusion_list = request.POST.get("exclusion_list") 

2715 obj.automatic_list = request.POST.get("automatic_list", True) 

2716 obj.save() 

2717 return JsonResponse({"message": "OK"}) 

2718 

2719 

2720@csrf_exempt 

2721def graphical_abstract(request, doi): 

2722 article = get_object_or_404(models.Article, doi=doi) 

2723 if request.method == "POST": 2723 ↛ 2731line 2723 didn't jump to line 2731 because the condition on line 2723 was always true

2724 obj, created = models.GraphicalAbstract.objects.get_or_create(resource=article) 

2725 obj.resource_doi = article.doi 

2726 obj.date_modified = request.POST.get("date_modified") 

2727 obj.graphical_abstract = request.FILES.get("graphical_abstract") 

2728 obj.illustration = request.FILES.get("illustration") 

2729 obj.save() 

2730 return JsonResponse({"message": "OK"}) 

2731 elif request.method == "DELETE": 

2732 obj = get_object_or_404(models.GraphicalAbstract, resource=article) 

2733 if obj: 

2734 obj.delete() 

2735 return JsonResponse({"message": "OK"}) 

2736 

2737 

2738class MoreLikeThisView(View): 

2739 def get(self, request, *args, **kwargs): 

2740 doi = self.kwargs.get("doi", "") 

2741 article = model_helpers.get_resource_by_doi(doi) 

2742 if not article: 

2743 raise Http404 

2744 

2745 results = solr_cmds.research_more_like_this(article) 

2746 return JsonResponse(results) 

2747 

2748 

2749class HelpView(TemplateView): 

2750 template_name = "help.html" 

2751 

2752 def get_context_data(self, **kwargs): 

2753 context = super().get_context_data(**kwargs) 

2754 

2755 context["journal"] = model_helpers.get_collection(settings.COLLECTION_PID) 

2756 

2757 return context 

2758 

2759 

2760def home(request): 

2761 context = {} 

2762 return render(request, "help.html", context)