Coverage for apps/ptf/model_helpers.py: 75%
553 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-19 19:20 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-19 19:20 +0000
1import datetime
2import itertools
3import random
4import re
5import unicodedata
7import dateutil.parser
8from unidecode import unidecode
10from django.conf import settings
11from django.http import Http404
12from django.shortcuts import get_list_or_404
13from django.urls import reverse
14from django.utils import timezone
15from django.utils.translation import gettext_lazy as _
17from .models import Article
18from .models import Author
19from .models import BibItem
20from .models import BibItemId
21from .models import Collection
22from .models import Container
23from .models import ExtId
24from .models import ExtLink
25from .models import Provider
26from .models import PtfSite
27from .models import Publisher
28from .models import RelatedObject
29from .models import RelationName
30from .models import Relationship
31from .models import Resource
32from .models import SiteMembership
33from .models import XmlBase
34from .site_register import SITE_REGISTER
35from .utils import volume_display
37##########################################################################
38#
39# Get functions
40#
41##########################################################################
44def get_first_last_years(year):
45 the_array = year.split("-")
47 fyear = the_array[0]
48 lyear = the_array[1] if len(the_array) > 1 else fyear
50 return fyear, lyear
53def get_provider_by_name(name):
54 if name == "numdam":
55 name = "mathdoc"
57 provider = Provider.objects.get(name=name)
58 return provider
61def get_provider(pid_type):
62 provider = Provider.objects.get(pid_type=pid_type)
63 return provider
66def get_publisher(name):
67 try:
68 key = make_key(name)
69 publisher = Publisher.objects.get(pub_key=key)
70 except Publisher.DoesNotExist:
71 publisher = None
72 return publisher
75def get_or_create_site(site_id, acro=None):
76 try:
77 site = PtfSite.objects.get(id=site_id)
78 except PtfSite.DoesNotExist:
79 site = PtfSite.objects.create(id=site_id, name=acro, domain=acro, acro=acro)
80 return site
83def get_journals():
84 journals = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="journal")
85 return journals.all()
88def get_actas():
89 actas = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="acta")
90 return actas.all()
93def get_lectures():
94 lectures = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="lecture-notes")
95 return lectures.all()
98def get_proceedings():
99 proceedings = Collection.objects.filter(sites__id=settings.SITE_ID, coltype="proceeding")
100 return proceedings.all()
103def get_collection_of_books(with_lectures=False):
104 filters = ["book-series"]
105 if with_lectures:
106 filters.append("lecture-notes")
108 book_series = Collection.objects.filter(sites__id=settings.SITE_ID, coltype__in=filters)
109 return book_series.all()
112def get_books():
113 return Container.objects.filter(
114 sites__id=settings.SITE_ID,
115 my_collection__coltype__in=["book-series", "lecture-notes", "book-edited-book"],
116 )
119def get_theses():
120 theses = Container.objects.filter(sites__id=settings.SITE_ID, my_collection__coltype="thesis")
121 return theses.all()
124# TODO require the provider in the get_ functions as it serves as a namespace
127def get_collection(pid, sites=True, prefetch=False):
128 try:
129 if sites:
130 col = Collection.objects.get(pid=pid, sites__id=settings.SITE_ID)
131 else:
132 col = Collection.objects.get(pid=pid)
133 except Collection.DoesNotExist:
134 col = None
135 return col
138def get_volumes_in_collection(collection):
139 """
140 used by issue-list.html and oai gallica
141 return list of issues by volume if volume_int exist or by date
142 return list of publishers GROUP BY name with date
143 @param collection:
144 @return:
146 """
148 items = (
149 collection.content.filter(sites__id=settings.SITE_ID)
150 .order_by("-vseries_int", "-year", "-volume_int", "number_int")
151 .all()
152 )
153 # We're building the following list:
154 # vseries = [ { 'vseries_int': vseries_int,
155 # 'volumes': list of volumes <=> volumes_in_vseriess
156 # }
157 # ]
158 #
159 # volumes_in_vseries = [ { 'volume_int': volume_int,
160 # 'title': ?
161 # 'fyear': fyear,
162 # 'lyear': lyear,
163 # 'issues': list of issues <=> issues_in_volume (list of issue objects)
165 if collection.collectionmembership_set.count() > 0: 165 ↛ 166line 165 didn't jump to line 166
166 col_membsership_qs = (
167 collection.collectionmembership_set.filter(container__sites__id=settings.SITE_ID)
168 .order_by("-vseries_int", "-volume_int", "number_int")
169 .all()
170 )
171 joined = itertools.chain(items, col_membsership_qs)
173 def sorter(dict_):
174 return (
175 dict_.vseries_int,
176 dict_.year if hasattr(dict_, "year") else dict_.container.year,
177 dict_.volume_int,
178 dict_.number_int,
179 )
181 items = sorted(joined, key=sorter, reverse=True)
183 # items is now a collection of Container and/or CollectionMembership
185 issue_to_appear_pid = ""
186 if hasattr(settings, "ISSUE_TO_APPEAR_PID"): 186 ↛ 187line 186 didn't jump to line 187, because the condition on line 186 was never true
187 issue_to_appear_pid = settings.ISSUE_TO_APPEAR_PID
189 issues_in_vseries = []
190 volumes_in_vseries = []
191 issues_in_volume = []
192 publishers = []
193 results_vseries = "-1"
194 results_volume = "-1"
195 results_year = "-1"
196 results_fyear = results_lyear = -1
197 volume_count = 0
198 max_volume_count = 0
199 max_width = 0
200 width = 0
201 for item in items:
202 width += len(item.number)
203 if hasattr(item, "container"): 203 ↛ 218line 203 didn't jump to line 218, because the condition on line 203 was never false
204 issue = item.container
205 # The issue-list template use issue properties to display the list of issues
206 # Replace the values with those of the CollectionMembership for the display
207 issue.veries = item.vseries
208 issue.volume = item.volume
209 issue.number = item.number
210 issue.vseries_int = item.vseries_int
211 issue.volume_int = item.volume_int
212 issue.number_int = item.number_int
214 year = issue.year
215 vseries = item.vseries
216 volume = item.volume
217 else:
218 issue = item
219 year = issue.year
220 vseries = issue.vseries
221 volume = issue.volume
223 if issue.pid != issue_to_appear_pid: 223 ↛ 201line 223 didn't jump to line 201, because the condition on line 223 was never false
224 fyear, lyear = get_first_last_years(year)
225 fyear = int(fyear)
226 lyear = int(lyear)
228 # new volume found, we need to add issues_in_volume in the current volumes_in_veries
229 if ( 229 ↛ 259line 229 didn't jump to line 259
230 results_volume != volume
231 or (results_volume == "" and results_year != year)
232 # or (results_volume == volume and results_year != year)
233 ):
234 # The first time, we simply add the issue in issues_in_volume (see below)
235 # But we do not append in volumes_in_vseries
236 if results_volume != "-1":
237 volumes_in_vseries.append(
238 {
239 "volume": results_volume,
240 "fyear": results_fyear,
241 "lyear": results_lyear,
242 "issues": issues_in_volume,
243 }
244 )
245 # Clear issues_in_volume to prepare a new volume
246 issues_in_volume = []
248 # Set the current volume info
249 results_volume = volume
250 results_year = year
251 results_fyear = fyear
252 results_lyear = lyear
253 volume_count += 1
254 if width > max_width:
255 max_width = width
256 width = 0
258 # New vseries found, we need to add volumes_in_vseries to the current vseries
259 if results_vseries != vseries:
260 # The first time, we do not append in issues_in_vseries.
261 # We simply set the vseries info and add the issues in issues_in_volume below
262 if results_vseries != "-1": 262 ↛ 263line 262 didn't jump to line 263, because the condition on line 262 was never true
263 issues_in_vseries.append(
264 {"vseries": results_vseries, "volumes": volumes_in_vseries}
265 )
266 volumes_in_vseries = []
267 results_vseries = vseries
268 max_volume_count = max(0, volume_count)
269 volume_count = 0
271 issues_in_volume.append(issue)
273 # we have to create a list of publishers with date - for Gallica OAI
274 if issue.my_publisher:
275 if publishers:
276 item = publishers[-1]
277 if issue.my_publisher.pub_name != item["name"]: 277 ↛ 278line 277 didn't jump to line 278
278 item = {
279 "name": issue.my_publisher.pub_name,
280 "fyear": fyear,
281 "lyear": lyear,
282 }
283 publishers.append(item)
284 else:
285 if fyear < item["fyear"]: 285 ↛ 287line 285 didn't jump to line 287, because the condition on line 285 was never false
286 item["fyear"] = fyear
287 if lyear > item["lyear"]: 287 ↛ 288line 287 didn't jump to line 288, because the condition on line 287 was never true
288 item["lyear"] = lyear
289 else:
290 publishers.insert(
291 0, {"name": issue.my_publisher.pub_name, "fyear": fyear, "lyear": lyear}
292 )
294 # At the end of the loop, we need to append the remaining issues_in_volume
295 # then volumes_in_vseries
296 if results_volume != "-1" and issues_in_volume:
297 volumes_in_vseries.append(
298 {
299 "volume": results_volume,
300 "fyear": results_fyear,
301 "lyear": results_lyear,
302 "issues": issues_in_volume,
303 }
304 )
305 # volume_count += 1
307 if results_vseries != "-1" and volumes_in_vseries:
308 issues_in_vseries.append({"vseries": results_vseries, "volumes": volumes_in_vseries})
309 max_volume_count = max(0, volume_count)
311 context = {
312 "sorted_issues": issues_in_vseries,
313 "volume_count": max_volume_count,
314 "publishers": publishers,
315 "max_width": max_width,
316 }
318 return context
321def get_container(pid, prefetch=False, sites=True):
322 try:
323 if prefetch:
324 container = (
325 Container.objects.filter(sites__id=settings.SITE_ID, pid=pid)
326 .prefetch_for_toc()
327 .first()
328 )
329 else:
330 if sites: 330 ↛ 333line 330 didn't jump to line 333, because the condition on line 330 was never false
331 container = Container.objects.get(sites__id=settings.SITE_ID, pid=pid)
332 else:
333 container = Container.objects.get(pid=pid)
335 except Container.DoesNotExist:
336 container = None
337 return container
340def get_book_serie(pid):
341 try:
342 book_serie = Collection.objects.get(
343 pid=pid, coltype="book-series", sites__id=settings.SITE_ID
344 )
345 except Collection.DoesNotExist:
346 book_serie = None
347 return book_serie
350def get_issues_count_in_collection(pid):
351 try:
352 collection = Collection.objects.get(pid=pid)
353 issues = Container.objects.filter(my_collection=collection).count()
354 return issues
355 except Exception:
356 pass
359def get_issues_in_volume(vid, is_cr=False, general_articles=False):
360 # 08/09/2022: vid is no longer built (see get_vid in models.py)
361 # It is now the pid of the first issue of the volume
362 first_issue = get_container(vid)
363 if first_issue is None:
364 raise Http404
366 collection = first_issue.get_collection()
367 year = first_issue.year
368 vseries = first_issue.vseries
369 volume = first_issue.volume
371 if is_cr:
372 year_int = int(year)
373 if year_int > 2020 and collection.pid not in ["CRMATH", "CRBIOL"]: 373 ↛ 376line 373 didn't jump to line 376, because the condition on line 373 was never true
374 # CRAS: Les thématiques à partir de 2021 ont un number en "T1", "T2",...
375 # On trie par number pour avoir les thématiques isolés des autres
376 queryset = Container.objects.order_by("number")
377 elif year_int > 2022 and collection.pid == "CRBIOL": 377 ↛ 378line 377 didn't jump to line 378, because the condition on line 377 was never true
378 queryset = Container.objects.order_by("number")
379 else:
380 queryset = Container.objects.order_by("number_int")
381 if general_articles: 381 ↛ 382line 381 didn't jump to line 382, because the condition on line 381 was never true
382 queryset = queryset.filter(title_html="")
383 else:
384 queryset = Container.objects.order_by("number_int")
385 queryset = queryset.filter(
386 my_collection__pid=collection.pid, year=year, vseries=vseries, volume=volume
387 ).prefetch_for_toc()
388 issues = get_list_or_404(queryset)
390 if is_cr and ( 390 ↛ 394line 390 didn't jump to line 394, because the condition on line 390 was never true
391 (year_int > 2020 and collection.pid != "CRBIOL")
392 or (year_int > 2022 and collection.pid == "CRBIOL")
393 ):
394 issues_articles = []
395 grouped_articles = []
396 grouped_issue_articles = {"issue": None, "articles": grouped_articles}
397 for issue in issues:
398 if len(issue.title_html) == 0:
399 grouped_articles.extend(issue.article_set.all().order_by_sequence())
400 grouped_issue_articles["issue"] = issue
401 else:
402 issues_articles.append(
403 {
404 "issue": issue,
405 "articles": issue.article_set.all().order_by_published_date()
406 if settings.SORT_ARTICLES_BY_DATE
407 else issue.article_set.all().order_by_sequence(),
408 }
409 )
410 if grouped_issue_articles["issue"] is not None:
411 issues_articles.insert(0, grouped_issue_articles)
412 else:
413 issues_articles = [
414 {
415 "issue": issue,
416 "articles": issue.article_set.all().order_by_published_date()
417 if settings.SORT_ARTICLES_BY_DATE
418 else issue.article_set.all().order_by_sequence(),
419 }
420 for issue in issues
421 ]
423 return issues_articles, collection
426def get_article(pid: str, prefetch=False, sites=True) -> Article | None:
427 try:
428 if prefetch:
429 article = (
430 Article.objects.filter(sites__id=settings.SITE_ID, pid=pid).prefetch_all().first()
431 )
432 else:
433 if sites: 433 ↛ 436line 433 didn't jump to line 436, because the condition on line 433 was never false
434 article = Article.objects.get(sites__id=settings.SITE_ID, pid=pid)
435 else:
436 article = Article.objects.get(pid=pid)
438 except Article.DoesNotExist:
439 article = None
440 return article
443def get_article_by_doi(doi, prefetch=False):
444 try:
445 if prefetch:
446 article = (
447 Article.objects.filter(sites__id=settings.SITE_ID, doi=doi).prefetch_all().first()
448 )
449 else:
450 article = Article.objects.get(sites__id=settings.SITE_ID, doi=doi)
452 except Article.DoesNotExist:
453 article = None
454 return article
457def get_articles():
458 article_qs = Article.objects.filter(sites__id=settings.SITE_ID).exclude(
459 classname="TranslatedArticle"
460 )
461 return article_qs
464def get_articles_by_deployed_date():
465 sitemembership_qs = SiteMembership.objects.filter(
466 site__id=settings.SITE_ID, resource__classname="Article"
467 ).order_by("-deployed", "-seq")
469 articles = [sm.resource.cast() for sm in sitemembership_qs]
470 return articles
473def get_articles_by_published_date():
474 article_qs = Article.objects.filter(sites__id=settings.SITE_ID).exclude(
475 classname="TranslatedArticle"
476 )
477 if hasattr(settings, "ISSUE_TO_APPEAR_PID"):
478 article_qs = article_qs.exclude(my_container__pid=settings.ISSUE_TO_APPEAR_PID)
479 article_qs = article_qs.order_by("-date_published", "-seq")
481 return article_qs
484def get_xmlbase(base):
485 try:
486 xmlbase = XmlBase.objects.get(base=base)
487 except XmlBase.DoesNotExist:
488 xmlbase = None
489 return xmlbase
492# RelationName are created with a fixture (see app/ptf/apps/ptf/fixtures/initial_data.json
493# Example { "left" : "follows", "right" : "followed-by" }
494# A related-article of an article has 1 relation name (ex "follows" or "followed-by")
495# You need to know if the relation was stored in the left or right attribute of a RelationName,
496# so that you can create/search the Relationship with the correct object/subject.
497# Ex: with A "follows" B, A is the subject and B the object because "follows" is a RelationName.left attribute
498# with A "followed-by" B, A is the object the B the subject because
499# "followed-by" is a RelationName.right attribute
500def get_relationname_left(left_name):
501 try:
502 relationname = RelationName.objects.get(left=left_name)
503 except RelationName.DoesNotExist:
504 relationname = None
506 return relationname
509def get_relationname_right(right_name):
510 try:
511 relationname = RelationName.objects.get(right=right_name)
512 except RelationName.DoesNotExist:
513 relationname = None
515 return relationname
518# See comments about RelationName above
519def get_relationship(subject_pid, object_pid, relationname):
520 try:
521 relationship = Relationship.objects.get(
522 subject_pid=subject_pid, object_pid=object_pid, rel_info=relationname
523 )
524 except Relationship.DoesNotExist:
525 relationship = None
527 return relationship
530def get_extid(resource, id_type):
531 extid = None
532 extids = ExtId.objects.filter(resource=resource, id_type=id_type)
533 if extids.count() > 0:
534 extid = extids.first()
536 return extid
539def get_bibitemid(bibitem, id_type):
540 bibitemid = None
541 bibitemids = BibItemId.objects.filter(bibitem=bibitem, id_type=id_type)
542 if bibitemids.count() > 0:
543 bibitemid = bibitemids.first()
545 return bibitemid
548def get_bibitem_by_seq(article, seq):
549 try:
550 bibitem = article.bibitem_set.get(sequence=seq)
551 except BibItem.DoesNotExist:
552 bibitem = None
553 return bibitem
556def get_extlink(**filters):
557 try:
558 extlink = ExtLink.objects.get(**filters)
559 except ExtLink.DoesNotExist:
560 extlink = None
561 return extlink
564def get_related_object(**filters):
565 """
566 Return RelatedObject with filters pass by params (all are optionals)
567 resource, base, rel, mimetype, location, metadata, seq
568 Check models.py for the params of a RelatedObject
569 """
570 try:
571 related_object = RelatedObject.objects.get(**filters)
572 related_object.select_related()
573 except RelatedObject.DoesNotExist:
574 related_object = None
575 return related_object
578def get_authors_by_letter(first_letter):
579 try:
580 authors = Author.objects.filter(first_letter=first_letter).order_by("name")
581 except Author.DoesNotExist:
582 authors = None
583 return authors
586def make_key(string):
587 n_string = unicodedata.normalize("NFKD", string).encode("ascii", "ignore").decode("ascii")
588 n_string = re.sub(r"[^\w\s-]", "", n_string).strip().lower()
589 n_string = re.sub(r"[-\s]+", "-", n_string)
590 if len(n_string) > 64:
591 n_string = n_string[:64]
593 return n_string if n_string else unidecode(string)
596def get_resource(pid: str, prefetch=False) -> Resource | None:
597 try:
598 if prefetch:
599 resource = (
600 Resource.objects.filter(sites__id=settings.SITE_ID, pid=pid).prefetch_all().first()
601 )
602 else:
603 resource = Resource.objects.get(pid=pid, sites__id=settings.SITE_ID)
604 except Resource.DoesNotExist:
605 resource = None
606 return resource
609def get_resource_by_doi(doi, prefetch=False):
610 try:
611 if prefetch: 611 ↛ 612line 611 didn't jump to line 612
612 resource = (
613 Resource.objects.filter(sites__id=settings.SITE_ID, doi=doi).prefetch_all().first()
614 )
615 else:
616 resource = Resource.objects.get(sites__id=settings.SITE_ID, doi=doi)
618 except Resource.DoesNotExist:
619 resource = None
620 return resource
623def get_random_containers():
624 # TODO get the newest containers only
626 containers = Container.objects.all()
627 random_list = random.sample(containers, 6)
629 return random_list
632def parse_date_str(date_str):
633 """
634 @param date_str:a string representing a date. Ex: "2017-01-10T18:24:58.202+01:00", "2017-05-03"
635 @return:a localized datetime object (localized means that the date has a timezone)
636 """
637 the_date = dateutil.parser.parse(date_str)
638 if not timezone.is_aware(the_date):
639 the_date = timezone.make_aware(the_date, datetime.UTC)
640 return the_date
643def get_issue_to_appear(colid):
644 """
645 Some journals want to display "articles to appear" with articles that have been accepted but are not yet
646 finalized (pages start at 1). ex: AIF
647 :param pid:
648 :return: The container object of articles to appear
649 """
650 pid = ""
652 if hasattr(settings, "ISSUE_TO_APPEAR_PIDS"):
653 if colid in settings.ISSUE_TO_APPEAR_PIDS:
654 pid = settings.ISSUE_TO_APPEAR_PIDS[colid]
656 container = get_container(pid=pid, prefetch=True)
657 return container
660def get_number_from_doi(doi):
661 value = 0
663 try:
664 index = doi.rfind(".")
665 index += 1
666 if index > 0:
667 str_value = doi[index:]
668 value = int(str_value)
669 except BaseException:
670 pass
672 return value
675def get_site_mersenne(collection_pid):
676 key = collection_pid.lower()
678 # TODO refactor smai-jcm, centre_mersenne to have collection_pid == key
679 # Do not use a find here, we want an access time in O(1)
680 if key == "smai-jcm": 680 ↛ 681line 680 didn't jump to line 681, because the condition on line 680 was never true
681 key = "smai"
682 elif key == "mersenne": 682 ↛ 683line 682 didn't jump to line 683, because the condition on line 682 was never true
683 key = "centre_mersenne"
684 elif key == "malsm": 684 ↛ 685line 684 didn't jump to line 685, because the condition on line 684 was never true
685 key = "mbk"
687 try:
688 site_item = settings.SITE_REGISTER[key]
689 except KeyError:
690 return None
691 site_id = site_item["site_id"]
692 site_acro = key
694 return get_or_create_site(site_id, site_acro)
697def get_container_breadcrumb(collection, container, vseries, volume, number, stop_at_volume=False):
698 crumbs = []
700 if collection: 700 ↛ 714line 700 didn't jump to line 714, because the condition on line 700 was never false
701 collection = collection.get_top_collection()
702 href = collection.get_absolute_url()
703 # We show the collection title instead of the basic 'Feuilleter' for the sites with several collections:
704 # 'ALL' and 'MBK' (proceedings site)
705 if settings.COLLECTION_PID in ["ALL", "MBK"] or settings.SITE_NAME == "gdml": 705 ↛ 706line 705 didn't jump to line 706, because the condition on line 705 was never true
706 title = collection.title_html
707 elif hasattr(settings, "SITE_NAME") and settings.SITE_NAME[0:2] == "cr":
708 title = _("Consulter")
709 else:
710 title = _("Feuilleter")
712 crumbs.append({"href": href, "title": title})
714 if container and container.ctype == "issue":
715 # TODO : Here, we should have YEAR_BREACRUMB in all settings file
716 # Until then we just search if YEAR_BREADCRUMB exists
717 if hasattr(settings, "YEAR_BREADCRUMB"): 717 ↛ 718line 717 didn't jump to line 718, because the condition on line 717 was never true
718 title = str(container.year)
719 href = reverse("articles-year", kwargs={"year": container.year})
720 else:
721 href = reverse("volume-items", kwargs={"vid": container.get_vid()})
722 title = "{} {} : ".format(_("Série"), vseries) if vseries else ""
723 if volume: 723 ↛ 724line 723 didn't jump to line 724, because the condition on line 723 was never true
724 title += f"{volume_display()} {volume} ({container.year})"
725 else:
726 title += "{} {}".format(_("Année"), container.year)
727 crumbs.append({"href": href, "title": title})
729 if not stop_at_volume:
730 if number: 730 ↛ 752line 730 didn't jump to line 752, because the condition on line 730 was never false
731 try:
732 year = int(container.year)
733 except ValueError:
734 year = 0
736 if ( 736 ↛ 745line 736 didn't jump to line 745
737 hasattr(settings, "SITE_NAME")
738 and settings.SITE_NAME[0:2] == "cr"
739 and (
740 (settings.SITE_NAME != "crbiol" and year > 2020)
741 or (settings.SITE_NAME == "crbiol" and year > 2022)
742 )
743 and container.title_html == ""
744 ):
745 title = _("Articles du volume en cours")
746 href = reverse("volume-general-items", kwargs={"vid": container.get_vid()})
747 else:
748 href = container.get_absolute_url()
749 title = "no." + " " + number
750 crumbs.append({"href": href, "title": title})
752 return crumbs
755def get_breadcrumb(article, container, collection, stop_at_volume=False):
756 all_crumbs = []
757 is_a_mersenne_books = False
758 previous = next = ""
759 article_crumb = None
761 if article:
762 display_page = True
763 if hasattr(settings, "PAGE_BREADCRUMB"): 763 ↛ 764line 763 didn't jump to line 764, because the condition on line 763 was never true
764 display_page = settings.PAGE_BREADCRUMB
765 if display_page: 765 ↛ 769line 765 didn't jump to line 769, because the condition on line 765 was never false
766 href = article.get_absolute_url()
767 title = article.get_breadcrumb_page_text()
768 article_crumb = {"href": href, "title": title}
769 previous = article.previous().get_absolute_url() if article.previous() else None
770 next = article.next().get_absolute_url() if article.next() else None
771 elif collection.pid == "CJPS" or settings.CONTAINER_SEQUENCED: 771 ↛ 772line 771 didn't jump to line 772, because the condition on line 771 was never true
772 previous = container.previous().get_absolute_url() if container.previous() else None
773 next = container.next().get_absolute_url() if container.next() else None
775 crumbs = get_container_breadcrumb(
776 collection,
777 container,
778 container.vseries,
779 container.volume,
780 container.number,
781 stop_at_volume,
782 )
783 if article_crumb:
784 crumbs.append(article_crumb)
786 all_crumbs.append({"crumbs": crumbs, "previous": previous, "next": next})
787 if collection.pid == "MBK": 787 ↛ 788line 787 didn't jump to line 788, because the condition on line 787 was never true
788 is_a_mersenne_books = True
789 else:
790 is_a_mersenne_books = False
791 # mersenne_books_crumb = {'href': collection.get_absolute_url(), 'title': collection.title_html}
792 for collection_membership in container.collectionmembership_set.all(): 792 ↛ 793line 792 didn't jump to line 793, because the loop on line 792 never started
793 collection = collection_membership.collection
794 vseries = collection_membership.vseries
795 volume = collection_membership.volume
796 number = collection_membership.number
797 crumbs = get_container_breadcrumb(
798 collection, container, vseries, volume, number, stop_at_volume=True
799 )
800 if article_crumb:
801 crumbs.append(article_crumb)
803 # uniquement pour les livres Mersenne ; si un livre appartient à une 2ème collection, on n'affiche que celle-ci
804 # {{2eme collection}} > Titre Container > Tome1...
805 if is_a_mersenne_books:
806 all_crumbs.pop()
807 # crumbs.insert(0, mersenne_books_crumb)
808 all_crumbs.append({"crumbs": crumbs, "previous": previous, "next": next})
810 show_tex = False
811 if hasattr(settings, "SHOW_TEX"): 811 ↛ 814line 811 didn't jump to line 814, because the condition on line 811 was never false
812 show_tex = settings.SHOW_TEX
814 return {"all_crumbs": all_crumbs, "show_tex": show_tex}
817##########################################################################
818#
819# Update functions
820#
821##########################################################################
822def post_resource_updated(resource):
823 """
824 A resource is modified (ex: matching), the last_modified date of its container has to be updated.
825 :param resource:
826 :return:
827 """
828 obj = resource.cast()
829 container = obj.get_container()
830 if container: 830 ↛ exitline 830 didn't return from function 'post_resource_updated', because the condition on line 830 was never false
831 container.last_modified = timezone.now()
832 container.save()
835def update_deployed_date(resource, site, deployed_date_in_prod_to_restore=None, file_=None):
836 """
837 Used by ptf_tools during DeployJatsIssue
839 Update the SiteMembership deployed_date of container/site based on the production website.
840 - If there is no deployed_date in ptf_tools (not yet in prod), we create one.
841 - with deployed_date_in_prod if it's not None (case when we restore data), or
842 - with now if deployed_date_in_prod is None (first deploy in prod)
843 - If the last_modified date of the container in ptf_tools is > deployed_date_in_prod
844 (we have a new version in ptf_tools), we update deployed_date_in_prod with now(),
845 - else we update deployed_date with deployed_date_in_prod
846 (Normally, they should be equal)
848 :param resource:
849 :param site:
850 :param deployed_date_in_prod_to_restore:
851 :param file_ file object to log info
852 :return:
853 """
855 def get_deployed_date_in_prod(resource_, site_):
856 deployed_date_in_prod = None
857 try:
858 membership = SiteMembership.objects.get(resource=resource_, site=site_)
859 deployed_date_in_prod = membership.deployed
860 except SiteMembership.DoesNotExist:
861 pass
863 return deployed_date_in_prod
865 def update_or_create(resource_, site_, deployed):
866 try:
867 membership = SiteMembership.objects.get(resource=resource_, site=site_)
868 membership.deployed = deployed
869 except SiteMembership.DoesNotExist:
870 membership = SiteMembership(resource=resource_, site=site_, deployed=deployed)
871 membership.save()
873 container = article = None
875 if resource.classname == "Article": 875 ↛ 876line 875 didn't jump to line 876, because the condition on line 875 was never true
876 article = resource
877 container = article.my_container
878 else:
879 container = resource
881 existing_deployed_date = get_deployed_date_in_prod(container, site)
883 # If we restore deployed_date, force the new value to the restored value
884 if deployed_date_in_prod_to_restore:
885 new_deployed_date = deployed_date_in_prod_to_restore
886 else:
887 # Get the existing deployed_date_in_prod (from SiteMembership)
888 new_deployed_date = existing_deployed_date
890 # If there is no value of if the current version (last_modified) is newer, update the date
891 if new_deployed_date is None or container.last_modified > new_deployed_date: 891 ↛ 896line 891 didn't jump to line 896, because the condition on line 891 was never false
892 new_deployed_date = timezone.now()
894 # Set the new value to the entire container/articles (+ collection)
896 if file_: 896 ↛ 897line 896 didn't jump to line 897, because the condition on line 896 was never true
897 file_.write(
898 "{}. Date to restore: {}. Container.last_modified: {}, Existing date {}. New date {}\n".format(
899 container.pid,
900 deployed_date_in_prod_to_restore,
901 container.last_modified,
902 existing_deployed_date,
903 new_deployed_date,
904 )
905 )
907 update_or_create(container, site, new_deployed_date)
908 update_or_create(container.get_collection(), site, new_deployed_date)
910 if article is not None: 910 ↛ 911line 910 didn't jump to line 911, because the condition on line 910 was never true
911 update_or_create(article, site, new_deployed_date)
912 else:
913 for article in container.article_set.all():
914 update_or_create(article, site, new_deployed_date)
917def assign_doi(pid):
918 """
919 In the Mersenne process, articles imported for the first time receive a DOI.
920 Thus function creates a new DOI, based on the last doi stored in the Collection object.
921 :param pid:
922 :return: A new DOI, equal to 10.5802/@pid.(last_doi + 1)
923 """
924 collection = get_collection(pid)
926 if collection is None: 926 ↛ 927line 926 didn't jump to line 927, because the condition on line 926 was never true
927 return None
929 last_doi = collection.last_doi + 1
930 collection.last_doi = last_doi
931 collection.save()
933 doi = "10.5802/" + pid.lower() + "." + str(last_doi)
934 return doi
937# TODO make a command ?
940def add_or_update_extid(
941 resource, id_type, id_value, checked, false_positive, update_last_modified=True
942):
943 from ptf.cmds import database_cmds
945 if id_value: 945 ↛ exitline 945 didn't return from function 'add_or_update_extid', because the condition on line 945 was never false
946 extid = get_extid(resource, id_type)
947 if extid:
948 if not extid.checked: 948 ↛ 949line 948 didn't jump to line 949, because the condition on line 948 was never true
949 extid.id_value = id_value
950 extid.checked = checked
951 extid.false_positive = false_positive
952 extid.save()
953 else:
954 cmd = database_cmds.addExtIdDatabaseCmd(
955 {
956 "id_type": id_type,
957 "id_value": id_value,
958 "checked": checked,
959 "false_positive": false_positive,
960 }
961 )
962 cmd.set_resource(resource)
963 cmd.do()
965 # last_modified is not modified during data restoration (importExtraDataPtfCmd)
966 if update_last_modified: 966 ↛ 967line 966 didn't jump to line 967, because the condition on line 966 was never true
967 post_resource_updated(resource)
970def add_or_update_bibitemid(
971 bibitem, id_type, id_value, checked, false_positive, update_last_modified=True
972):
973 from ptf.cmds import database_cmds
974 from ptf.cmds import xml_cmds
976 if id_value: 976 ↛ exitline 976 didn't return from function 'add_or_update_bibitemid', because the condition on line 976 was never false
977 bibitemid = get_bibitemid(bibitem, id_type)
978 if bibitemid:
979 bibitemid.id_value = id_value
980 bibitemid.checked = checked
981 bibitemid.false_positive = false_positive
982 bibitemid.save()
983 else:
984 cmd = database_cmds.addBibItemIdDatabaseCmd(
985 {
986 "id_type": id_type,
987 "id_value": id_value,
988 "checked": checked,
989 "false_positive": false_positive,
990 }
991 )
992 cmd.set_bibitem(bibitem)
993 cmd.do()
995 # Update citation_xml|html|tex
996 cmd = xml_cmds.updateBibitemCitationXmlCmd()
997 cmd.set_bibitem(bibitem)
998 cmd.do()
1000 # last_modified is not modified during data restoration (importExtraDataPtfCmd)
1001 if update_last_modified:
1002 post_resource_updated(bibitem.resource)
1005def get_site_id(collection_id):
1006 result = [v for k, v in SITE_REGISTER.items() if v["collection_pid"] == collection_id]
1007 return result[0]["site_id"] if result else ""
1010def get_collection_id(site_id):
1011 result = [v for k, v in SITE_REGISTER.items() if v["site_id"] == site_id]
1012 return result[0]["collection_pid"] if result else ""
1015def is_site_en_only(site_id):
1016 result = [v for k, v in SITE_REGISTER.items() if v["site_id"] == site_id]
1017 return result[0]["en_only"] if result else False
1020def is_site_fr_only(site_id):
1021 result = [v for k, v in SITE_REGISTER.items() if v["site_id"] == site_id]
1022 return result[0]["fr_only"] if result and "fr_only" in result[0] else False