Coverage for apps/ptf/cmds/database_cmds.py: 61%
1178 statements
« prev ^ index » next coverage.py v7.3.2, created at 2024-11-04 17:46 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2024-11-04 17:46 +0000
1from unidecode import unidecode
3from django.conf import settings
4from django.db.models import Q
5from django.utils import timezone
7from ptf import exceptions
8from ptf import model_helpers
10from ..models import Abstract
11from ..models import Article
12from ..models import Author
13from ..models import Award
14from ..models import BibItem
15from ..models import BibItemId
16from ..models import Collection
17from ..models import CollectionMembership
18from ..models import Container
19from ..models import Contrib
20from ..models import ContribAddress
21from ..models import Contribution
22from ..models import DataStream
23from ..models import ExtId
24from ..models import ExtLink
25from ..models import FrontMatter
26from ..models import Kwd
27from ..models import MetaDataPart
28from ..models import Provider
29from ..models import PtfSite
30from ..models import Publisher
31from ..models import RelatedObject
32from ..models import RelationName
33from ..models import Relationship
34from ..models import ResourceCount
35from ..models import ResourceId
36from ..models import ResourceInSpecialIssue
37from ..models import SiteMembership
38from ..models import Stats
39from ..models import Subj
40from ..models import SupplementaryMaterial
41from ..models import TranslatedArticle
42from ..models import XmlBase
43from ..models import parse_page_count
44from .base_cmds import baseCmd
45from .base_cmds import make_int
47# from .xml.jats import jats_parser
49# TODO: call full_clean before each .save() call to validate a Model object
50# It requires to update models.py and add some blank=True to fields that can be null/empty
51# Example: number and vseries for a Container
54def get_first_letter(name):
55 letter = ""
56 if name:
57 letter = name[0]
58 letter = unidecode(letter)
59 if len(letter) > 1:
60 letter = letter[0]
61 letter = letter.upper()
62 if letter == "?":
63 letter = "Z"
65 # with 't Hooft, G => first_letter is H
66 if name.startswith("'t") and len(name) > 3:
67 letter = name[3].upper()
69 return letter
72def add_contributors(contributors, resource=None, bibitem=None):
73 if resource is None and bibitem is None: 73 ↛ 74line 73 didn't jump to line 74, because the condition on line 73 was never true
74 raise RuntimeError("add_contributors: resource and bibitem are None")
76 seq = 0
77 for contrib in contributors:
78 seq += 1
80 contrib["seq"] = seq
81 contribution_fields_list = Contribution.get_fields_list()
82 contributions_fields = {
83 key: contrib[key] for key in contribution_fields_list if key in contrib
84 }
86 contribution = Contribution(resource=resource, bibitem=bibitem, **contributions_fields)
87 contribution.save()
89 for addr in contrib["addresses"]:
90 contrib_address = ContribAddress(contribution=contribution, address=addr)
91 contrib_address.save()
93 if bibitem is None and contribution.role == "author" and not contribution.is_etal():
94 ref_name = contribution.mid if contribution.mid else str(contribution)
95 try:
96 author = Author.objects.get(name=ref_name)
97 author.count += 1
98 except Author.DoesNotExist:
99 letter = ref_name[0]
100 letter = unidecode(letter)
101 if len(letter) > 1: 101 ↛ 102line 101 didn't jump to line 102, because the condition on line 101 was never true
102 letter = letter[0]
103 letter = letter.upper()
104 if letter == "?": 104 ↛ 105line 104 didn't jump to line 105, because the condition on line 104 was never true
105 letter = "Z"
107 # with 't Hooft, G => first_letter is H
108 if ref_name.startswith("'t") and len(ref_name) > 3: 108 ↛ 109line 108 didn't jump to line 109, because the condition on line 108 was never true
109 letter = ref_name[3].upper()
111 author = Author(name=ref_name, first_letter=letter, count=1)
112 author.save()
115def add_counts(xobj, resource, add_total=False):
116 seq = 1
117 for name, value in xobj.counts:
118 try:
119 ResourceCount.objects.get(resource=resource, name=name)
120 raise exceptions.ResourceExists(f"The ResourceCount {name} already exists")
121 except ResourceCount.DoesNotExist:
122 resource_count = ResourceCount(resource=resource, name=name, seq=seq, value=value)
124 resource_count.save()
126 if name == "page-count" and add_total: 126 ↛ 137line 126 didn't jump to line 137, because the condition on line 126 was never false
127 value = parse_page_count(value)
129 try:
130 total = Stats.objects.get(name=name)
131 total.value += value
132 except Stats.DoesNotExist:
133 total = Stats(name=name, value=value)
135 total.save()
137 seq += 1
140def add_biblio(xobj, resource):
141 for seq, xbibitem in enumerate(xobj.bibitems, start=1):
142 bibitem = BibItem(
143 resource=resource,
144 sequence=seq,
145 label=xbibitem.label,
146 citation_xml=xbibitem.citation_xml,
147 citation_tex=xbibitem.citation_tex,
148 citation_html=xbibitem.citation_html,
149 type=xbibitem.type,
150 user_id=xbibitem.user_id,
151 article_title_tex=xbibitem.article_title_tex,
152 chapter_title_tex=xbibitem.chapter_title_tex,
153 source_tex=xbibitem.source_tex,
154 publisher_name=xbibitem.publisher_name,
155 publisher_loc=xbibitem.publisher_loc,
156 institution=xbibitem.institution,
157 series=xbibitem.series,
158 volume=xbibitem.volume,
159 issue=xbibitem.issue,
160 month=xbibitem.month,
161 year=xbibitem.year,
162 comment=xbibitem.comment,
163 annotation=xbibitem.annotation,
164 fpage=xbibitem.fpage,
165 lpage=xbibitem.lpage,
166 page_range=xbibitem.page_range,
167 size=xbibitem.size,
168 )
170 bibitem.save()
172 add_contributors(contributors=xbibitem.contributors, bibitem=bibitem)
174 if xbibitem.extids:
175 the_types = []
176 for id_type, id_value in xbibitem.extids:
177 if id_type and id_type not in the_types:
178 the_types.append(id_type)
180 bibitemid = BibItemId(
181 bibitem=bibitem,
182 id_type=id_type,
183 id_value=id_value,
184 checked=True,
185 false_positive=False,
186 )
188 bibitemid.save()
191def add_relations(xobj, resource):
192 for relation in xobj.relations:
193 with_doi = "10." in relation.id_value
194 if with_doi and resource.doi is None: 194 ↛ 195line 194 didn't jump to line 195, because the condition on line 194 was never true
195 raise ValueError(
196 f"The article {resource.pid} has no DOI but uses the relation {relation.rel_type} with the DOI {relation.id_value}"
197 )
199 # First, we need to find if the relation is stored in the RelationName as a left or right attribute
200 name = relation.rel_type
201 relationname = model_helpers.get_relationname_left(left_name=name)
203 if relationname:
204 # RelationName with a left attribute (ex "follows"):
205 # the subject of the relationship is the xml parent (typically the article defined by the xml)
206 # the object is the id declared by the <related-article>
207 # Example <article>
208 # <article_id ...>A</article-id>
209 # <related-article ... related-article-type="follows">B</related-article>
210 # => RelationShip with subject = A and object = B
212 subject_pid = resource.doi if with_doi else resource.pid
213 subject_resource = resource
214 object_pid = relation.id_value
215 # Find the resource to update the related article
216 # But to work during a regular import, the related article must already be in the database
217 # Depending on the import order, it might not work
218 if with_doi: 218 ↛ 219line 218 didn't jump to line 219, because the condition on line 218 was never true
219 object_resource = model_helpers.get_article_by_doi(relation.id_value)
220 else:
221 object_resource = model_helpers.get_article(relation.id_value)
222 else:
223 relationname = model_helpers.get_relationname_right(right_name=name)
225 if relationname: 225 ↛ 247line 225 didn't jump to line 247, because the condition on line 225 was never false
226 # RelationName with a right attribute (ex "followed-by"):
227 # the subject of the relationship is the id declared by the <related-article>
228 # the object is the xml parent (typically the article defined by the xml)
229 # Example <article>
230 # <article_id ...>A</article-id>
231 # <related-article ... related-article-type="followed-by">B</related-article>
232 # => RelationShip with subject = B and object = A
234 subject_pid = relation.id_value
235 # Find the resource to update the related article
236 # But to work during a regular import, the related article must already be in the database
237 # Depending on the import order, it might not work
238 if with_doi: 238 ↛ 239line 238 didn't jump to line 239, because the condition on line 238 was never true
239 subject_resource = model_helpers.get_article_by_doi(relation.id_value)
240 else:
241 subject_resource = model_helpers.get_article(relation.id_value)
243 object_pid = resource.doi if with_doi else resource.pid
244 object_resource = resource
246 # Elsevier creates basic relation. Create the relationname on the fly if necessary
247 if not relationname and name == "refers to": 247 ↛ 248line 247 didn't jump to line 248, because the condition on line 247 was never true
248 relationname = RelationName(
249 left="refers to",
250 right="is referenced by",
251 gauche="fait référence à",
252 droite="est référencé par",
253 )
254 relationname.save()
256 subject_pid = resource.doi if with_doi else resource.pid
257 subject_resource = resource
258 object_pid = relation.id_value
259 # Find the resource to update the related article
260 # But to work during a regular import, the related article must already be in the database
261 # Depending on the import order, it might not work
262 if with_doi:
263 object_resource = model_helpers.get_article_by_doi(relation.id_value)
264 else:
265 object_resource = model_helpers.get_article(relation.id_value)
267 if relationname: 267 ↛ 192line 267 didn't jump to line 192, because the condition on line 267 was never false
268 params = {"subject_pid": subject_pid, "object_pid": object_pid, "solr_commit": False}
269 cmd = addRelationshipDatabaseCmd(params)
270 if subject_resource is not None:
271 cmd.set_subject_resource(subject_resource)
272 if object_resource is not None:
273 cmd.set_object_resource(object_resource)
274 cmd.set_relationname(relationname)
276 try:
277 relationship = Relationship.objects.get(
278 subject_pid=subject_pid, object_pid=object_pid, rel_info=relationname
279 )
280 # la première fois que l'on crée la relation une des 2 ressources ID est a priori None
281 # la deuxième fois (la relation symétrique) il faut compléter la
282 # RelationShip
283 if relationship.resource is not None and relationship.related is not None: 283 ↛ 284line 283 didn't jump to line 284, because the condition on line 283 was never true
284 raise exceptions.ResourceExists(
285 f"The Relationship {subject_pid} {relationname.left} {object_pid} already exists"
286 )
287 if subject_resource is not None: 287 ↛ 289line 287 didn't jump to line 289, because the condition on line 287 was never false
288 relationship.resource = subject_resource
289 if object_resource is not None: 289 ↛ 291line 289 didn't jump to line 291, because the condition on line 289 was never false
290 relationship.related = object_resource
291 relationship.save()
293 except Relationship.DoesNotExist:
294 relationship = Relationship(
295 subject_pid=subject_pid,
296 object_pid=object_pid,
297 resource=subject_resource,
298 related=object_resource,
299 rel_info=relationname,
300 )
301 relationship.save()
304def add_frontmatter(xobj, resource):
305 if hasattr(xobj, "frontmatter_xml") and xobj.frontmatter_xml is not None:
306 frontmatter = FrontMatter(
307 resource=resource,
308 value_xml=xobj.frontmatter_xml,
309 value_html=xobj.frontmatter_toc_html,
310 foreword_html=xobj.frontmatter_foreword_html,
311 )
312 frontmatter.save()
315def add_publisher(xobj):
316 if hasattr(xobj, "publisher") and xobj.publisher:
317 publisher = model_helpers.get_publisher(xobj.publisher.name)
319 if publisher is None:
320 cmd = addPublisherDatabaseCmd({"xobj": xobj.publisher})
321 publisher = cmd.do()
323 return publisher
326class addSiteDatabaseCmd(baseCmd):
327 """
328 addSiteDatabaseCmd: adds/remove a PtfSite
330 Exception raised:
331 - ValueError if the init params are empty
332 - exceptions.ResourceExists during do if the site already exists
333 - exceptions.ResourceDoesNotExist during undo if the site does not exist
334 - RuntimeError during undo if resources are still deployed
335 """
337 def __init__(self, params=None):
338 self.site_name = None
339 self.site_domain = None
340 self.site_id = None
342 super().__init__(params)
344 if not self.site_name: 344 ↛ 345line 344 didn't jump to line 345, because the condition on line 344 was never true
345 self.site_name = settings.SITE_NAME
347 if not self.site_domain: 347 ↛ 348line 347 didn't jump to line 348, because the condition on line 347 was never true
348 self.site_domain = settings.SITE_DOMAIN
350 self.required_params.extend(["site_name", "site_domain", "site_id"])
352 # Returns a PtfSite
353 def internal_do(self) -> PtfSite:
354 super().internal_do()
356 try:
357 PtfSite.objects.get(name=self.site_name)
358 raise exceptions.ResourceExists(
359 "The site " + self.site_name + " " + self.site_domain + " already exists"
360 )
361 except PtfSite.DoesNotExist:
362 site = PtfSite(
363 domain=self.site_domain, name=self.site_name, acro=self.site_name, id=self.site_id
364 )
365 site.save()
367 return site
369 def pre_undo(self):
370 super().pre_undo()
372 if SiteMembership.objects.filter(site__name=self.site_name).exists():
373 raise RuntimeError(
374 "Impossible de supprimer le site car il y a encore des ressources publiees"
375 )
377 def internal_undo(self):
378 super().internal_undo()
380 try:
381 # may throw PtfSite.DoesNotExist
382 site = PtfSite.objects.get(name=self.site_name)
383 id = site.id
384 site.delete()
385 except PtfSite.DoesNotExist:
386 raise exceptions.ResourceDoesNotExist("The site " + self.site_name + " does not exist")
388 return id
391class addProviderDatabaseCmd(baseCmd):
392 """
393 addProviderDatabaseCmd: adds/remove a Provider
395 Exception raised:
396 - ValueError if the init params are empty
397 - exceptions.ResourceExists during do if the provider already exists
398 - exceptions.ResourceDoesNotExist during undo if the provider does not exist
399 """
401 def __init__(self, params=None):
402 self.name = None
403 self.pid_type = None
404 self.sid_type = None
406 super().__init__(params)
408 self.required_params.extend(["name", "pid_type"])
410 def internal_do(self):
411 super().internal_do()
413 try:
414 Provider.objects.get(name=self.name, pid_type=self.pid_type, sid_type=self.sid_type)
415 raise exceptions.ResourceExists("The provider " + self.name + " already exists")
416 except Provider.DoesNotExist:
417 p = Provider(name=self.name, pid_type=self.pid_type, sid_type=self.sid_type)
418 p.save()
420 return p
422 def internal_undo(self):
423 super().internal_undo()
425 try:
426 p = Provider.objects.get(
427 name=self.name, pid_type=self.pid_type, sid_type=self.sid_type
428 )
429 id = p.id
430 p.delete()
431 except Provider.DoesNotExist:
432 raise exceptions.ResourceDoesNotExist("The provider " + self.name + " does not exist")
434 return id
437class addXmlBaseDatabaseCmd(baseCmd):
438 """
439 addXmlBaseDatabaseCmd: adds/remove an XmlBase
441 XmlBase is the root URL of an ExtLink (ex: http://archive.numdam.org/article)
443 Exception raised:
444 - ValueError if the init params are empty
445 - exceptions.ResourceExists during do if the XmlBase already exists
446 - exceptions.ResourceDoesNotExist during undo if the XmlBase does not exist
447 - RuntimeError during undo if related extlinks or objects still exist
448 """
450 def __init__(self, params=None):
451 self.base = None # Ex: http://archive.numdam.org/article
453 super().__init__(params)
455 self.required_params.extend(["base"])
457 def internal_do(self):
458 super().internal_do()
460 try:
461 XmlBase.objects.get(base=self.base)
462 raise exceptions.ResourceExists("The xmlbase " + self.base + " already exists")
463 except XmlBase.DoesNotExist:
464 xmlbase = XmlBase(base=self.base)
465 xmlbase.save()
467 return xmlbase
469 def internal_undo(self):
470 super().internal_undo()
472 try:
473 xmlbase = XmlBase.objects.get(base=self.base)
474 id = xmlbase.id
475 except XmlBase.DoesNotExist:
476 raise exceptions.ResourceDoesNotExist("The xmlbase " + self.base + " does not exist")
478 try:
479 extlink = ExtLink.objects.get(base=xmlbase)
481 if extlink:
482 raise RuntimeError(
483 "Impossible de supprimer cette ressource car elle est encore utilisee par des ExtLinks"
484 )
486 except ExtLink.DoesNotExist:
487 pass
489 try:
490 related_object = RelatedObject.objects.get(base=xmlbase)
492 if related_object:
493 raise RuntimeError(
494 "Impossible de supprimer cette ressource car elle est encore utilisee par des RelatedObjects"
495 )
497 except RelatedObject.DoesNotExist:
498 pass
500 xmlbase.delete()
501 return id
504class addExtLinkDatabaseCmd(baseCmd):
505 """
506 addExtLinkDatabaseCmd: adds/remove an ExtLink
507 An extlink is a link to an external object (image...)
509 Exception raised:
510 - ValueError if the init params are empty
511 - exceptions.ResourceExists during do if the ExtLink already exists
512 - exceptions.ResourceDoesNotExist during undo if the ExtLink does not exist
513 - RuntimeError during undo if resources are still deployed
514 """
516 def __init__(self, params=None):
517 self.rel = None # 'website' or 'small_icon'
518 self.mimetype = None
519 self.location = None
520 self.metadata = None
521 self.seq = None
522 self.resource = None
523 self.base = None
525 super().__init__(params)
527 self.required_params.extend(["rel", "location", "seq", "resource"])
529 def set_resource(self, resource):
530 self.resource = resource
532 def set_base(self, base):
533 self.base = base
535 def internal_do(self):
536 super().internal_do()
538 try:
539 ExtLink.objects.get(
540 resource=self.resource,
541 base=self.base,
542 rel=self.rel,
543 mimetype=self.mimetype,
544 location=self.location,
545 metadata=self.metadata,
546 seq=self.seq,
547 )
548 raise exceptions.ResourceExists(
549 "The ExtLink " + self.base + " " + self.rel + " already exists"
550 )
551 except ExtLink.DoesNotExist:
552 extlink = ExtLink(
553 resource=self.resource,
554 base=self.base,
555 rel=self.rel,
556 mimetype=self.mimetype,
557 location=self.location,
558 metadata=self.metadata,
559 seq=self.seq,
560 )
561 extlink.save()
563 return extlink
565 def internal_undo(self):
566 super().internal_undo()
568 try:
569 extlink = ExtLink.objects.get(resource=self.resource, base=self.base, rel=self.rel)
570 id = extlink.id
571 extlink.delete()
572 except ExtLink.DoesNotExist:
573 raise exceptions.ResourceDoesNotExist("The extlink " + self.rel + " does not exist")
575 return id
578class addExtIdDatabaseCmd(baseCmd):
579 """
580 addExtIdDatabaseCmd: adds/remove an ExtId
582 Exception raised:
583 - ValueError if the init params are empty
584 - exceptions.ResourceExists during do if the ExtId already exists
585 - exceptions.ResourceDoesNotExist during undo if the ExtId does not exist
586 - RuntimeError during undo if resources are still deployed
587 """
589 def __init__(self, params=None):
590 self.resource = None
591 self.id_type = None
592 self.id_value = None
593 self.checked = True
594 self.false_positive = False
596 super().__init__(params)
598 self.required_params.extend(["id_type", "id_value", "resource"])
600 def set_resource(self, resource):
601 self.resource = resource
603 def internal_do(self):
604 super().internal_do()
606 try:
607 # May raise Resource.DoesNotExist
608 extid = ExtId.objects.get(
609 resource=self.resource, id_type=self.id_type, id_value=self.id_value
610 )
611 except ExtId.DoesNotExist:
612 extid = ExtId(
613 resource=self.resource,
614 id_type=self.id_type,
615 id_value=self.id_value,
616 checked=self.checked,
617 false_positive=self.false_positive,
618 )
619 extid.save()
621 return extid
623 def internal_undo(self):
624 super().internal_undo()
626 try:
627 extid = ExtId.objects.get(
628 resource=self.resource, id_type=self.id_type, id_value=self.id_value
629 )
630 id = extid.id
631 extid.delete()
632 except ExtId.DoesNotExist:
633 raise exceptions.ResourceDoesNotExist("The extid " + self.id_value + " does not exist")
635 return id
638class addRelatedObjectDatabaseCmd(baseCmd):
639 """
640 addRelatedObjectDatabaseCmd: adds/remove a RelatedObject
642 a related object is a pdf/djvu... attached to the object (article...)
643 It can be for example a listing of a program attached to an article.
645 Exception raised:
646 - ValueError if the init params are empty
647 - exceptions.ResourceExists during do if the RelatedObject already exists
648 - exceptions.ResourceDoesNotExist during undo if the RelatedObject does not exist
649 - RuntimeError during undo if resources are still deployed
650 """
652 def __init__(self, params=None):
653 self.rel = None
654 self.mimetype = None
655 self.location = None
656 self.metadata = None
657 self.seq = None
658 self.resource = None
659 self.base = None
661 super().__init__(params)
663 self.required_params.extend(["rel", "location", "seq", "resource"])
665 def set_resource(self, resource):
666 self.resource = resource
668 def set_base(self, base):
669 self.base = base
671 def internal_do(self):
672 super().internal_do()
674 try:
675 RelatedObject.objects.get(
676 resource=self.resource,
677 base=self.base,
678 rel=self.rel,
679 mimetype=self.mimetype,
680 location=self.location,
681 metadata=self.metadata,
682 seq=self.seq,
683 )
684 raise exceptions.ResourceExists(
685 "The RelatedObject "
686 + self.base
687 + " "
688 + self.rel
689 + " "
690 + self.location
691 + " already exists"
692 )
693 except RelatedObject.DoesNotExist:
694 related_object = RelatedObject(
695 resource=self.resource,
696 base=self.base,
697 rel=self.rel,
698 mimetype=self.mimetype,
699 location=self.location,
700 metadata=self.metadata,
701 seq=self.seq,
702 )
704 related_object.save()
706 return related_object
708 def internal_undo(self):
709 super().internal_undo()
711 try:
712 related_object = RelatedObject.objects.get(
713 resource=self.resource, base=self.base, rel=self.rel, location=self.location
714 )
715 id = related_object.id
716 related_object.delete()
717 except RelatedObject.DoesNotExist:
718 raise exceptions.ResourceDoesNotExist(
719 "The relatedobject " + self.location + " does not exist"
720 )
722 return id
725class addSupplementaryMaterialDatabaseCmd(addRelatedObjectDatabaseCmd):
726 """
727 addSupplementaryMaterialDatabaseCmd: adds/remove a Supplementary Materiel
729 a supplementary material is a pdf/djvu... attached to the object (article...)
730 It can be for example a listing of a program attached to an article.
732 Exception raised:
733 - ValueError if the init params are empty
734 - exceptions.ResourceExists during do if the RelatedObject already exists
735 - exceptions.ResourceDoesNotExist during undo if the RelatedObject does not exist
736 - RuntimeError during undo if resources are still deployed
737 """
739 def __init__(self, params=None):
740 super().__init__(params)
742 def internal_do(self):
743 supplementary_material, _created = SupplementaryMaterial.objects.update_or_create(
744 caption=self.caption,
745 resource=self.resource,
746 base=self.base,
747 rel=self.rel,
748 mimetype=self.mimetype,
749 location=self.location,
750 metadata=self.metadata,
751 seq=self.seq,
752 )
753 return supplementary_material
755 def internal_undo(self):
756 try:
757 supplementary_material = SupplementaryMaterial.objects.get(
758 resource=self.resource, base=self.base, rel=self.rel, location=self.location
759 )
760 pk = supplementary_material.pk
761 supplementary_material.delete()
762 except SupplementaryMaterial.DoesNotExist:
763 raise exceptions.ResourceDoesNotExist(
764 "The SupplementaryMaterial " + self.location + " does not exist"
765 )
766 return pk
769class addDataStreamDatabaseCmd(baseCmd):
770 """
771 addDataStreamDatabaseCmd: adds/remove a DataStream
773 a datastream is the pdf/djvu... of the object (container, article)
775 Exception raised:
776 - ValueError if the init params are empty
777 - exceptions.ResourceExists during do if the DataStream already exists
778 - exceptions.ResourceDoesNotExist during undo if the DataStream does not exist
779 - RuntimeError during undo if resources are still deployed
780 """
782 def __init__(self, params=None):
783 self.rel = None
784 self.mimetype = None
785 self.location = None
786 self.text = None
787 self.seq = None
788 self.resource = None
789 self.base = None
791 super().__init__(params)
793 self.required_params.extend(["rel", "location", "seq", "resource"])
795 def set_resource(self, resource):
796 self.resource = resource
798 def set_base(self, base):
799 self.base = base
801 def internal_do(self):
802 super().internal_do()
804 try:
805 DataStream.objects.get(
806 resource=self.resource,
807 base=self.base,
808 rel=self.rel,
809 mimetype=self.mimetype,
810 location=self.location,
811 text=self.text,
812 seq=self.seq,
813 )
814 raise exceptions.ResourceExists(
815 "The DataStream "
816 + self.base
817 + " "
818 + self.rel
819 + " "
820 + self.location
821 + " already exists"
822 )
823 except DataStream.DoesNotExist:
824 datastream = DataStream(
825 resource=self.resource,
826 base=self.base,
827 rel=self.rel,
828 mimetype=self.mimetype,
829 location=self.location,
830 text=self.text,
831 seq=self.seq,
832 )
834 datastream.save()
836 return datastream
838 def internal_undo(self):
839 super().internal_undo()
841 try:
842 datastream = DataStream.objects.get(
843 resource=self.resource, base=self.base, rel=self.rel, location=self.location
844 )
845 id = datastream.id
846 datastream.delete()
847 except DataStream.DoesNotExist:
848 raise exceptions.ResourceDoesNotExist(
849 "The datastream " + self.location + " does not exist"
850 )
852 return id
855class addResourceCountDatabaseCmd(baseCmd):
856 """
857 addResourceCountDatabaseCmd: adds/remove a ResourceCount
859 A ResourceCount is a generic count element.
860 Exemple: page count, table count, image count...
862 Exception raised:
863 - ValueError if the init params are empty
864 - exceptions.ResourceExists during do if the ResourceCount already exists
865 - exceptions.ResourceDoesNotExist during undo if the ResourceCount does not exist
866 - RuntimeError during undo if resources are still deployed
867 """
869 def __init__(self, params=None):
870 self.seq = None
871 self.name = None
872 self.value = None
873 self.resource = None
874 self.add_total = False
876 super().__init__(params)
878 self.required_params.extend(["seq", "name", "value", "resource"])
880 def set_resource(self, resource):
881 self.resource = resource
883 def internal_do(self):
884 super().internal_do()
886 try:
887 ResourceCount.objects.get(resource=self.resource, name=self.name)
888 raise exceptions.ResourceExists("The ResourceCount " + self.name + " already exists")
889 except ResourceCount.DoesNotExist:
890 resource_count = ResourceCount(
891 resource=self.resource, name=self.name, seq=self.seq, value=self.value
892 )
894 resource_count.save()
896 if self.name == "page-count" and self.add_total:
897 value = parse_page_count(self.value)
899 try:
900 total = Stats.objects.get(name=self.name)
901 total.value += value
902 except Stats.DoesNotExist:
903 total = Stats(name=self.name, value=value)
905 total.save()
907 return resource_count
909 def internal_undo(self):
910 super().internal_undo()
912 try:
913 resource_count = ResourceCount.objects.get(resource=self.resource, name=self.name)
914 id = resource_count.id
915 resource_count.delete()
916 except ResourceCount.DoesNotExist:
917 raise exceptions.ResourceDoesNotExist("The count " + self.name + " does not exist")
919 return id
922class addMetaDataPartDatabaseCmd(baseCmd):
923 """
924 addMetaDataPartDatabaseCmd: adds/remove a MetaDataPart
926 A MetaDataPart is a generic count element.
927 Exemple: page count, table count, image count...
929 Exception raised:
930 - ValueError if the init params are empty
931 - exceptions.ResourceExists during do if the MetaDataPart already exists
932 - exceptions.ResourceDoesNotExist during undo if the MetaDataPart does not exist
933 - RuntimeError during undo if resources are still deployed
934 """
936 def __init__(self, params=None):
937 self.seq = None
938 self.name = None
939 self.data = None
940 self.resource = None
942 super().__init__(params)
944 self.required_params.extend(["seq", "name", "data", "resource"])
946 def set_resource(self, resource):
947 self.resource = resource
949 def internal_do(self):
950 super().internal_do()
952 try:
953 MetaDataPart.objects.get(resource=self.resource, name=self.name)
954 raise exceptions.ResourceExists("The MetaDataPart " + self.name + " already exists")
955 except MetaDataPart.DoesNotExist:
956 metadatapart = MetaDataPart(
957 resource=self.resource, name=self.name, seq=self.seq, data=self.data
958 )
960 metadatapart.save()
962 return metadatapart
964 def internal_undo(self):
965 super().internal_undo()
967 try:
968 metadatapart = MetaDataPart.objects.get(resource=self.resource, name=self.name)
969 id = metadatapart.id
970 metadatapart.delete()
971 except MetaDataPart.DoesNotExist:
972 raise exceptions.ResourceDoesNotExist(
973 "The metadatapart " + self.name + " does not exist"
974 )
976 return id
979class addBibItemDatabaseCmd(baseCmd):
980 """
981 addBibItemDatabaseCmd: adds/remove a BibItem
983 No verification is done to check if a BibItem already exists
984 Rationale: BibItems are only added in a loop within an article.
985 The check is actually the existence of the article.
987 Exception raised:
988 - ValueError if the init params are empty
989 - exceptions.ResourceDoesNotExist during undo if the BibItem does not exist
990 - RuntimeError during undo if resources are still deployed
991 """
993 def __init__(self, params=None):
994 self.sequence = None
995 self.label = ""
996 self.citation_xml = None
997 self.citation_tex = None
998 self.citation_html = None
999 self.resource = None
1001 self.type = ""
1002 self.user_id = ""
1003 self.title_tex = ""
1004 self.publisher_name = ""
1005 self.publisher_loc = ""
1006 self.institution = ""
1007 self.series = ""
1008 self.volume = ""
1009 self.issue = ""
1010 self.month = ""
1011 self.year = ""
1012 self.comment = ""
1013 self.annotation = ""
1014 self.fpage = ""
1015 self.lpage = ""
1016 self.page_range = ""
1017 self.size = ""
1018 self.source = ""
1019 self.article_title_tex = ""
1020 self.chapter_title_tex = ""
1022 self.contributors = None
1024 super().__init__(params)
1026 self.required_params.extend(["sequence", "citation_xml", "resource"])
1028 def set_resource(self, resource):
1029 self.resource = resource
1031 def internal_do(self):
1032 super().internal_do()
1034 bibitem = BibItem(
1035 resource=self.resource,
1036 sequence=self.sequence,
1037 label=self.label,
1038 citation_xml=self.citation_xml,
1039 citation_tex=self.citation_tex,
1040 citation_html=self.citation_html,
1041 type=self.type,
1042 user_id=self.user_id,
1043 article_title_tex=self.article_title_tex,
1044 chapter_title_tex=self.chapter_title_tex,
1045 source_tex=self.source_tex,
1046 publisher_name=self.publisher_name,
1047 publisher_loc=self.publisher_loc,
1048 institution=self.institution,
1049 series=self.series,
1050 volume=self.volume,
1051 issue=self.issue,
1052 month=self.month,
1053 year=self.year,
1054 comment=self.comment,
1055 annotation=self.annotation,
1056 fpage=self.fpage,
1057 lpage=self.lpage,
1058 page_range=self.page_range,
1059 size=self.size,
1060 )
1062 bibitem.save()
1064 return bibitem
1066 def post_do(self, bibitem):
1067 super().post_do(bibitem)
1069 add_contributors(contributors=self.contributors, bibitem=bibitem)
1071 def internal_undo(self):
1072 super().internal_undo()
1074 try:
1075 bibitem = BibItem.objects.get(resource=self.resource, sequence=self.sequence)
1076 id = bibitem.id
1077 bibitem.delete()
1078 except BibItem.DoesNotExist:
1079 raise exceptions.ResourceDoesNotExist(
1080 "The bibitem " + self.sequence + " does not exist"
1081 )
1083 return id
1086class addBibItemIdDatabaseCmd(baseCmd):
1087 """
1088 addBibItemIdDatabaseCmd: adds/remove a BibItemId
1090 No verification is done to check if a BibItemId already exists
1091 Rationale: BibItems are only added in a loop within an article.
1092 The check is actually the existence of the article.
1094 Exception raised:
1095 - ValueError if the init params are empty
1096 - exceptions.ResourceDoesNotExist during undo if the BibItemId does not exist
1097 - RuntimeError during undo if resources are still deployed
1098 """
1100 def __init__(self, params=None):
1101 self.bibitem = None
1102 self.id_type = None
1103 self.id_value = None
1104 self.checked = True
1105 self.false_positive = False
1107 super().__init__(params)
1109 self.required_params.extend(["bibitem", "id_type", "id_value"])
1111 def set_bibitem(self, bibitem):
1112 self.bibitem = bibitem
1114 def internal_do(self):
1115 super().internal_do()
1117 bibitemid = BibItemId(
1118 bibitem=self.bibitem,
1119 id_type=self.id_type,
1120 id_value=self.id_value,
1121 checked=self.checked,
1122 false_positive=self.false_positive,
1123 )
1125 bibitemid.save()
1127 return bibitemid
1129 def internal_undo(self):
1130 super().internal_undo()
1132 try:
1133 bibitemid = BibItemId.objects.get(
1134 bibitem=self.bibitem, id_type=self.id_type, id_value=self.id_value
1135 )
1136 id = bibitemid.id
1137 bibitemid.delete()
1138 except BibItemId.DoesNotExist:
1139 raise exceptions.ResourceDoesNotExist(
1140 "The bibitemid " + self.value + " does not exist"
1141 )
1143 return id
1146class addFrontMatterDatabaseCmd(baseCmd):
1147 """
1148 addFrontMatterDatabaseCmd: adds/remove a FrontMatter
1150 No verification is done to check if a FrontMatter already exists
1151 Rationale: FrontMatters are only added in a loop within an article.
1152 The check is actually the existence of the article.
1154 Exception raised:
1155 - ValueError if the init params are empty
1156 - exceptions.ResourceDoesNotExist during undo if the FrontMatter does not exist
1157 - RuntimeError during undo if resources are still deployed
1158 """
1160 def __init__(self, params=None):
1161 self.value_xml = ""
1162 self.value_html = ""
1163 self.foreword_html = ""
1164 self.resource = None
1166 super().__init__(params)
1168 self.required_params.extend(["value_xml", "resource"])
1170 def set_resource(self, resource):
1171 self.resource = resource
1173 def internal_do(self):
1174 super().internal_do()
1176 frontmatter = FrontMatter(
1177 resource=self.resource,
1178 value_xml=self.value_xml,
1179 value_html=self.value_html,
1180 foreword_html=self.foreword_html,
1181 )
1183 frontmatter.save()
1185 return frontmatter
1187 def internal_undo(self):
1188 super().internal_undo()
1190 try:
1191 frontmatter = FrontMatter.objects.get(resource=self.resource)
1192 id = frontmatter.id
1193 frontmatter.delete()
1194 except FrontMatter.DoesNotExist:
1195 raise exceptions.ResourceDoesNotExist(
1196 "The front-matter " + self.text + " does not exist"
1197 )
1199 return id
1202class addRelationshipDatabaseCmd(baseCmd):
1203 """
1204 addRelationshipDatabaseCmd: adds/remove a Relationship
1206 Relationship relates 2 resources (ex: articles) with a relation. ex "follows", "followed-by"
1208 RelationName are created with a fixture (see app/ptf/apps/ptf/fixtures/initial_data.json
1209 Example { "left" : "follows", "right" : "followed-by" }
1210 A related-article of an article has 1 relation name (ex "follows" or "followed-by")
1211 You need to know if the relation was stored in the left or right attribute of a RelationName,
1212 so that you can create/search the Relationship with the correct object/subject.
1213 Ex: with A "follows" B, A is the subject and B the object because "follows" is a RelationName.left attribute
1214 with A "followed-by" B, A is the object the B the subject because
1215 "followed-by" is a RelationName.right attribute
1216 A Relationship relates 2 resources with a RelationName
1219 Exception raised:
1220 - ValueError if the init params are empty
1221 - exceptions.ResourceExists during do if the Relationship already exists
1222 - exceptions.ResourceDoesNotExist during undo if the Relationship does not exist
1223 - RuntimeError during undo if resources are still deployed
1224 """
1226 def __init__(self, params=None):
1227 self.subject_resource = None
1228 self.subject_pid = None
1229 self.object_resource = None
1230 self.object_pid = None
1231 self.relationname = None
1233 super().__init__(params)
1235 self.required_params.extend(["subject_pid", "object_pid", "relationname"])
1237 def set_subject_resource(self, resource):
1238 self.subject_resource = resource
1239 # self.subject_pid = resource.pid
1241 def set_object_resource(self, resource):
1242 self.object_resource = resource
1243 # self.object_pid = resource.pid
1245 def set_relationname(self, relationname):
1246 self.relationname = relationname
1248 def internal_do(self):
1249 super().internal_do()
1251 try:
1252 relationship = Relationship.objects.get(
1253 subject_pid=self.subject_pid,
1254 object_pid=self.object_pid,
1255 rel_info=self.relationname,
1256 )
1257 # la première fois que l'on crée la relation une des 2 ressourcesID est a priori None
1258 # la deuxième fois (la relation symétrique) il faut compléter la
1259 # RelationShip
1260 if relationship.resource is not None and relationship.related is not None:
1261 raise exceptions.ResourceExists(
1262 "The Relationship {} {} {} already exists".format(
1263 self.subject_pid, self.relationname.left, self.object_pid
1264 )
1265 )
1266 if self.subject_resource is not None:
1267 relationship.resource = self.subject_resource
1268 if self.object_resource is not None:
1269 relationship.related = self.object_resource
1270 relationship.save()
1272 except Relationship.DoesNotExist:
1273 relationship = Relationship(
1274 subject_pid=self.subject_pid,
1275 object_pid=self.object_pid,
1276 resource=self.subject_resource,
1277 related=self.object_resource,
1278 rel_info=self.relationname,
1279 )
1281 relationship.save()
1283 return relationship
1285 def internal_undo(self):
1286 super().internal_undo()
1288 try:
1289 relationship = Relationship.objects.get(
1290 subject_pid=self.subject_pid,
1291 object_pid=self.object_pid,
1292 rel_info=self.relationname,
1293 )
1294 id = relationship.id
1296 # Create relationship is typically a 2 steps process
1297 # (1: create the relationship with only 1 resource. 2: update the relationship with the 2nd resource)
1298 # Undo is also a 2 steps process
1299 # (1: unset a resource. 2: delete the relationship)
1300 if relationship.resource is not None and relationship.related is not None:
1301 # Both left and right resources are set: unset the resource
1302 # that was given as param
1303 if self.subject_resource is None:
1304 relationship.related = None
1305 else:
1306 relationship.resource = None
1307 relationship.save()
1308 else:
1309 relationship.delete()
1310 except Relationship.DoesNotExist:
1311 raise exceptions.ResourceDoesNotExist(
1312 "The relationship " + self.relationname + " does not exist"
1313 )
1315 return id
1318class addResourceDatabaseCmd(baseCmd):
1319 """
1320 addResourceDatabaseCmd: base class for all resources
1322 Exception raised:
1323 - exceptions.ResourceDoesNotExist during undo if the Resource does not exist
1324 """
1326 def __init__(self, params=None):
1327 self.xobj = None # model_data object
1329 self.provider = None
1330 self._prod_deployed_date = None
1332 super().__init__(params)
1334 self.required_params.extend(["xobj", "provider"])
1336 # May raise ValueError
1337 def check_params(self):
1338 super().check_params()
1340 if hasattr(self.xobj, "pid") and not self.xobj.pid and not self.xobj.sid: 1340 ↛ 1341line 1340 didn't jump to line 1341, because the condition on line 1340 was never true
1341 raise ValueError("pid et sid sont vides")
1343 def set_provider(self, provider):
1344 self.provider = provider
1346 # May raise Provider.DoesNotExist
1347 def set_provider_by_name_or_id(self, provider_name="", pid_type="", sid_type=None):
1348 self.provider = Provider.objects.get(
1349 name=provider_name, pid_type=pid_type, sid_type=sid_type
1350 )
1352 def post_do(self, resource):
1353 super().post_do(resource)
1354 self.object_to_be_deleted = resource
1356 site = model_helpers.get_or_create_site(settings.SITE_ID, resource.pid)
1357 if site: 1357 ↛ 1363line 1357 didn't jump to line 1363, because the condition on line 1357 was never false
1358 resource.deploy(site, self._prod_deployed_date)
1360 # Creation of SiteMembership for production website on ptf_tools is handled in DeployJatsIssue
1361 # Restoration of SiteMembership is handled in importExtraDataPtfCmd
1363 for id_type, id_value in self.xobj.ids:
1364 if ( 1364 ↛ 1363line 1364 didn't jump to line 1363
1365 id_type != self.provider.pid_type
1366 and id_type != self.provider.sid_type
1367 and (id_type != "numdam-id" or self.provider.pid_type != "mathdoc-id")
1368 ):
1369 try:
1370 # May raise Resource.DoesNotExist
1371 resource_id = ResourceId.objects.get(
1372 resource=resource, id_type=id_type, id_value=id_value
1373 )
1374 except ResourceId.DoesNotExist:
1375 resource_id = ResourceId(resource=resource, id_type=id_type, id_value=id_value)
1376 resource_id.save()
1378 for id_type, id_value in self.xobj.extids:
1379 if ( 1379 ↛ 1378line 1379 didn't jump to line 1378
1380 id_type != self.provider.pid_type
1381 and id_type != self.provider.sid_type
1382 and (id_type != "numdam-id" or self.provider.pid_type != "mathdoc-id")
1383 ):
1384 try:
1385 # May raise Resource.DoesNotExist
1386 ExtId.objects.get(resource=resource, id_type=id_type, id_value=id_value)
1387 except ExtId.DoesNotExist:
1388 ext_id = ExtId(resource=resource, id_type=id_type, id_value=id_value)
1389 ext_id.save()
1391 seq = 1
1392 # abstract_set = self.xobj.abstract_set.all()
1393 for a in self.xobj.abstracts:
1394 value_xml = a["value_xml"] if "value_xml" in a else ""
1395 value_html = a["value_html"] if "value_html" in a else ""
1396 value_tex = a["value_tex"] if "value_tex" in a else ""
1398 la = Abstract(
1399 resource=resource,
1400 tag=a["tag"],
1401 lang=a["lang"],
1402 seq=seq,
1403 value_xml=value_xml,
1404 value_html=value_html,
1405 value_tex=value_tex,
1406 )
1407 la.save()
1408 seq += 1
1410 add_contributors(contributors=self.xobj.contributors, resource=resource)
1412 for i, kwd in enumerate(self.xobj.kwds):
1413 k = Kwd(
1414 resource=resource, lang=kwd["lang"], type=kwd["type"], value=kwd["value"], seq=i
1415 )
1416 k.save()
1418 for i, subj in enumerate(self.xobj.subjs):
1419 s = Subj(
1420 resource=resource, lang=subj["lang"], type=subj["type"], value=subj["value"], seq=i
1421 )
1422 s.save()
1424 seq = 1
1425 for a in self.xobj.awards:
1426 abbrev = a["abbrev"]
1427 award_id = a["award_id"]
1429 award = Award(resource=resource, abbrev=abbrev, award_id=award_id, seq=seq)
1430 award.save()
1431 seq += 1
1433 # TODO custom meta
1435 def pre_undo(self):
1436 super().pre_undo()
1438 # None value not detected in check_params (required_delete_params)
1439 # => undo was already called
1440 if self.object_to_be_deleted is None:
1441 raise exceptions.ResourceDoesNotExist("The object to be deleted no longer exists")
1443 # Django automatically deletes related objects such as ResourceIds,
1444 # Abstracts...
1446 # Author are deleted by signals (see models.py)
1447 # Another solution would be to do it here
1449 # Undeploy the resource in all sites
1450 for site in self.object_to_be_deleted.sites.all():
1451 self.object_to_be_deleted.undeploy(site)
1453 def internal_undo(self):
1454 super().internal_undo()
1456 id = self.object_to_be_deleted.id
1457 self.object_to_be_deleted.delete()
1459 return id
1461 def post_undo(self):
1462 super().internal_undo()
1464 self.object_to_be_deleted = None # prevents a 2nd attempt to delete
1467class addPublisherDatabaseCmd(baseCmd):
1468 """
1469 addPublisherDatabaseCmd: adds/remove a publisher
1471 Exception raised:
1472 - ValueError if the init params are empty
1473 - exceptions.ResourceExists during do if the Publisher already exists
1474 - exceptions.ResourceDoesNotExist during undo if the Publisher does not exist
1475 """
1477 def __init__(self, params=None):
1478 self.xobj = None # model_data object
1479 self.object_to_be_deleted = None
1481 super().__init__(params)
1483 self.required_params.extend(["xobj"])
1484 self.required_delete_params.append("object_to_be_deleted")
1486 def set_object_to_be_deleted(self, obj):
1487 self.object_to_be_deleted = obj
1489 def internal_do(self):
1490 super().internal_do()
1492 # A Publisher is a resource. Therefore it needs a provider (that provides the publisher id/key)
1493 # As we are creating the key, Mathdoc is the provider
1494 provider = Provider.objects.get(name="mathdoc", pid_type="mathdoc-id")
1495 key = model_helpers.make_key(self.xobj.name)
1497 try:
1498 Publisher.objects.get(pub_key=key)
1499 raise exceptions.ResourceExists("The publisher " + self.xobj.name + " already exists")
1500 except Publisher.DoesNotExist:
1501 publisher = Publisher(
1502 pub_key=key,
1503 pub_name=self.xobj.name,
1504 pub_loc=self.xobj.loc,
1505 pid=key,
1506 provider=provider,
1507 )
1508 publisher.save()
1510 self.object_to_be_deleted = publisher
1511 return publisher
1513 def internal_undo(self):
1514 super().internal_undo()
1516 # None value not detected in check_params (required_delete_params)
1517 # => undo was already called
1518 if self.object_to_be_deleted is None:
1519 raise exceptions.ResourceDoesNotExist("The object to be deleted no longer exists")
1521 self.object_to_be_deleted.refresh_from_db()
1523 if self.object_to_be_deleted.publishes.count():
1524 raise RuntimeError(
1525 "Impossible de supprimer ce publisher car il a encore des resources qui sont publiées par ce publisher"
1526 )
1528 id = self.object_to_be_deleted.id
1529 self.object_to_be_deleted.delete()
1530 self.object_to_be_deleted = None
1532 return id
1535class addContainerDatabaseCmd(addResourceDatabaseCmd):
1536 """
1537 addContainerDatabaseCmd: adds/remove a container
1539 an Container needs a Collection
1541 Exception raised:
1542 - ValueError if the init params are empty
1543 - exceptions.ResourceExists during do if the container already exists
1544 - exceptions.ResourceDoesNotExist during undo if the Container does not exist
1545 """
1547 def __init__(self, params=None):
1548 self.last_modified = None
1549 self.collection = None
1550 self._publisher = None
1552 super().__init__(params)
1554 self.required_params.extend(["collection"])
1556 def add_collection(self, collection):
1557 if not self.collection: 1557 ↛ exitline 1557 didn't return from function 'add_collection', because the condition on line 1557 was never false
1558 self.collection = collection
1560 def pre_do(self):
1561 super().pre_do()
1563 self._publisher = add_publisher(self.xobj)
1565 def internal_do(self):
1566 super().internal_do()
1568 vseries = volume = number = seq = ""
1569 if hasattr(self.xobj, "volume"):
1570 vseries = self.xobj.vseries
1571 volume = self.xobj.volume
1572 number = self.xobj.number
1573 seq = self.xobj.seq
1574 elif len(self.xobj.incollection) > 0: 1574 ↛ 1583line 1574 didn't jump to line 1583, because the condition on line 1574 was never false
1575 # Books do not have vseries/volume/number, but a list of incollection
1576 # Set vseries/volume/number from the 1st incollection (the main collection)
1577 incol = self.xobj.incollection[0]
1578 vseries = incol.vseries
1579 volume = ""
1580 number = incol.volume
1581 seq = incol.seq
1583 seq = make_int(volume) if volume else make_int(self.xobj.year)
1585 last_modified = model_helpers.parse_date_str(self.xobj.last_modified_iso_8601_date_str)
1586 if self.xobj.prod_deployed_date_iso_8601_date_str:
1587 self._prod_deployed_date = model_helpers.parse_date_str(
1588 self.xobj.prod_deployed_date_iso_8601_date_str
1589 )
1591 with_online_first = (
1592 self.xobj.with_online_first if hasattr(self.xobj, "with_online_first") else False
1593 )
1595 try:
1596 Container.objects.get(
1597 pid=self.xobj.pid,
1598 provider__pid_type=self.provider.pid_type,
1599 my_collection__pid=self.collection.pid,
1600 )
1601 raise exceptions.ResourceExists("The container " + self.xobj.pid + " already exists")
1603 except Container.DoesNotExist:
1604 container = Container(
1605 ctype=self.xobj.ctype,
1606 doi=self.xobj.doi,
1607 pid=self.xobj.pid,
1608 lang=self.xobj.lang,
1609 title_xml=self.xobj.title_xml,
1610 title_tex=self.xobj.title_tex,
1611 title_html=self.xobj.title_html,
1612 trans_lang=self.xobj.trans_lang,
1613 trans_title_tex=self.xobj.trans_title_tex,
1614 trans_title_html=self.xobj.trans_title_html,
1615 provider=self.provider,
1616 my_publisher=self._publisher,
1617 my_collection=self.collection,
1618 year=self.xobj.year,
1619 vseries=vseries,
1620 vseries_int=make_int(vseries),
1621 volume=volume,
1622 volume_int=make_int(volume),
1623 number=number,
1624 number_int=make_int(number),
1625 seq=seq,
1626 last_modified=last_modified,
1627 with_online_first=with_online_first,
1628 body_html=self.xobj.body_html,
1629 body_tex=self.xobj.body_tex,
1630 body_xml=self.xobj.body_xml,
1631 )
1633 container.save()
1635 return container
1637 def post_do(self, container):
1638 super().post_do(container)
1640 if hasattr(self.xobj, "incollection"):
1641 for incol in self.xobj.incollection:
1642 # Ignore the first incollection which was treated as the main collection
1643 if incol.pid != self.collection.pid:
1644 collection = model_helpers.get_collection(incol.pid)
1645 if collection: 1645 ↛ 1641line 1645 didn't jump to line 1641, because the condition on line 1645 was never false
1646 collection_membership = CollectionMembership(
1647 collection=collection,
1648 container=container,
1649 seq=incol.seq,
1650 vseries=incol.vseries,
1651 volume="",
1652 number=incol.volume,
1653 vseries_int=make_int(incol.vseries),
1654 volume_int=0,
1655 number_int=make_int(incol.volume),
1656 )
1657 collection_membership.save()
1659 add_biblio(self.xobj, container)
1660 add_counts(self.xobj, container, add_total=True)
1661 add_relations(self.xobj, container)
1662 add_frontmatter(self.xobj, container)
1664 def post_undo(self):
1665 collection = self.object_to_be_deleted.get_collection()
1666 super().post_undo()
1668 if self._publisher is not None:
1669 if self._publisher.publishes.count() == 0:
1670 self._publisher.delete()
1671 self._publisher = None
1673 if collection.parent and collection.content.count() == 0:
1674 # Child collection that was created on the fly is removed automatically
1675 # if it no longer has any content
1676 collection.delete()
1679class addResourceInSpecialIssueDatabaseCmd(baseCmd):
1680 """
1681 addResourceInSpecialIssueDatabaseCmd: adds/remove a ResourceInSpecialIssue
1683 a ResourceInSpecialIssue needs a issue
1685 params :
1686 - obj : the resource 'article, book, ...'
1687 - obj_doi: the doi of the resource
1688 - container : the special issue using the resource
1689 - seq : sequence of the resource in the special issue
1690 - citation : html citation of the resource
1692 Exception raised:
1693 - ValueError if the init params are empty
1694 - exceptions.ResourceExists during do if the article already exists
1695 - exceptions.ResourceDoesNotExist during undo if the Article does not exist
1696 """
1698 def __init__(self, params=None):
1699 # parents are used for book parts.
1701 # Container containing the article
1702 self.container = params["container"]
1703 # self.collection = None
1704 # self.provider = params["provider"]
1705 self.obj_doi = params["obj_doi"]
1706 self.seq = params["seq"]
1707 # self.xobj = params["xobj"]
1708 self.citation = params["citation"]
1709 # self.resource = None
1711 # super().__init__(params)
1713 def do(self):
1714 # super().internal_do()
1715 # changer nom resource en x...
1716 # xresource = self.xobj
1717 resource_doi = self.obj_doi
1718 container = self.container
1719 seq = self.seq
1720 citation = self.citation
1721 # if not citation:
1722 # citation = resource.citation_html
1723 # juste mettre la vérif sur le champ doi car toutes les resources ont ce champ
1724 # et mettre model_helper get_resource...
1725 # if isinstance(resource, jats_parser.JatsArticle):
1726 if resource_doi:
1727 resource = Article.objects.get(doi=resource_doi)
1728 else:
1729 pass
1730 try:
1731 ResourceInSpecialIssue.objects.get(
1732 resource=resource, resource_doi=resource_doi, my_container=container
1733 )
1734 raise exceptions.ResourceExists(
1735 f"The ResourceInSpecialIssue {resource} for issue {container} already exists"
1736 )
1738 except ResourceInSpecialIssue.DoesNotExist:
1739 resource_in_special_issue = ResourceInSpecialIssue(
1740 resource=resource,
1741 resource_doi=resource_doi,
1742 my_container=container,
1743 citation=citation,
1744 seq=seq,
1745 )
1747 resource_in_special_issue.save()
1748 return resource_in_special_issue
1751class addArticleDatabaseCmd(addResourceDatabaseCmd):
1752 """
1753 addArticleDatabaseCmd: adds/remove an article
1755 an article needs a container (book or issue)
1757 Exception raised:
1758 - ValueError if the init params are empty
1759 - exceptions.ResourceExists during do if the article already exists
1760 - exceptions.ResourceDoesNotExist during undo if the Article does not exist
1761 """
1763 def __init__(self, params=None):
1764 # parents are used for book parts.
1765 self.pseq = 0 # parent seq
1766 self.parent = None # article parent
1768 # Container containing the article
1769 self.container = None
1770 self.collection = None
1772 self.assign_doi = False
1773 self.seq = 0
1775 self.translated_articles = []
1777 super().__init__(params)
1779 def check_params(self):
1780 super().check_params()
1782 check_title = True
1783 if hasattr(self.xobj, "doi") and self.xobj.doi and self.xobj.doi.find("pcjournal") > 0:
1784 check_title = False
1785 if "original_article" in self.required_params: 1785 ↛ 1787line 1785 didn't jump to line 1787, because the condition on line 1785 was never true
1786 # A Translation may not have a title
1787 check_title = False
1788 if ( 1788 ↛ 1794line 1788 didn't jump to line 1794
1789 check_title
1790 and self.is_add_cmd
1791 and not self.xobj.title_tex
1792 and not self.xobj.trans_title_tex
1793 ):
1794 raise ValueError("title_tex et trans_title_tex sont vides")
1796 def set_container(self, container):
1797 self.container = container
1798 self.collection = container.my_collection
1799 self.set_provider(container.provider)
1801 def set_collection(self, collection):
1802 self.collection = collection
1803 self.set_provider(collection.provider)
1805 def set_parent(self, parent):
1806 self.parent = parent
1808 def parse_dates(self):
1809 dates = {
1810 "accepted": None,
1811 "received": None,
1812 "revised": None,
1813 "online": None,
1814 "published": None,
1815 }
1817 for date_entry in self.xobj.history_dates:
1818 if date_entry["date"] is None: 1818 ↛ 1819line 1818 didn't jump to line 1819, because the condition on line 1818 was never true
1819 raise ValueError(
1820 f"The date {date_entry['type']} of the article {self.xobj.pid} is None"
1821 )
1823 date = model_helpers.parse_date_str(date_entry["date"])
1824 dates[date_entry["type"]] = date
1826 if self.xobj.date_published_iso_8601_date_str:
1827 dates["published"] = model_helpers.parse_date_str(
1828 self.xobj.date_published_iso_8601_date_str
1829 )
1831 if self.xobj.prod_deployed_date_iso_8601_date_str:
1832 self._prod_deployed_date = model_helpers.parse_date_str(
1833 self.xobj.prod_deployed_date_iso_8601_date_str
1834 )
1836 return dates
1838 def add_translations(self, xobj, article):
1839 if hasattr(xobj, "translations") and xobj.translations is not None: 1839 ↛ exitline 1839 didn't return from function 'add_translations', because the condition on line 1839 was never false
1840 for xarticle in xobj.translations: 1840 ↛ 1841line 1840 didn't jump to line 1841, because the loop on line 1840 never started
1841 cmd = addTranslatedArticleDatabaseCmd({"xobj": xarticle})
1842 cmd.set_original_article(article)
1843 cmd.set_provider(article.provider)
1844 trans_article = cmd.do()
1845 self.translated_articles.append(trans_article)
1847 def internal_do(self):
1848 super().internal_do()
1850 doi = self.xobj.doi
1851 if self.assign_doi and not doi and self.container:
1852 colid = self.container.my_collection.pid
1853 doi = model_helpers.assign_doi(colid)
1855 seq = self.xobj.seq or self.seq
1856 dates = self.parse_dates()
1858 try:
1859 Article.objects.get(
1860 pid=self.xobj.pid, doi=doi, provider=self.provider, my_container=self.container
1861 )
1862 raise exceptions.ResourceExists("The article " + self.xobj.pid + " already exists")
1863 except Article.DoesNotExist:
1864 article = Article(
1865 pid=self.xobj.pid,
1866 doi=doi,
1867 lang=self.xobj.lang,
1868 title_xml=self.xobj.title_xml,
1869 title_tex=self.xobj.title_tex,
1870 title_html=self.xobj.title_html,
1871 trans_lang=self.xobj.trans_lang,
1872 trans_title_tex=self.xobj.trans_title_tex,
1873 trans_title_html=self.xobj.trans_title_html,
1874 provider=self.provider,
1875 my_container=self.container,
1876 fpage=self.xobj.fpage,
1877 lpage=self.xobj.lpage,
1878 seq=seq,
1879 atype=self.xobj.atype,
1880 page_range=self.xobj.page_range,
1881 page_type=self.xobj.page_type,
1882 elocation=self.xobj.elocation,
1883 article_number=self.xobj.article_number,
1884 talk_number=self.xobj.talk_number,
1885 pseq=self.pseq,
1886 parent=self.parent,
1887 date_accepted=dates["accepted"],
1888 date_received=dates["received"],
1889 date_revised=dates["revised"],
1890 date_online_first=dates["online"],
1891 date_published=dates["published"],
1892 coi_statement=self.xobj.coi_statement,
1893 funding_statement_html=self.xobj.funding_statement_html,
1894 funding_statement_xml=self.xobj.funding_statement_xml,
1895 footnotes_html=self.xobj.footnotes_html,
1896 footnotes_xml=self.xobj.footnotes_xml,
1897 body_html=self.xobj.body_html,
1898 body_tex=self.xobj.body_tex,
1899 body_xml=self.xobj.body_xml,
1900 )
1902 article.save()
1904 if doi:
1905 collection = self.collection
1906 doi_number = model_helpers.get_number_from_doi(doi)
1907 if doi_number > collection.last_doi:
1908 collection.last_doi = doi_number
1909 collection.save()
1911 return article
1913 def post_do(self, article):
1914 super().post_do(article)
1916 add_biblio(self.xobj, article)
1917 add_counts(self.xobj, article, add_total=True)
1918 add_relations(self.xobj, article)
1919 self.add_translations(self.xobj, article)
1922class addCollectionDatabaseCmd(addResourceDatabaseCmd):
1923 """
1924 addCollectionDatabaseCmd: adds/remove a collection
1926 Exception raised:
1927 - ValueError if the init params are empty
1928 - exceptions.ResourceExists during do if the book already exists
1929 - exceptions.ResourceDoesNotExist during undo if the book does not exist
1930 """
1932 def __init__(self, params=None):
1933 # self.coltype = None
1934 # self.wall = 5
1935 self.parent = None
1937 super().__init__(params)
1939 def set_parent(self, parent):
1940 self.parent = parent
1942 def internal_do(self):
1943 super().internal_do()
1945 title_sort = (
1946 self.xobj.title_tex if len(self.xobj.title_tex) < 129 else self.xobj.title_tex[0:127]
1947 )
1949 try:
1950 col = Collection.objects.get(
1951 pid=self.xobj.pid,
1952 title_tex=self.xobj.title_tex,
1953 provider__pid_type=self.provider.pid_type,
1954 )
1955 except Collection.DoesNotExist:
1956 col = Collection.objects.create(
1957 coltype=self.xobj.coltype,
1958 abbrev=self.xobj.abbrev,
1959 wall=self.xobj.wall,
1960 pid=self.xobj.pid,
1961 lang=self.xobj.lang,
1962 title_xml=self.xobj.title_xml,
1963 title_tex=self.xobj.title_tex,
1964 title_html=self.xobj.title_html,
1965 title_sort=title_sort,
1966 trans_lang=self.xobj.trans_lang,
1967 trans_title_tex=self.xobj.trans_title_tex,
1968 trans_title_html=self.xobj.trans_title_html,
1969 provider=self.provider,
1970 parent=self.parent,
1971 )
1972 else:
1973 raise exceptions.ResourceExists(f"The collection pid:{self.xobj.pid} already exists")
1974 return col
1976 # def internal_undo(self):
1977 # super().internal_undo()
1978 #
1979 # try:
1980 # col = Collection.objects.get(pid=self.pid,
1981 # provider__pid_type=self.provider.pid_type)
1982 # id = col.id
1983 # if col.parent and not col.ancestors.all().count() :
1984 # col.parent = None
1985 # col.delete()
1986 #
1987 #
1988 # elif not col.parent and not col.ancestors.all().count() :
1989 # col.delete()
1990 #
1991 # except Collection.DoesNotExist:
1992 # raise exceptions.ResourceDoesNotExist(
1993 # "The collection " + self.pid + " does not exist")
1994 #
1995 # return id
1998class addTranslatedArticleDatabaseCmd(addArticleDatabaseCmd):
1999 """
2000 addTranslatedArticleDatabaseCmd: adds/remove a translated article
2001 """
2003 def __init__(self, params=None):
2004 super().__init__(params)
2006 self.original_article = None
2008 self.required_params = ["xobj", "original_article"]
2010 def set_original_article(self, original_article):
2011 self.original_article = original_article
2013 def internal_do(self):
2014 # DO NOT CALL the parent internal_do or it will create an Article
2016 dates = self.parse_dates()
2018 try:
2019 TranslatedArticle.objects.get(pid=self.xobj.pid)
2020 raise exceptions.ResourceExists(
2021 "The translated article " + self.xobj.pid + " already exists"
2022 )
2023 except Article.DoesNotExist:
2024 article = TranslatedArticle(
2025 original_article=self.original_article,
2026 pid=self.xobj.pid,
2027 doi=self.xobj.doi,
2028 lang=self.xobj.lang,
2029 title_xml=self.xobj.title_xml,
2030 title_tex=self.xobj.title_tex,
2031 title_html=self.xobj.title_html,
2032 trans_lang=self.xobj.trans_lang,
2033 trans_title_tex=self.xobj.trans_title_tex,
2034 trans_title_html=self.xobj.trans_title_html,
2035 provider=self.provider,
2036 my_container=None,
2037 fpage=self.xobj.fpage,
2038 lpage=self.xobj.lpage,
2039 seq=self.xobj.seq,
2040 atype=self.xobj.atype,
2041 page_range=self.xobj.page_range,
2042 page_type=self.xobj.page_type,
2043 elocation=self.xobj.elocation,
2044 article_number=self.xobj.article_number,
2045 talk_number=self.xobj.talk_number,
2046 pseq=self.pseq,
2047 parent=self.parent,
2048 date_accepted=dates["accepted"],
2049 date_received=dates["received"],
2050 date_revised=dates["revised"],
2051 date_online_first=dates["online"],
2052 date_published=dates["published"],
2053 coi_statement=self.xobj.coi_statement,
2054 funding_statement_html=self.xobj.funding_statement_html,
2055 funding_statement_xml=self.xobj.funding_statement_xml,
2056 footnotes_html=self.xobj.footnotes_html,
2057 footnotes_xml=self.xobj.footnotes_xml,
2058 body_html=self.xobj.body_html,
2059 body_tex=self.xobj.body_tex,
2060 body_xml=self.xobj.body_xml,
2061 )
2063 article.save()
2065 return article
2067 def post_do(self, container):
2068 super().post_do(container)
2070 if hasattr(self.xobj, "incollection"):
2071 for incol in self.xobj.incollection:
2072 # Ignore the first incollection which was treated as the main collection
2073 if incol.pid != self.collection.pid:
2074 collection = model_helpers.get_collection(incol.pid)
2075 if collection:
2076 collection_membership = CollectionMembership(
2077 collection=collection,
2078 container=container,
2079 seq=incol.seq,
2080 vseries=incol.vseries,
2081 volume="",
2082 number=incol.volume,
2083 vseries_int=make_int(incol.vseries),
2084 volume_int=0,
2085 number_int=make_int(incol.volume),
2086 )
2087 collection_membership.save()
2089 add_biblio(self.xobj, container)
2090 add_counts(self.xobj, container, add_total=True)
2091 add_relations(self.xobj, container)
2092 add_frontmatter(self.xobj, container)
2094 def post_undo(self):
2095 collection = self.object_to_be_deleted.get_collection()
2096 super().post_undo()
2098 if self._publisher is not None:
2099 if self._publisher.publishes.count() == 0:
2100 self._publisher.delete()
2101 self._publisher = None
2103 if collection.parent and collection.content.count() == 0:
2104 # Child collection that was created on the fly is removed automatically
2105 # if it no longer has any content
2106 collection.delete()
2109##########################################################################
2110##########################################################################
2111#
2112# Update Commands
2113#
2114##########################################################################
2115##########################################################################
2118class updateCollectionDatabaseCmd(addResourceDatabaseCmd):
2119 """
2120 updateCollectionDatabaseCmd: updates a Collection (journal, acta)
2122 a Collection needs a Provider
2124 Exception raised:
2125 - ValueError if the init params are empty
2126 - exceptions.ResourceDoesNotExist during do if the Collection does not exist
2127 """
2129 def __init__(self, params=None):
2130 super().__init__(params)
2132 def internal_do(self):
2133 super().internal_do()
2135 try:
2136 collection = Collection.objects.get(
2137 pid=self.xobj.pid, provider__pid_type=self.provider.pid_type
2138 )
2139 except Collection.DoesNotExist:
2140 raise exceptions.ResourceDoesNotExist(f"The journal {self.xobj.pid} does not exist")
2142 # delete objects in direct relation with the collection
2143 # the new related objects (extlink, resourceid...) will be added in
2144 # addResourceDatabaseCmd::post_do
2145 collection.extlink_set.all().delete()
2146 collection.resourceid_set.all().delete()
2147 collection.abstract_set.all().delete()
2149 title_sort = (
2150 self.xobj.title_tex if len(self.xobj.title_tex) < 129 else self.xobj.title_tex[0:127]
2151 )
2153 collection.coltype = self.xobj.coltype
2154 collection.lang = self.xobj.lang
2155 collection.title_xml = self.xobj.title_xml
2156 collection.title_tex = self.xobj.title_tex
2157 collection.title_html = self.xobj.title_html
2158 collection.title_sort = title_sort
2159 collection.abbrev = self.xobj.abbrev
2161 collection.wall = self.xobj.wall
2162 collection.save()
2164 return collection
2167class updateExtLinkDatabaseCmd(baseCmd):
2168 """
2169 An extlink is a link to an external object (website, image...)
2170 updateExtLinkDatabaseCmd:
2171 - updates an ExtLink, or
2172 - creates the object if it does not exist, or
2173 - deletes the object if it exists and the new location value is empty
2175 Exception raised:
2176 - ValueError if the init params are empty
2177 """
2179 def __init__(self, params=None):
2180 self.rel = None # 'website' or 'small_icon'
2181 self.mimetype = None
2182 self.location = None
2183 self.metadata = None
2184 self.seq = None
2185 self.resource = None
2186 self.base = None
2188 super().__init__(params)
2190 self.required_params.extend(["rel", "resource"])
2192 def set_resource(self, resource):
2193 self.resource = resource
2195 def set_base(self, base):
2196 self.base = base
2198 def internal_do(self):
2199 super().internal_do()
2201 extlink = None
2203 try:
2204 extlink = ExtLink.objects.get(resource=self.resource, rel=self.rel)
2205 self.seq = extlink.seq
2207 except ExtLink.DoesNotExist:
2208 if self.location:
2209 if not self.seq:
2210 self.seq = ExtLink.objects.filter(resource=self.resource).count() + 1
2212 extlink = ExtLink(resource=self.resource, rel=self.rel, seq=self.seq)
2213 extlink.save()
2215 if self.location:
2216 extlink.location = self.location
2218 if self.rel in ["website", "test_website"]:
2219 self.metadata = "website"
2221 if self.base:
2222 extlink.base = self.base
2223 if self.mimetype:
2224 extlink.mimetype = self.mimetype
2225 if self.metadata:
2226 extlink.metadata = self.metadata
2228 extlink.seq = self.seq
2230 extlink.save()
2231 elif extlink:
2232 extlink.delete()
2233 extlink = None
2235 return extlink
2238class updateResourceIdDatabaseCmd(baseCmd):
2239 """
2240 A ResourceId is another id of the resource (doi, issn...)
2241 updateResourceIdDatabaseCmd:
2242 - updates an ResourceId, or
2243 - creates the object if it does not exist, or
2244 - deletes the object if it exists and the new location value is empty
2246 Exception raised:
2247 - ValueError if the init params are empty
2248 """
2250 def __init__(self, params={}):
2251 self.id_type = None # 'doi', 'issn', 'e-issn'
2252 self.id_value = None
2253 self.resource = None
2255 super().__init__(params)
2257 self.required_params.extend(["id_type", "resource"])
2259 def set_resource(self, resource):
2260 self.resource = resource
2262 def internal_do(self):
2263 super().internal_do()
2265 resourceid = None
2266 id_type = self.id_type
2267 id_value = self.id_value
2269 if id_type == "ojs-id": 2269 ↛ 2284line 2269 didn't jump to line 2284, because the condition on line 2269 was never false
2270 # ojs-id (aka article folder name in /cedram_dev) may not be unique
2271 # create an internal id
2272 if id_value == "edito": 2272 ↛ 2273line 2272 didn't jump to line 2273, because the condition on line 2272 was never true
2273 qs = ResourceId.objects.filter(
2274 id_type="ojs-id", id_value__startswith=id_value + "$$"
2275 )
2276 count = qs.count()
2277 if count:
2278 id_value = id_value + "$$" + str(count + 1)
2279 else:
2280 qs = ResourceId.objects.filter(id_type="ojs-id", id_value__startswith=id_value)
2281 count = qs.count()
2282 if count: 2282 ↛ 2283line 2282 didn't jump to line 2283, because the condition on line 2282 was never true
2283 id_value = id_value + "$$" + str(count + 1)
2284 try:
2285 resourceid = ResourceId.objects.get(resource=self.resource, id_type=id_type)
2287 except ResourceId.DoesNotExist:
2288 if id_value: 2288 ↛ 2291line 2288 didn't jump to line 2291, because the condition on line 2288 was never false
2289 resourceid = ResourceId(resource=self.resource, id_type=id_type, id_value=id_value)
2291 if id_value: 2291 ↛ 2294line 2291 didn't jump to line 2294, because the condition on line 2291 was never false
2292 resourceid.id_value = id_value
2293 resourceid.save()
2294 elif resourceid:
2295 resourceid.delete()
2296 resourceid = None
2298 return resourceid
2301class deleteResourceDatabaseCmd(baseCmd):
2302 """
2303 deleteResourceDatabaseCmd: base class for all resources
2304 NOT USED. TODO: remove
2305 """
2307 def __init__(self, params=None):
2308 self.pid = None # primary id given by the provider
2309 self.sid = None # surrogate id given by the provider
2310 self.provider = None
2312 super().__init__(params)
2314 def pre_do(self):
2315 super().pre_do()
2317 if self.pid is None and self.sid is None:
2318 raise ValueError("pid et sid sont vides")
2320 if self.provider is None:
2321 raise ValueError("provider est vide")
2323 def set_provider(self, provider):
2324 self.provider = provider
2326 # May raise Provider.DoesNotExist
2327 def set_provider_by_name_or_id(self, provider_name="", pid_type="", sid_type=None):
2328 self.provider = Provider.objects.get(
2329 name=provider_name, pid_type=pid_type, sid_type=sid_type
2330 )
2333class publishArticleDatabaseCmd(baseCmd):
2334 """
2335 Publish an article <=> Create a pub-date
2336 @return: list of updated articles
2337 """
2339 def __init__(self, params=None):
2340 self.article = None
2341 self.container = None
2342 self.pre_publish = False # Publish on the test website
2343 self.update_db = True
2344 super().__init__(params)
2346 self.required_params.extend(["article"])
2348 def set_article(self, article):
2349 self.article = article
2350 self.container = article.my_container
2351 if self.container is None and article.classname == "TranslatedArticle":
2352 self.container = self.article.original_article.my_container
2354 def publish_article(self, article, update_articles):
2355 # In a collection with standalone articles, the article number is based on
2356 # the publication order.
2357 # It has to be updated when we publish because of the articles excluded for publication
2358 update_article_number = False
2359 # TODO: use a param instead of checking PCJ
2360 if self.container.my_collection.pid == "PCJ" and not self.pre_publish: 2360 ↛ 2361line 2360 didn't jump to line 2361, because the condition on line 2360 was never true
2361 update_article_number = True
2363 article_number = (
2364 self.container.article_set.filter(date_published__isnull=False).count() + 1
2365 )
2367 if (not article.date_published and not self.pre_publish) or ( 2367 ↛ exitline 2367 didn't return from function 'publish_article', because the condition on line 2367 was never false
2368 not article.date_pre_published and self.pre_publish
2369 ):
2370 today = model_helpers.parse_date_str(timezone.now().isoformat())
2372 # Les articles numérisés n'ont pas à avoir de date_published
2373 # Les anciens articles issus de Cedrics ont déjà une date_published.
2374 # Les nouveaux articles du Centre Mersenne sont publiés à partir de 2019.
2375 year = article.get_year()
2376 fyear, lyear = model_helpers.get_first_last_years(year)
2377 try:
2378 fyear = int(fyear)
2379 except ValueError:
2380 fyear = 0
2382 if fyear > 2016 and not self.container.with_online_first:
2383 if self.pre_publish: 2383 ↛ 2384line 2383 didn't jump to line 2384, because the condition on line 2383 was never true
2384 article.date_pre_published = today
2385 else:
2386 article.date_published = today
2387 if update_article_number: 2387 ↛ 2388line 2387 didn't jump to line 2388, because the condition on line 2387 was never true
2388 article.article_number = "e" + str(article_number)
2389 article_number += 1
2390 if self.update_db: 2390 ↛ 2392line 2390 didn't jump to line 2392, because the condition on line 2390 was never false
2391 article.save()
2392 update_articles.append(article)
2393 elif fyear == 0 or self.container.with_online_first: 2393 ↛ 2394line 2393 didn't jump to line 2394, because the condition on line 2393 was never true
2394 if not article.date_online_first and not self.pre_publish:
2395 # Online First
2396 article.date_online_first = today
2397 if self.update_db:
2398 article.save()
2399 update_articles.append(article)
2400 elif self.pre_publish:
2401 article.date_pre_published = today
2402 if self.update_db:
2403 article.save()
2404 update_articles.append(article)
2406 def internal_do(self):
2407 update_articles = []
2409 # In a collection with standalone articles, the article number is based on
2410 # the publication order.
2411 # It has to be updated when we publish because of the articles excluded for publication
2412 update_article_number = False
2413 # TODO: use a param instead of checking PCJ
2414 if self.container.my_collection.pid == "PCJ" and not self.pre_publish:
2415 update_article_number = True
2417 self.publish_article(self.article, update_articles)
2419 # TODO: update in upload articles ?
2421 # PCJ: update the article seq, it is used by the breadcrumb
2422 if update_article_number:
2423 i = 1
2424 for article in self.container.article_set.exclude(do_not_publish=True).order_by(
2425 "-date_published"
2426 ):
2427 article.seq = i
2428 i += 1
2429 article.save()
2431 return update_articles
2434class publishContainerDatabaseCmd(publishArticleDatabaseCmd):
2435 """
2436 Publish a container <=> Create a pub-date for all articles/book-parts of the container
2437 @var : fake : if True, return list of potentially updated articles BUT don't update database
2438 @return: list of updated articles
2439 """
2441 def __init__(self, params=None):
2442 super().__init__(params)
2444 self.required_params = ["container"]
2446 def set_container(self, container):
2447 self.container = container
2449 def internal_do(self):
2450 update_articles = []
2452 # In a collection with standalone articles, the article number is based on
2453 # the publication order.
2454 # It has to be updated when we publish because of the articles excluded for publication
2455 update_article_number = False
2456 # TODO: use a param instead of checking PCJ
2457 if self.container.my_collection.pid == "PCJ" and not self.pre_publish: 2457 ↛ 2458line 2457 didn't jump to line 2458, because the condition on line 2457 was never true
2458 update_article_number = True
2460 for article in self.container.article_set.exclude(do_not_publish=True):
2461 self.publish_article(article, update_articles)
2463 # PCJ: update the article seq, it is used by the breadcrumb
2464 if update_article_number: 2464 ↛ 2465line 2464 didn't jump to line 2465, because the condition on line 2464 was never true
2465 i = 1
2466 for article in self.container.article_set.exclude(do_not_publish=True).order_by(
2467 "-date_published"
2468 ):
2469 article.seq = i
2470 i += 1
2471 article.save()
2473 return update_articles
2475 # TODO Le container(book) peut également avoir une date de publication
2478def convert_contribs(pid, delete=False):
2479 if pid == "PCJ":
2480 # PCJ: pid start with "10_24072"
2481 pid = "10_24072"
2483 if delete:
2484 revert_contribs(pid)
2486 if pid is not None:
2487 qs = Contrib.objects.filter(
2488 Q(group__resource__pid__startswith=pid)
2489 | Q(group__bibitem__resource__pid__startswith=pid)
2490 )
2491 else:
2492 qs = Contrib.objects.all()[0:100]
2494 total = qs.count()
2495 i = 1
2496 percent = 0
2498 for contrib in qs:
2499 if int(i / total * 100) > percent:
2500 percent += 1
2501 if percent % 5 == 0:
2502 print(pid, percent)
2503 i += 1
2505 # contrib_fields_list = Contrib.get_fields_list()
2506 # contrib_fields = {
2507 # attr_name: getattr(contrib, attr_name) for attr_name in contrib_fields_list
2508 # }
2510 # Augment the contrib attributes to match Contribution fields
2511 role = contrib.contrib_type
2512 if not role:
2513 role = contrib.group.content_type
2514 if not role:
2515 role = "author"
2516 if role[-1] == "s":
2517 role = role[0:-1]
2518 contrib.corresponding = role == "corresponding"
2519 contrib.role = role if role != "corresponding" else "author"
2521 ref_name = contrib.last_name if contrib.last_name else None
2522 if ref_name is None:
2523 ref_name = contrib.string_name if contrib.string_name else None
2524 letter = get_first_letter(ref_name) if ref_name else ""
2525 contrib.first_letter = letter
2527 contrib.deceased_before_publication = contrib.deceased
2528 contrib.idref = None
2529 contrib.mid = None
2531 contribution_fields_list = Contribution.get_fields_list()
2532 contributions_fields = {
2533 attr_name: getattr(contrib, attr_name) for attr_name in contribution_fields_list
2534 }
2536 contribution = Contribution(
2537 resource=contrib.group.resource, bibitem=contrib.group.bibitem, **contributions_fields
2538 )
2539 contribution.save()
2541 for contrib_address in contrib.contribaddress_set.all():
2542 contrib_address.contribution = contribution
2543 contrib_address.save()
2545 qs = Contribution.objects.filter(
2546 Q(resource__pid__startswith=pid) | Q(bibitem__resource__pid__startswith=pid)
2547 )
2548 print(qs.count())
2551def revert_contribs(pid):
2552 print(f"Delete Contribution for {pid}", end=" ")
2553 Contribution.objects.filter(
2554 Q(resource__pid__startswith=pid) | Q(bibitem__resource__pid__startswith=pid)
2555 ).delete()
2556 print("done")