Coverage for src/ptf/views/components/breadcrumb.py: 75%
222 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-05 09:56 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-05 09:56 +0000
1from __future__ import annotations
3from dataclasses import dataclass
4from dataclasses import field
6from django.conf import settings
7from django.urls import reverse
8from django.urls import reverse_lazy
9from django.utils import timezone
10from django.utils.translation import gettext as translate_text
11from django.utils.translation import gettext_lazy as _
13from ptf.model_helpers import get_issues_in_volume
14from ptf.utils import volume_display
17@dataclass
18class BreadcrumbItem:
19 """
20 Interface for a breadcrumb item.
21 """
23 title: str
24 url: str
25 icon_class: str = field(default="")
26 html: bool = field(default=False)
28 def __init__(self, title: str, url: str, icon_class: str = "", html=False):
29 self.title = title
30 self.url = url
33@dataclass
34class Breadcrumb:
35 """
36 Interface for Breadcrumb data.
37 """
39 previousItem: BreadcrumbItem = None
40 nextItem: BreadcrumbItem = None
41 items: list[BreadcrumbItem] = field(default_factory=list)
43 def add_item(self, title: str, url: str, icon_class: str = "", html=False):
44 self.items.append(BreadcrumbItem(title=title, url=url, icon_class=icon_class, html=html))
47def get_base_breadcrumb() -> Breadcrumb:
48 """
49 Returns a breadcrumb with the default "Home" breadcrumb item.
50 """
51 return Breadcrumb(
52 items=[
53 BreadcrumbItem(
54 title=_("Home"), url=reverse_lazy("mesh:home"), icon_class="fa-house-chimney"
55 )
56 ]
57 )
60# logging.basicConfig(level=logging.DEBUG)
63def get_breadcrumb(resource, is_volume=False): # noqa: F811 (TODO: remove above function)
64 """
65 Solution with a visitor
66 """
67 if settings.SITE_NAME in ["crchim", "crphys", "crmeca", "crbiol", "crgeos", "crmath"]:
68 visitor = BreadcrumbVisitorCR()
69 else:
70 visitor = BreadcrumbVisitor()
72 if is_volume:
73 resource = Volume(resource)
75 crumb = resource.accept(visitor)
77 return crumb
80#########################################################################################
81#
82# Other solutions
83#
84# Solution 1:
85# BCBuilder with functions dynamically added to the Article/Container/Collection
86#
87# Solution 2:
88# BCBuilder Article/Container/Collection mixin dynamically added the base classes
89# a VolumeBCMixin class is added to handle volumes
90#
91# Solution 3:
92# A visitor
93#
94#########################################################################################
96'''
97class BCBuilder:
98 def __init__(self):
99 self.crumb = Breadcrumb()
101 def add_article_bcitem(self, article):
102 display_page = True
103 if hasattr(settings, "PAGE_BREADCRUMB"):
104 display_page = settings.PAGE_BREADCRUMB
105 if display_page:
106 href = article.get_absolute_url()
107 title = article.get_breadcrumb_page_text()
108 self.crumb.add_item(title, href)
110 def add_collection_bcitem(self, collection):
111 href = collection.get_absolute_url()
113 if collection.pid == "MALSM":
114 href = reverse("malsm_books")
116 # We show the collection title instead of the basic 'Feuilleter' for the sites with several collections:
117 # Numdam, Geodesic, Proceedings
118 if settings.COLLECTION_PID in ["ALL", "PROCEEDINGS"]:
119 title = collection.title_html
120 elif collection.pid in settings.CRAS_COLLECTIONS:
121 title = _("Consulter")
122 else:
123 title = _("Feuilleter")
125 self.crumb.add_item(title, href)
127 def add_volume_bcitem(self, container):
128 if container and container.ctype == "issue":
129 volume = VolumeBCMixin(container)
130 href = volume.get_absolute_url()
132 if hasattr(settings, "YEAR_BREADCRUMB"):
133 title = str(container.year)
134 else:
135 title = (
136 "{} {} : ".format(_("Série"), container.vseries) if container.vseries else ""
137 )
138 if container.volume:
139 title += f"{volume_display()} {container.volume} ({container.year})"
140 else:
141 title += "{} {}".format(_("Année"), container.year)
142 self.crumb.add_item(title, href)
144 def add_container_bcitem(self, container):
145 title = ""
146 href = ""
148 colid = container.get_top_collection().pid
149 if colid in settings.CRAS_COLLECTIONS and not container.title_html:
150 year = int(container.year)
151 if (colid != "CRBIOL" and year > 2020) or (colid == "CRBIOL" and year > 2022):
152 now = timezone.now()
153 curyear = str(now.year)
154 if curyear == container.year:
155 title = translate_text("Articles du volume en cours")
156 else:
157 title = translate_text("Articles du volume")
158 href = reverse("volume-general-items", kwargs={"vid": container.get_vid()})
160 if not title and container.number:
161 title = "no." + " " + container.number
162 href = container.get_absolute_url()
164 if title:
165 self.crumb.add_item(title, href)
168#############################################################################
169#
170# Solution 1: BCBuilder with functions
171# (not complete, need to extend the resources with get_next and get_previous)
172#
173#############################################################################
176# def article_build_breadcrumb(self):
177# collection = self.get_top_collection()
178# container = self.get_container()
179#
180# breadcrumb_builder = BCBuilder()
181#
182# breadcrumb_builder.add_collection_bcitem(collection)
183# breadcrumb_builder.add_container_bcitem(container)
184# breadcrumb_builder.add_article_bcitem(self)
185#
186# breadcrumb_builder.set_next_previous_article_bc_items(self)
187#
188# return breadcrumb_builder
189#
190#
191# def container_build_breadcrumb(self):
192# collection = self.get_top_collection()
193#
194# breadcrumb_builder = BCBuilder()
195#
196# breadcrumb_builder.add_collection_bcitem(collection)
197# breadcrumb_builder.add_container_bcitem(self)
198#
199# breadcrumb_builder.set_next_previous_container_bc_items(self)
200#
201# return breadcrumb_builder
202#
203#
204# def collection_build_breadcrumb(self):
205# breadcrumb_builder = BCBuilder()
206#
207# breadcrumb_builder.add_collection_bcitem(self)
208#
209# return breadcrumb_builder
211# Article.build_breadcrumb = article_build_breadcrumb
212# Article.get_next = article_get_next
213# Container.build_breadcrumb = container_build_breadcrumb
214# Container.get_next = container_get_next
215# Collection.build_breadcrumb = collection_build_breadcrumb
218###########################################
219#
220# Solution 2: BCBuilder with mixin
221#
222###########################################
225class ResourceBCMixin:
226 def get_next(self):
227 return None
229 def get_previous(self):
230 return None
232 def _next_in_qs(self, qs):
233 next_item = None
235 if qs.count() > 1:
236 ready_for_next = False
237 for item in qs:
238 if ready_for_next:
239 next_item = item
240 ready_for_next = False
241 if item.pid == self.pid:
242 ready_for_next = True
243 return next_item
246class ArticleBCMixin(ResourceBCMixin):
247 def build_breadcrumb(self):
248 collection = self.get_top_collection()
249 container = self.get_container()
251 breadcrumb_builder = BCBuilder()
253 breadcrumb_builder.add_collection_bcitem(collection)
254 breadcrumb_builder.add_volume_bcitem(container)
255 breadcrumb_builder.add_container_bcitem(container)
256 breadcrumb_builder.add_article_bcitem(self)
258 self.set_next_previous_bc_items(breadcrumb_builder.crumb)
260 return breadcrumb_builder.crumb
262 def get_next(self):
263 next_article = None
265 try:
266 next_article = self.my_container.article_set.get(seq=(self.seq + 1))
267 except (Article.DoesNotExist, MultipleObjectsReturned):
268 pass
270 if next_article is None and not self.my_container.title_html and self.my_container.volume:
271 qs = Container.objects.filter(volume=self.my_container.volume)
272 if qs.count() > 1:
273 qs = qs.order_by("number_int")
274 next_issue = self._next_in_qs(qs)
275 if next_issue:
276 qs = next_issue.article_set.order_by("seq")
277 if qs.exists():
278 next_article = qs.first()
280 return next_article
282 def get_previous(self):
283 previous_article = None
285 try:
286 previous_article = self.my_container.article_set.get(seq=(self.seq - 1))
287 except (Article.DoesNotExist, MultipleObjectsReturned):
288 pass
290 if (
291 previous_article is None
292 and not self.my_container.title_html
293 and self.my_container.volume
294 ):
295 qs = Container.objects.filter(volume=self.my_container.volume)
296 if qs.count() > 1:
297 qs = qs.order_by("-number_int")
298 previous_issue = self._next_in_qs(qs)
299 if previous_issue:
300 qs = previous_issue.article_set.order_by("-seq")
301 if qs.exists():
302 previous_article = qs.first()
304 return previous_article
306 def set_next_previous_bc_items(self, crumb):
307 next_article = self.get_next()
308 if next_article is not None:
309 crumb.nextItem = BreadcrumbItem(
310 translate_text("Suivant"), next_article.get_absolute_url()
311 )
313 previous_article = self.get_previous()
314 if previous_article is not None:
315 crumb.previousItem = BreadcrumbItem(
316 translate_text("Précédent"), previous_article.get_absolute_url()
317 )
319 # Les articles de CRAS des volumes généraux sont mis dans plusieurs containers (G1, G2, ...)
320 # On regarde s'il y a un numéro (caché) suivant/précédant pour y prendre le premier/dernier article
321 if (next_article is None or previous_article is None) and not self.my_container.title_html:
322 issues_article, collection = get_issues_in_volume(self.my_container.pid, True, True)
324 if next_article is None:
325 return_next = None
326 current_found = False
327 index = 0
328 articles = issues_article[0]["articles"]
329 while index < len(articles) and return_next is None:
330 if current_found:
331 return_next = articles[index]
332 if articles[index].pid == self.pid:
333 current_found = True
334 index += 1
335 if return_next is not None:
336 crumb.nextItem = BreadcrumbItem(
337 translate_text("Suivant"), return_next.get_absolute_url()
338 )
339 if previous_article is None:
340 return_prev = None
341 current_found = False
342 articles = issues_article[0]["articles"]
343 index = len(articles) - 1
344 while index >= 0 and return_prev is None:
345 if current_found:
346 return_prev = articles[index]
347 if articles[index].pid == self.pid:
348 current_found = True
349 index -= 1
350 if return_prev is not None:
351 crumb.previousItem = BreadcrumbItem(
352 translate_text("Précédent"), return_prev.get_absolute_url()
353 )
356class ContainerBCMixin(ResourceBCMixin):
357 def build_breadcrumb(self):
358 collection = self.get_top_collection()
360 breadcrumb_builder = BCBuilder()
362 breadcrumb_builder.add_collection_bcitem(collection)
363 breadcrumb_builder.add_volume_bcitem(self)
364 breadcrumb_builder.add_container_bcitem(self)
366 self.set_next_previous_bc_items(breadcrumb_builder.crumb)
368 return breadcrumb_builder.crumb
370 def get_next(self):
371 # No Next/Previous for CRAS Special Issues or "Volume articles"
372 colid = self.get_top_collection().pid
373 if colid in settings.CRAS_COLLECTIONS:
374 year = int(self.year)
375 if (
376 self.title_html
377 or (colid != "CRBIOL" and year > 2020)
378 or (colid == "CRBIOL" and year > 2022)
379 ):
380 return None
382 collection = self.get_top_collection()
383 if collection.pid in settings.COLLECTIONS_SEQUENCED:
384 qs = collection.content.order_by("seq")
385 else:
386 qs = collection.content.order_by("vseries_int", "year", "volume_int", "number_int")
388 next_issue = self._next_in_qs(qs)
389 return next_issue
391 def get_previous(self):
392 # No Next/Previous for CRAS Special Issues or "Volume articles"
393 colid = self.get_top_collection().pid
394 if colid in settings.CRAS_COLLECTIONS:
395 year = int(self.year)
396 if (
397 self.title_html
398 or (colid != "CRBIOL" and year > 2020)
399 or (colid == "CRBIOL" and year > 2022)
400 ):
401 return None
403 collection = self.get_top_collection()
404 if collection.pid in settings.COLLECTIONS_SEQUENCED:
405 qs = collection.content.order_by("-seq")
406 else:
407 qs = collection.content.order_by("-vseries_int", "-year", "-volume_int", "-number_int")
408 next_issue = self._next_in_qs(qs)
409 return next_issue
411 def set_next_previous_bc_items(self, crumb):
412 next_container = self.get_next()
413 if next_container is not None:
414 title = translate_text("Suivant")
415 href = next_container.get_absolute_url()
416 crumb.nextItem = BreadcrumbItem(title, href)
418 previous_container = self.get_previous()
419 if previous_container is not None:
420 title = translate_text("Précédent")
421 href = previous_container.get_absolute_url()
422 crumb.previousItem = BreadcrumbItem(title, href)
425class VolumeBCMixin(ContainerBCMixin):
426 """
427 There is no Volume class in the PTF Model.
428 VolumeBCMixin is not a mixin but a full class.
429 In order to work with get_breadcrumb, we need to add Resource functions such as get_absolute_url
430 """
432 def __init__(self, container_bc, **kwargs):
433 super().__init__(**kwargs)
434 self.container_bc = container_bc
436 def __getattribute__(self, name):
437 try:
438 value = super().__getattribute__(name)
439 except AttributeError:
440 value = self.container_bc.__getattribute__(name)
441 return value
443 def build_breadcrumb(self):
444 collection = self.container_bc.get_top_collection()
446 breadcrumb_builder = BCBuilder()
448 breadcrumb_builder.add_collection_bcitem(collection)
449 breadcrumb_builder.add_volume_bcitem(self)
451 self.set_next_previous_bc_items(breadcrumb_builder.crumb)
453 return breadcrumb_builder.crumb
455 def get_absolute_url(self):
456 if hasattr(settings, "YEAR_BREADCRUMB"):
457 href = reverse("articles-year", kwargs={"year": self.container_bc.year})
458 else:
459 href = reverse("volume-items", kwargs={"vid": self.container_bc.get_vid()})
461 return href
463 def _next_in_volume_qs(self, qs):
464 next_item = None
466 if qs.count() > 1:
467 ready_for_next = False
468 for item in qs:
469 if ready_for_next and (
470 item.year != self.container_bc.year or item.volume != self.container_bc.volume
471 ):
472 next_item = item
473 ready_for_next = False
474 if item.pid == self.container_bc.pid:
475 ready_for_next = True
476 return next_item
478 def get_next(self):
479 next_container = None
480 collection = self.container_bc.get_top_collection()
481 if collection.pid in settings.COLLECTIONS_SEQUENCED:
482 next_container = self.container_bc.get_next()
483 else:
484 qs = collection.content.order_by("vseries_int", "year", "volume_int", "number_int")
485 next_container = self._next_in_volume_qs(qs)
487 if next_container:
488 # Convert to VolumeBCMixin to have access to the "volume" get_absolute_url
489 next_container = VolumeBCMixin(next_container)
491 return next_container
493 def get_previous(self):
494 previous_container = None
495 collection = self.container_bc.get_top_collection()
496 if collection.pid in settings.COLLECTIONS_SEQUENCED:
497 previous_container = self.container_bc.get_previous()
498 else:
499 qs = collection.content.order_by("-vseries_int", "-year", "-volume_int", "-number_int")
500 previous_container = self._next_in_volume_qs(qs)
502 if previous_container:
503 # Convert to VolumeBCMixin to have access to the "volume" get_absolute_url
504 previous_container = VolumeBCMixin(previous_container)
506 return previous_container
509class CollectionBCMixin(ResourceBCMixin):
510 def build_breadcrumb(self):
511 breadcrumb_builder = BCBuilder()
513 breadcrumb_builder.add_collection_bcitem(self)
515 return breadcrumb_builder.crumb
517'''
518###########################################
519#
520# Solution 3: a visitor
521#
522###########################################
525class BreadcrumbVisitor:
526 def __init__(self):
527 self.crumb = Breadcrumb()
529 def visit(self, resource):
530 meth = getattr(self, "visit_" + resource.classname.lower())
531 return meth(resource)
533 def visit_article(self, article):
534 collection = article.get_top_collection()
535 container = article.get_container()
537 self._add_collection_bcitem(collection)
538 self._add_volume_bcitem(container)
539 self._add_container_bcitem(container)
540 self._add_article_bcitem(article)
542 next_article, previous_article = self.set_next_previous_article_bc_items(article)
543 if next_article is not None: 543 ↛ 544line 543 didn't jump to line 544 because the condition on line 543 was never true
544 self.crumb.nextItem = BreadcrumbItem(
545 translate_text("Suivant"), next_article.get_absolute_url()
546 )
548 if previous_article is not None: 548 ↛ 549line 548 didn't jump to line 549 because the condition on line 548 was never true
549 self.crumb.previousItem = BreadcrumbItem(
550 translate_text("Précédent"), previous_article.get_absolute_url()
551 )
553 return self.crumb
555 def visit_container(self, container):
556 collection = container.get_top_collection()
558 self._add_collection_bcitem(collection)
559 self._add_volume_bcitem(container)
560 self._add_container_bcitem(container)
562 self.set_next_previous_container_bc_items(container)
564 return self.crumb
566 def visit_volume(self, volume):
567 collection = volume.get_top_collection()
569 self._add_collection_bcitem(collection)
570 self._add_volume_bcitem(volume)
572 self.set_next_previous_container_bc_items(volume)
574 return self.crumb
576 def visit_collection(self, collection):
577 self._add_collection_bcitem(collection)
579 return self.crumb
581 def _add_article_bcitem(self, article):
582 display_page = True
583 if hasattr(settings, "PAGE_BREADCRUMB"): 583 ↛ 584line 583 didn't jump to line 584 because the condition on line 583 was never true
584 display_page = settings.PAGE_BREADCRUMB
585 if display_page: 585 ↛ exitline 585 didn't return from function '_add_article_bcitem' because the condition on line 585 was always true
586 href = article.get_absolute_url()
587 title = article.get_breadcrumb_page_text()
588 self.crumb.add_item(title, href)
590 def _add_collection_bcitem(self, collection):
591 href = collection.get_absolute_url()
593 if collection.pid == "MALSM": 593 ↛ 594line 593 didn't jump to line 594 because the condition on line 593 was never true
594 href = reverse("malsm_books")
596 # We show the collection title instead of the basic 'Feuilleter' for the sites with several collections:
597 # Numdam, Geodesic, Proceedings
598 if settings.COLLECTION_PID in ["ALL", "PROCEEDINGS"]: 598 ↛ 600line 598 didn't jump to line 600 because the condition on line 598 was always true
599 title = collection.title_html
600 elif collection.pid in settings.CRAS_COLLECTIONS:
601 title = _("Consulter")
602 else:
603 title = _("Feuilleter")
605 self.crumb.add_item(title, href)
607 def _add_volume_bcitem(self, container):
608 if container and container.ctype == "issue":
609 volume = Volume(container)
610 href = volume.get_absolute_url()
612 if hasattr(settings, "YEAR_BREADCRUMB"): 612 ↛ 613line 612 didn't jump to line 613 because the condition on line 612 was never true
613 title = str(container.year)
614 else:
615 title = (
616 "{} {} : ".format(_("Série"), container.vseries) if container.vseries else ""
617 )
618 if container.volume: 618 ↛ 619line 618 didn't jump to line 619 because the condition on line 618 was never true
619 title += f"{volume_display()} {container.volume} ({container.year})"
620 else:
621 title += "{} {}".format(_("Année"), container.year)
622 self.crumb.add_item(title, href)
624 def _add_container_bcitem(self, container):
625 title = ""
626 href = ""
628 colid = container.get_top_collection().pid
629 if colid in settings.CRAS_COLLECTIONS and not container.title_html:
630 year = int(container.year)
631 if (colid != "CRBIOL" and year > 2020) or (colid == "CRBIOL" and year > 2022):
632 now = timezone.now()
633 curyear = str(now.year)
634 if curyear == container.year: 634 ↛ 635line 634 didn't jump to line 635 because the condition on line 634 was never true
635 title = translate_text("Articles du volume en cours")
636 else:
637 title = translate_text("Articles du volume")
638 href = reverse("volume-general-items", kwargs={"vid": container.get_vid()})
640 if not title and container.number:
641 title = "no." + " " + container.number
642 href = container.get_absolute_url()
644 if title: 644 ↛ exitline 644 didn't return from function '_add_container_bcitem' because the condition on line 644 was always true
645 self.crumb.add_item(title, href)
647 def set_next_previous_container_bc_items(self, container):
648 next_container = container.get_next_resource()
649 if next_container is not None: 649 ↛ 650line 649 didn't jump to line 650 because the condition on line 649 was never true
650 title = translate_text("Suivant")
651 href = next_container.get_absolute_url()
652 self.crumb.nextItem = BreadcrumbItem(title, href)
654 previous_container = container.get_previous_resource()
655 if previous_container is not None: 655 ↛ 656line 655 didn't jump to line 656 because the condition on line 655 was never true
656 title = translate_text("Précédent")
657 href = previous_container.get_absolute_url()
658 self.crumb.previousItem = BreadcrumbItem(title, href)
660 def set_next_previous_article_bc_items(self, article):
661 next_article = article.get_next_resource()
662 if next_article is not None: 662 ↛ 663line 662 didn't jump to line 663 because the condition on line 662 was never true
663 self.crumb.nextItem = BreadcrumbItem(
664 translate_text("Suivant"), next_article.get_absolute_url()
665 )
667 previous_article = article.get_previous_resource()
668 if previous_article is not None: 668 ↛ 669line 668 didn't jump to line 669 because the condition on line 668 was never true
669 self.crumb.previousItem = BreadcrumbItem(
670 translate_text("Précédent"), previous_article.get_absolute_url()
671 )
672 return next_article, previous_article
675class BreadcrumbVisitorCR(BreadcrumbVisitor):
676 def set_next_previous_article_bc_items(self, article):
677 next_article, previous_article = super().set_next_previous_article_bc_items(article)
678 # Les articles de CRAS des volumes généraux sont mis dans plusieurs containers (G1, G2, ...)
679 # On regarde s'il y a un numéro (caché) suivant/précédant pour y prendre le premier/dernier article
680 if not article.my_container.title_html: 680 ↛ 713line 680 didn't jump to line 713 because the condition on line 680 was always true
681 issues_article, collection = get_issues_in_volume(article.my_container.pid, True, True)
683 if next_article is None: 683 ↛ 698line 683 didn't jump to line 698 because the condition on line 683 was always true
684 return_next = None
685 current_found = False
686 index = 0
687 articles = issues_article[0]["articles"]
688 while index < len(articles) and return_next is None:
689 if current_found: 689 ↛ 690line 689 didn't jump to line 690 because the condition on line 689 was never true
690 return_next = articles[index]
691 if articles[index].pid == article.pid: 691 ↛ 693line 691 didn't jump to line 693 because the condition on line 691 was always true
692 current_found = True
693 index += 1
694 if return_next is not None: 694 ↛ 695line 694 didn't jump to line 695 because the condition on line 694 was never true
695 self.crumb.nextItem = BreadcrumbItem(
696 translate_text("Suivant"), return_next.get_absolute_url()
697 )
698 if previous_article is None: 698 ↛ 713line 698 didn't jump to line 713 because the condition on line 698 was always true
699 return_prev = None
700 current_found = False
701 articles = issues_article[0]["articles"]
702 index = len(articles) - 1
703 while index >= 0 and return_prev is None:
704 if current_found: 704 ↛ 705line 704 didn't jump to line 705 because the condition on line 704 was never true
705 return_prev = articles[index]
706 if articles[index].pid == article.pid: 706 ↛ 708line 706 didn't jump to line 708 because the condition on line 706 was always true
707 current_found = True
708 index -= 1
709 if return_prev is not None: 709 ↛ 710line 709 didn't jump to line 710 because the condition on line 709 was never true
710 self.crumb.previousItem = BreadcrumbItem(
711 translate_text("Précédent"), return_prev.get_absolute_url()
712 )
713 return next_article, previous_article
716class Volume:
717 """
718 There is no Volume class in the PTF Model.
719 Add it here to handle breadcrumb code for volumes
720 """
722 def __init__(self, container, **kwargs):
723 super().__init__(**kwargs)
724 self.container = container
725 self.classname = "Volume"
727 def __getattribute__(self, name):
728 try:
729 value = super().__getattribute__(name)
730 except AttributeError:
731 value = self.container.__getattribute__(name)
732 return value
734 def cast(self):
735 return self
737 def accept(self, visitor):
738 """
739 We need to copy the resource:accept function here.
740 If we do not, the call to volume.accept() will look for accept.
741 The __get__attribute__ function will find the accept function of the encapsulated container function
742 => accept will be called for the encapsulated container
743 """
744 return visitor.visit(self)
746 def get_absolute_url(self):
747 if hasattr(settings, "YEAR_BREADCRUMB"): 747 ↛ 748line 747 didn't jump to line 748 because the condition on line 747 was never true
748 href = reverse("articles-year", kwargs={"year": self.container.year})
749 else:
750 href = reverse("volume-items", kwargs={"vid": self.container.get_vid()})
752 return href
754 def _next_in_volume_qs(self, qs):
755 next_item = None
757 if qs.count() > 1: 757 ↛ 758line 757 didn't jump to line 758 because the condition on line 757 was never true
758 ready_for_next = False
759 for item in qs:
760 if ready_for_next and (
761 item.year != self.container.year or item.volume != self.container.volume
762 ):
763 next_item = item
764 ready_for_next = False
765 if item.pid == self.container.pid:
766 ready_for_next = True
767 return next_item
769 def get_next_resource(self):
770 next_container = None
771 collection = self.container.get_top_collection()
772 if collection.pid in settings.COLLECTIONS_SEQUENCED: 772 ↛ 773line 772 didn't jump to line 773 because the condition on line 772 was never true
773 next_container = self.container.get_next_resource()
774 else:
775 qs = collection.content.order_by("vseries_int", "year", "volume_int", "number_int")
776 next_container = self._next_in_volume_qs(qs)
778 if next_container: 778 ↛ 780line 778 didn't jump to line 780 because the condition on line 778 was never true
779 # Convert to VolumeBCMixin to have access to the "volume" get_absolute_url
780 next_container = Volume(next_container)
782 return next_container
784 def get_previous_resource(self):
785 previous_container = None
786 collection = self.container.get_top_collection()
787 if collection.pid in settings.COLLECTIONS_SEQUENCED: 787 ↛ 788line 787 didn't jump to line 788 because the condition on line 787 was never true
788 previous_container = self.container.get_previous_resource()
789 else:
790 qs = collection.content.order_by("-vseries_int", "-year", "-volume_int", "-number_int")
791 previous_container = self._next_in_volume_qs(qs)
793 if previous_container: 793 ↛ 795line 793 didn't jump to line 795 because the condition on line 793 was never true
794 # Convert to VolumeBCMixin to have access to the "volume" get_absolute_url
795 previous_container = Volume(previous_container)
797 return previous_container