Coverage for apps/ptf/cmds/database_cmds.py: 61%
1157 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-19 19:20 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-05-19 19:20 +0000
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 SiteMembership
37from ..models import Stats
38from ..models import Subj
39from ..models import SupplementaryMaterial
40from ..models import TranslatedArticle
41from ..models import XmlBase
42from ..models import parse_page_count
43from .base_cmds import baseCmd
44from .base_cmds import make_int
46# TODO: call full_clean before each .save() call to validate a Model object
47# It requires to update models.py and add some blank=True to fields that can be null/empty
48# Example: number and vseries for a Container
51def get_first_letter(name):
52 letter = ""
53 if name:
54 letter = name[0]
55 letter = unidecode(letter)
56 if len(letter) > 1:
57 letter = letter[0]
58 letter = letter.upper()
59 if letter == "?":
60 letter = "Z"
62 # with 't Hooft, G => first_letter is H
63 if name.startswith("'t") and len(name) > 3:
64 letter = name[3].upper()
66 return letter
69def add_contributors(contributors, resource=None, bibitem=None):
70 if resource is None and bibitem is None: 70 ↛ 71line 70 didn't jump to line 71, because the condition on line 70 was never true
71 raise RuntimeError("add_contributors: resource and bibitem are None")
73 seq = 0
74 for contrib in contributors:
75 seq += 1
77 contrib["seq"] = seq
78 contribution_fields_list = Contribution.get_fields_list()
79 contributions_fields = {
80 key: contrib[key] for key in contribution_fields_list if key in contrib
81 }
83 contribution = Contribution(resource=resource, bibitem=bibitem, **contributions_fields)
84 contribution.save()
86 for addr in contrib["addresses"]:
87 contrib_address = ContribAddress(contribution=contribution, address=addr)
88 contrib_address.save()
90 if bibitem is None and contribution.role == "author" and not contribution.is_etal():
91 ref_name = contribution.mid if contribution.mid else str(contribution)
92 try:
93 author = Author.objects.get(name=ref_name)
94 author.count += 1
95 except Author.DoesNotExist:
96 letter = ref_name[0]
97 letter = unidecode(letter)
98 if len(letter) > 1: 98 ↛ 99line 98 didn't jump to line 99, because the condition on line 98 was never true
99 letter = letter[0]
100 letter = letter.upper()
101 if letter == "?": 101 ↛ 102line 101 didn't jump to line 102, because the condition on line 101 was never true
102 letter = "Z"
104 # with 't Hooft, G => first_letter is H
105 if ref_name.startswith("'t") and len(ref_name) > 3: 105 ↛ 106line 105 didn't jump to line 106, because the condition on line 105 was never true
106 letter = ref_name[3].upper()
108 author = Author(name=ref_name, first_letter=letter, count=1)
109 author.save()
112def add_counts(xobj, resource, add_total=False):
113 seq = 1
114 for name, value in xobj.counts:
115 try:
116 ResourceCount.objects.get(resource=resource, name=name)
117 raise exceptions.ResourceExists(f"The ResourceCount {name} already exists")
118 except ResourceCount.DoesNotExist:
119 resource_count = ResourceCount(resource=resource, name=name, seq=seq, value=value)
121 resource_count.save()
123 if name == "page-count" and add_total: 123 ↛ 134line 123 didn't jump to line 134, because the condition on line 123 was never false
124 value = parse_page_count(value)
126 try:
127 total = Stats.objects.get(name=name)
128 total.value += value
129 except Stats.DoesNotExist:
130 total = Stats(name=name, value=value)
132 total.save()
134 seq += 1
137def add_biblio(xobj, resource):
138 for seq, xbibitem in enumerate(xobj.bibitems, start=1):
139 bibitem = BibItem(
140 resource=resource,
141 sequence=seq,
142 label=xbibitem.label,
143 citation_xml=xbibitem.citation_xml,
144 citation_tex=xbibitem.citation_tex,
145 citation_html=xbibitem.citation_html,
146 type=xbibitem.type,
147 user_id=xbibitem.user_id,
148 article_title_tex=xbibitem.article_title_tex,
149 chapter_title_tex=xbibitem.chapter_title_tex,
150 source_tex=xbibitem.source_tex,
151 publisher_name=xbibitem.publisher_name,
152 publisher_loc=xbibitem.publisher_loc,
153 institution=xbibitem.institution,
154 series=xbibitem.series,
155 volume=xbibitem.volume,
156 issue=xbibitem.issue,
157 month=xbibitem.month,
158 year=xbibitem.year,
159 comment=xbibitem.comment,
160 annotation=xbibitem.annotation,
161 fpage=xbibitem.fpage,
162 lpage=xbibitem.lpage,
163 page_range=xbibitem.page_range,
164 size=xbibitem.size,
165 )
167 bibitem.save()
169 add_contributors(contributors=xbibitem.contributors, bibitem=bibitem)
171 if xbibitem.extids:
172 the_types = []
173 for id_type, id_value in xbibitem.extids:
174 if id_type and id_type not in the_types:
175 the_types.append(id_type)
177 bibitemid = BibItemId(
178 bibitem=bibitem,
179 id_type=id_type,
180 id_value=id_value,
181 checked=True,
182 false_positive=False,
183 )
185 bibitemid.save()
188def add_relations(xobj, resource):
189 for relation in xobj.relations:
190 with_doi = "10." in relation.id_value
191 if with_doi and resource.doi is None: 191 ↛ 192line 191 didn't jump to line 192, because the condition on line 191 was never true
192 raise ValueError(
193 f"The article {resource.pid} has no DOI but uses the relation {relation.rel_type} with the DOI {relation.id_value}"
194 )
196 # First, we need to find if the relation is stored in the RelationName as a left or right attribute
197 name = relation.rel_type
198 relationname = model_helpers.get_relationname_left(left_name=name)
200 if relationname:
201 # RelationName with a left attribute (ex "follows"):
202 # the subject of the relationship is the xml parent (typically the article defined by the xml)
203 # the object is the id declared by the <related-article>
204 # Example <article>
205 # <article_id ...>A</article-id>
206 # <related-article ... related-article-type="follows">B</related-article>
207 # => RelationShip with subject = A and object = B
209 subject_pid = resource.doi if with_doi else resource.pid
210 subject_resource = resource
211 object_pid = relation.id_value
212 # Find the resource to update the related article
213 # But to work during a regular import, the related article must already be in the database
214 # Depending on the import order, it might not work
215 if with_doi: 215 ↛ 216line 215 didn't jump to line 216, because the condition on line 215 was never true
216 object_resource = model_helpers.get_article_by_doi(relation.id_value)
217 else:
218 object_resource = model_helpers.get_article(relation.id_value)
219 else:
220 relationname = model_helpers.get_relationname_right(right_name=name)
222 if relationname: 222 ↛ 244line 222 didn't jump to line 244, because the condition on line 222 was never false
223 # RelationName with a right attribute (ex "followed-by"):
224 # the subject of the relationship is the id declared by the <related-article>
225 # the object is the xml parent (typically the article defined by the xml)
226 # Example <article>
227 # <article_id ...>A</article-id>
228 # <related-article ... related-article-type="followed-by">B</related-article>
229 # => RelationShip with subject = B and object = A
231 subject_pid = relation.id_value
232 # Find the resource to update the related article
233 # But to work during a regular import, the related article must already be in the database
234 # Depending on the import order, it might not work
235 if with_doi: 235 ↛ 236line 235 didn't jump to line 236, because the condition on line 235 was never true
236 subject_resource = model_helpers.get_article_by_doi(relation.id_value)
237 else:
238 subject_resource = model_helpers.get_article(relation.id_value)
240 object_pid = resource.doi if with_doi else resource.pid
241 object_resource = resource
243 # Elsevier creates basic relation. Create the relationname on the fly if necessary
244 if not relationname and name == "refers to": 244 ↛ 245line 244 didn't jump to line 245, because the condition on line 244 was never true
245 relationname = RelationName(
246 left="refers to",
247 right="is referenced by",
248 gauche="fait référence à",
249 droite="est référencé par",
250 )
251 relationname.save()
253 subject_pid = resource.doi if with_doi else resource.pid
254 subject_resource = resource
255 object_pid = relation.id_value
256 # Find the resource to update the related article
257 # But to work during a regular import, the related article must already be in the database
258 # Depending on the import order, it might not work
259 if with_doi:
260 object_resource = model_helpers.get_article_by_doi(relation.id_value)
261 else:
262 object_resource = model_helpers.get_article(relation.id_value)
264 if relationname: 264 ↛ 189line 264 didn't jump to line 189, because the condition on line 264 was never false
265 params = {"subject_pid": subject_pid, "object_pid": object_pid, "solr_commit": False}
266 cmd = addRelationshipDatabaseCmd(params)
267 if subject_resource is not None:
268 cmd.set_subject_resource(subject_resource)
269 if object_resource is not None:
270 cmd.set_object_resource(object_resource)
271 cmd.set_relationname(relationname)
273 try:
274 relationship = Relationship.objects.get(
275 subject_pid=subject_pid, object_pid=object_pid, rel_info=relationname
276 )
277 # la première fois que l'on crée la relation une des 2 ressources ID est a priori None
278 # la deuxième fois (la relation symétrique) il faut compléter la
279 # RelationShip
280 if relationship.resource is not None and relationship.related is not None: 280 ↛ 281line 280 didn't jump to line 281, because the condition on line 280 was never true
281 raise exceptions.ResourceExists(
282 f"The Relationship {subject_pid} {relationname.left} {object_pid} already exists"
283 )
284 if subject_resource is not None: 284 ↛ 286line 284 didn't jump to line 286, because the condition on line 284 was never false
285 relationship.resource = subject_resource
286 if object_resource is not None: 286 ↛ 288line 286 didn't jump to line 288, because the condition on line 286 was never false
287 relationship.related = object_resource
288 relationship.save()
290 except Relationship.DoesNotExist:
291 relationship = Relationship(
292 subject_pid=subject_pid,
293 object_pid=object_pid,
294 resource=subject_resource,
295 related=object_resource,
296 rel_info=relationname,
297 )
298 relationship.save()
301def add_frontmatter(xobj, resource):
302 if hasattr(xobj, "frontmatter_xml") and xobj.frontmatter_xml is not None:
303 frontmatter = FrontMatter(
304 resource=resource,
305 value_xml=xobj.frontmatter_xml,
306 value_html=xobj.frontmatter_toc_html,
307 foreword_html=xobj.frontmatter_foreword_html,
308 )
309 frontmatter.save()
312def add_publisher(xobj):
313 if hasattr(xobj, "publisher") and xobj.publisher:
314 publisher = model_helpers.get_publisher(xobj.publisher.name)
316 if publisher is None:
317 cmd = addPublisherDatabaseCmd({"xobj": xobj.publisher})
318 publisher = cmd.do()
320 return publisher
323class addSiteDatabaseCmd(baseCmd):
324 """
325 addSiteDatabaseCmd: adds/remove a PtfSite
327 Exception raised:
328 - ValueError if the init params are empty
329 - exceptions.ResourceExists during do if the site already exists
330 - exceptions.ResourceDoesNotExist during undo if the site does not exist
331 - RuntimeError during undo if resources are still deployed
332 """
334 def __init__(self, params=None):
335 self.site_name = None
336 self.site_domain = None
337 self.site_id = None
339 super().__init__(params)
341 if not self.site_name: 341 ↛ 342line 341 didn't jump to line 342, because the condition on line 341 was never true
342 self.site_name = settings.SITE_NAME
344 if not self.site_domain: 344 ↛ 345line 344 didn't jump to line 345, because the condition on line 344 was never true
345 self.site_domain = settings.SITE_DOMAIN
347 self.required_params.extend(["site_name", "site_domain", "site_id"])
349 # Returns a PtfSite
350 def internal_do(self):
351 super().internal_do()
353 try:
354 PtfSite.objects.get(name=self.site_name)
355 raise exceptions.ResourceExists(
356 "The site " + self.site_name + " " + self.site_domain + " already exists"
357 )
358 except PtfSite.DoesNotExist:
359 site = PtfSite(
360 domain=self.site_domain, name=self.site_name, acro=self.site_name, id=self.site_id
361 )
362 site.save()
364 return site
366 def pre_undo(self):
367 super().pre_undo()
369 if SiteMembership.objects.filter(site__name=self.site_name).exists():
370 raise RuntimeError(
371 "Impossible de supprimer le site car il y a encore des ressources publiees"
372 )
374 def internal_undo(self):
375 super().internal_undo()
377 try:
378 # may throw PtfSite.DoesNotExist
379 site = PtfSite.objects.get(name=self.site_name)
380 id = site.id
381 site.delete()
382 except PtfSite.DoesNotExist:
383 raise exceptions.ResourceDoesNotExist("The site " + self.site_name + " does not exist")
385 return id
388class addProviderDatabaseCmd(baseCmd):
389 """
390 addProviderDatabaseCmd: adds/remove a Provider
392 Exception raised:
393 - ValueError if the init params are empty
394 - exceptions.ResourceExists during do if the provider already exists
395 - exceptions.ResourceDoesNotExist during undo if the provider does not exist
396 """
398 def __init__(self, params=None):
399 self.name = None
400 self.pid_type = None
401 self.sid_type = None
403 super().__init__(params)
405 self.required_params.extend(["name", "pid_type"])
407 def internal_do(self):
408 super().internal_do()
410 try:
411 Provider.objects.get(name=self.name, pid_type=self.pid_type, sid_type=self.sid_type)
412 raise exceptions.ResourceExists("The provider " + self.name + " already exists")
413 except Provider.DoesNotExist:
414 p = Provider(name=self.name, pid_type=self.pid_type, sid_type=self.sid_type)
415 p.save()
417 return p
419 def internal_undo(self):
420 super().internal_undo()
422 try:
423 p = Provider.objects.get(
424 name=self.name, pid_type=self.pid_type, sid_type=self.sid_type
425 )
426 id = p.id
427 p.delete()
428 except Provider.DoesNotExist:
429 raise exceptions.ResourceDoesNotExist("The provider " + self.name + " does not exist")
431 return id
434class addXmlBaseDatabaseCmd(baseCmd):
435 """
436 addXmlBaseDatabaseCmd: adds/remove an XmlBase
438 XmlBase is the root URL of an ExtLink (ex: http://archive.numdam.org/article)
440 Exception raised:
441 - ValueError if the init params are empty
442 - exceptions.ResourceExists during do if the XmlBase already exists
443 - exceptions.ResourceDoesNotExist during undo if the XmlBase does not exist
444 - RuntimeError during undo if related extlinks or objects still exist
445 """
447 def __init__(self, params=None):
448 self.base = None # Ex: http://archive.numdam.org/article
450 super().__init__(params)
452 self.required_params.extend(["base"])
454 def internal_do(self):
455 super().internal_do()
457 try:
458 XmlBase.objects.get(base=self.base)
459 raise exceptions.ResourceExists("The xmlbase " + self.base + " already exists")
460 except XmlBase.DoesNotExist:
461 xmlbase = XmlBase(base=self.base)
462 xmlbase.save()
464 return xmlbase
466 def internal_undo(self):
467 super().internal_undo()
469 try:
470 xmlbase = XmlBase.objects.get(base=self.base)
471 id = xmlbase.id
472 except XmlBase.DoesNotExist:
473 raise exceptions.ResourceDoesNotExist("The xmlbase " + self.base + " does not exist")
475 try:
476 extlink = ExtLink.objects.get(base=xmlbase)
478 if extlink:
479 raise RuntimeError(
480 "Impossible de supprimer cette ressource car elle est encore utilisee par des ExtLinks"
481 )
483 except ExtLink.DoesNotExist:
484 pass
486 try:
487 related_object = RelatedObject.objects.get(base=xmlbase)
489 if related_object:
490 raise RuntimeError(
491 "Impossible de supprimer cette ressource car elle est encore utilisee par des RelatedObjects"
492 )
494 except RelatedObject.DoesNotExist:
495 pass
497 xmlbase.delete()
498 return id
501class addExtLinkDatabaseCmd(baseCmd):
502 """
503 addExtLinkDatabaseCmd: adds/remove an ExtLink
504 An extlink is a link to an external object (image...)
506 Exception raised:
507 - ValueError if the init params are empty
508 - exceptions.ResourceExists during do if the ExtLink already exists
509 - exceptions.ResourceDoesNotExist during undo if the ExtLink does not exist
510 - RuntimeError during undo if resources are still deployed
511 """
513 def __init__(self, params=None):
514 self.rel = None # 'website' or 'small_icon'
515 self.mimetype = None
516 self.location = None
517 self.metadata = None
518 self.seq = None
519 self.resource = None
520 self.base = None
522 super().__init__(params)
524 self.required_params.extend(["rel", "location", "seq", "resource"])
526 def set_resource(self, resource):
527 self.resource = resource
529 def set_base(self, base):
530 self.base = base
532 def internal_do(self):
533 super().internal_do()
535 try:
536 ExtLink.objects.get(
537 resource=self.resource,
538 base=self.base,
539 rel=self.rel,
540 mimetype=self.mimetype,
541 location=self.location,
542 metadata=self.metadata,
543 seq=self.seq,
544 )
545 raise exceptions.ResourceExists(
546 "The ExtLink " + self.base + " " + self.rel + " already exists"
547 )
548 except ExtLink.DoesNotExist:
549 extlink = ExtLink(
550 resource=self.resource,
551 base=self.base,
552 rel=self.rel,
553 mimetype=self.mimetype,
554 location=self.location,
555 metadata=self.metadata,
556 seq=self.seq,
557 )
558 extlink.save()
560 return extlink
562 def internal_undo(self):
563 super().internal_undo()
565 try:
566 extlink = ExtLink.objects.get(resource=self.resource, base=self.base, rel=self.rel)
567 id = extlink.id
568 extlink.delete()
569 except ExtLink.DoesNotExist:
570 raise exceptions.ResourceDoesNotExist("The extlink " + self.rel + " does not exist")
572 return id
575class addExtIdDatabaseCmd(baseCmd):
576 """
577 addExtIdDatabaseCmd: adds/remove an ExtId
579 Exception raised:
580 - ValueError if the init params are empty
581 - exceptions.ResourceExists during do if the ExtId already exists
582 - exceptions.ResourceDoesNotExist during undo if the ExtId does not exist
583 - RuntimeError during undo if resources are still deployed
584 """
586 def __init__(self, params=None):
587 self.resource = None
588 self.id_type = None
589 self.id_value = None
590 self.checked = True
591 self.false_positive = False
593 super().__init__(params)
595 self.required_params.extend(["id_type", "id_value", "resource"])
597 def set_resource(self, resource):
598 self.resource = resource
600 def internal_do(self):
601 super().internal_do()
603 try:
604 # May raise Resource.DoesNotExist
605 extid = ExtId.objects.get(
606 resource=self.resource, id_type=self.id_type, id_value=self.id_value
607 )
608 except ExtId.DoesNotExist:
609 extid = ExtId(
610 resource=self.resource,
611 id_type=self.id_type,
612 id_value=self.id_value,
613 checked=self.checked,
614 false_positive=self.false_positive,
615 )
616 extid.save()
618 return extid
620 def internal_undo(self):
621 super().internal_undo()
623 try:
624 extid = ExtId.objects.get(
625 resource=self.resource, id_type=self.id_type, id_value=self.id_value
626 )
627 id = extid.id
628 extid.delete()
629 except ExtId.DoesNotExist:
630 raise exceptions.ResourceDoesNotExist("The extid " + self.id_value + " does not exist")
632 return id
635class addRelatedObjectDatabaseCmd(baseCmd):
636 """
637 addRelatedObjectDatabaseCmd: adds/remove a RelatedObject
639 a related object is a pdf/djvu... attached to the object (article...)
640 It can be for example a listing of a program attached to an article.
642 Exception raised:
643 - ValueError if the init params are empty
644 - exceptions.ResourceExists during do if the RelatedObject already exists
645 - exceptions.ResourceDoesNotExist during undo if the RelatedObject does not exist
646 - RuntimeError during undo if resources are still deployed
647 """
649 def __init__(self, params=None):
650 self.rel = None
651 self.mimetype = None
652 self.location = None
653 self.metadata = None
654 self.seq = None
655 self.resource = None
656 self.base = None
658 super().__init__(params)
660 self.required_params.extend(["rel", "location", "seq", "resource"])
662 def set_resource(self, resource):
663 self.resource = resource
665 def set_base(self, base):
666 self.base = base
668 def internal_do(self):
669 super().internal_do()
671 try:
672 RelatedObject.objects.get(
673 resource=self.resource,
674 base=self.base,
675 rel=self.rel,
676 mimetype=self.mimetype,
677 location=self.location,
678 metadata=self.metadata,
679 seq=self.seq,
680 )
681 raise exceptions.ResourceExists(
682 "The RelatedObject "
683 + self.base
684 + " "
685 + self.rel
686 + " "
687 + self.location
688 + " already exists"
689 )
690 except RelatedObject.DoesNotExist:
691 related_object = RelatedObject(
692 resource=self.resource,
693 base=self.base,
694 rel=self.rel,
695 mimetype=self.mimetype,
696 location=self.location,
697 metadata=self.metadata,
698 seq=self.seq,
699 )
701 related_object.save()
703 return related_object
705 def internal_undo(self):
706 super().internal_undo()
708 try:
709 related_object = RelatedObject.objects.get(
710 resource=self.resource, base=self.base, rel=self.rel, location=self.location
711 )
712 id = related_object.id
713 related_object.delete()
714 except RelatedObject.DoesNotExist:
715 raise exceptions.ResourceDoesNotExist(
716 "The relatedobject " + self.location + " does not exist"
717 )
719 return id
722class addSupplementaryMaterialDatabaseCmd(addRelatedObjectDatabaseCmd):
723 """
724 addSupplementaryMaterialDatabaseCmd: adds/remove a Supplementary Materiel
726 a supplementary material is a pdf/djvu... attached to the object (article...)
727 It can be for example a listing of a program attached to an article.
729 Exception raised:
730 - ValueError if the init params are empty
731 - exceptions.ResourceExists during do if the RelatedObject already exists
732 - exceptions.ResourceDoesNotExist during undo if the RelatedObject does not exist
733 - RuntimeError during undo if resources are still deployed
734 """
736 def __init__(self, params=None):
737 super().__init__(params)
739 def internal_do(self):
740 supplementary_material, _created = SupplementaryMaterial.objects.update_or_create(
741 caption=self.caption,
742 resource=self.resource,
743 base=self.base,
744 rel=self.rel,
745 mimetype=self.mimetype,
746 location=self.location,
747 metadata=self.metadata,
748 seq=self.seq,
749 )
750 return supplementary_material
752 def internal_undo(self):
753 try:
754 supplementary_material = SupplementaryMaterial.objects.get(
755 resource=self.resource, base=self.base, rel=self.rel, location=self.location
756 )
757 pk = supplementary_material.pk
758 supplementary_material.delete()
759 except SupplementaryMaterial.DoesNotExist:
760 raise exceptions.ResourceDoesNotExist(
761 "The SupplementaryMaterial " + self.location + " does not exist"
762 )
763 return pk
766class addDataStreamDatabaseCmd(baseCmd):
767 """
768 addDataStreamDatabaseCmd: adds/remove a DataStream
770 a datastream is the pdf/djvu... of the object (container, article)
772 Exception raised:
773 - ValueError if the init params are empty
774 - exceptions.ResourceExists during do if the DataStream already exists
775 - exceptions.ResourceDoesNotExist during undo if the DataStream does not exist
776 - RuntimeError during undo if resources are still deployed
777 """
779 def __init__(self, params=None):
780 self.rel = None
781 self.mimetype = None
782 self.location = None
783 self.text = None
784 self.seq = None
785 self.resource = None
786 self.base = None
788 super().__init__(params)
790 self.required_params.extend(["rel", "location", "seq", "resource"])
792 def set_resource(self, resource):
793 self.resource = resource
795 def set_base(self, base):
796 self.base = base
798 def internal_do(self):
799 super().internal_do()
801 try:
802 DataStream.objects.get(
803 resource=self.resource,
804 base=self.base,
805 rel=self.rel,
806 mimetype=self.mimetype,
807 location=self.location,
808 text=self.text,
809 seq=self.seq,
810 )
811 raise exceptions.ResourceExists(
812 "The DataStream "
813 + self.base
814 + " "
815 + self.rel
816 + " "
817 + self.location
818 + " already exists"
819 )
820 except DataStream.DoesNotExist:
821 datastream = DataStream(
822 resource=self.resource,
823 base=self.base,
824 rel=self.rel,
825 mimetype=self.mimetype,
826 location=self.location,
827 text=self.text,
828 seq=self.seq,
829 )
831 datastream.save()
833 return datastream
835 def internal_undo(self):
836 super().internal_undo()
838 try:
839 datastream = DataStream.objects.get(
840 resource=self.resource, base=self.base, rel=self.rel, location=self.location
841 )
842 id = datastream.id
843 datastream.delete()
844 except DataStream.DoesNotExist:
845 raise exceptions.ResourceDoesNotExist(
846 "The datastream " + self.location + " does not exist"
847 )
849 return id
852class addResourceCountDatabaseCmd(baseCmd):
853 """
854 addResourceCountDatabaseCmd: adds/remove a ResourceCount
856 A ResourceCount is a generic count element.
857 Exemple: page count, table count, image count...
859 Exception raised:
860 - ValueError if the init params are empty
861 - exceptions.ResourceExists during do if the ResourceCount already exists
862 - exceptions.ResourceDoesNotExist during undo if the ResourceCount does not exist
863 - RuntimeError during undo if resources are still deployed
864 """
866 def __init__(self, params=None):
867 self.seq = None
868 self.name = None
869 self.value = None
870 self.resource = None
871 self.add_total = False
873 super().__init__(params)
875 self.required_params.extend(["seq", "name", "value", "resource"])
877 def set_resource(self, resource):
878 self.resource = resource
880 def internal_do(self):
881 super().internal_do()
883 try:
884 ResourceCount.objects.get(resource=self.resource, name=self.name)
885 raise exceptions.ResourceExists("The ResourceCount " + self.name + " already exists")
886 except ResourceCount.DoesNotExist:
887 resource_count = ResourceCount(
888 resource=self.resource, name=self.name, seq=self.seq, value=self.value
889 )
891 resource_count.save()
893 if self.name == "page-count" and self.add_total:
894 value = parse_page_count(self.value)
896 try:
897 total = Stats.objects.get(name=self.name)
898 total.value += value
899 except Stats.DoesNotExist:
900 total = Stats(name=self.name, value=value)
902 total.save()
904 return resource_count
906 def internal_undo(self):
907 super().internal_undo()
909 try:
910 resource_count = ResourceCount.objects.get(resource=self.resource, name=self.name)
911 id = resource_count.id
912 resource_count.delete()
913 except ResourceCount.DoesNotExist:
914 raise exceptions.ResourceDoesNotExist("The count " + self.name + " does not exist")
916 return id
919class addMetaDataPartDatabaseCmd(baseCmd):
920 """
921 addMetaDataPartDatabaseCmd: adds/remove a MetaDataPart
923 A MetaDataPart is a generic count element.
924 Exemple: page count, table count, image count...
926 Exception raised:
927 - ValueError if the init params are empty
928 - exceptions.ResourceExists during do if the MetaDataPart already exists
929 - exceptions.ResourceDoesNotExist during undo if the MetaDataPart does not exist
930 - RuntimeError during undo if resources are still deployed
931 """
933 def __init__(self, params=None):
934 self.seq = None
935 self.name = None
936 self.data = None
937 self.resource = None
939 super().__init__(params)
941 self.required_params.extend(["seq", "name", "data", "resource"])
943 def set_resource(self, resource):
944 self.resource = resource
946 def internal_do(self):
947 super().internal_do()
949 try:
950 MetaDataPart.objects.get(resource=self.resource, name=self.name)
951 raise exceptions.ResourceExists("The MetaDataPart " + self.name + " already exists")
952 except MetaDataPart.DoesNotExist:
953 metadatapart = MetaDataPart(
954 resource=self.resource, name=self.name, seq=self.seq, data=self.data
955 )
957 metadatapart.save()
959 return metadatapart
961 def internal_undo(self):
962 super().internal_undo()
964 try:
965 metadatapart = MetaDataPart.objects.get(resource=self.resource, name=self.name)
966 id = metadatapart.id
967 metadatapart.delete()
968 except MetaDataPart.DoesNotExist:
969 raise exceptions.ResourceDoesNotExist(
970 "The metadatapart " + self.name + " does not exist"
971 )
973 return id
976class addBibItemDatabaseCmd(baseCmd):
977 """
978 addBibItemDatabaseCmd: adds/remove a BibItem
980 No verification is done to check if a BibItem already exists
981 Rationale: BibItems are only added in a loop within an article.
982 The check is actually the existence of the article.
984 Exception raised:
985 - ValueError if the init params are empty
986 - exceptions.ResourceDoesNotExist during undo if the BibItem does not exist
987 - RuntimeError during undo if resources are still deployed
988 """
990 def __init__(self, params=None):
991 self.sequence = None
992 self.label = ""
993 self.citation_xml = None
994 self.citation_tex = None
995 self.citation_html = None
996 self.resource = None
998 self.type = ""
999 self.user_id = ""
1000 self.title_tex = ""
1001 self.publisher_name = ""
1002 self.publisher_loc = ""
1003 self.institution = ""
1004 self.series = ""
1005 self.volume = ""
1006 self.issue = ""
1007 self.month = ""
1008 self.year = ""
1009 self.comment = ""
1010 self.annotation = ""
1011 self.fpage = ""
1012 self.lpage = ""
1013 self.page_range = ""
1014 self.size = ""
1015 self.source = ""
1016 self.article_title_tex = ""
1017 self.chapter_title_tex = ""
1019 self.contributors = None
1021 super().__init__(params)
1023 self.required_params.extend(["sequence", "citation_xml", "resource"])
1025 def set_resource(self, resource):
1026 self.resource = resource
1028 def internal_do(self):
1029 super().internal_do()
1031 bibitem = BibItem(
1032 resource=self.resource,
1033 sequence=self.sequence,
1034 label=self.label,
1035 citation_xml=self.citation_xml,
1036 citation_tex=self.citation_tex,
1037 citation_html=self.citation_html,
1038 type=self.type,
1039 user_id=self.user_id,
1040 article_title_tex=self.article_title_tex,
1041 chapter_title_tex=self.chapter_title_tex,
1042 source_tex=self.source_tex,
1043 publisher_name=self.publisher_name,
1044 publisher_loc=self.publisher_loc,
1045 institution=self.institution,
1046 series=self.series,
1047 volume=self.volume,
1048 issue=self.issue,
1049 month=self.month,
1050 year=self.year,
1051 comment=self.comment,
1052 annotation=self.annotation,
1053 fpage=self.fpage,
1054 lpage=self.lpage,
1055 page_range=self.page_range,
1056 size=self.size,
1057 )
1059 bibitem.save()
1061 return bibitem
1063 def post_do(self, bibitem):
1064 super().post_do(bibitem)
1066 add_contributors(contributors=self.contributors, bibitem=bibitem)
1068 def internal_undo(self):
1069 super().internal_undo()
1071 try:
1072 bibitem = BibItem.objects.get(resource=self.resource, sequence=self.sequence)
1073 id = bibitem.id
1074 bibitem.delete()
1075 except BibItem.DoesNotExist:
1076 raise exceptions.ResourceDoesNotExist(
1077 "The bibitem " + self.sequence + " does not exist"
1078 )
1080 return id
1083class addBibItemIdDatabaseCmd(baseCmd):
1084 """
1085 addBibItemIdDatabaseCmd: adds/remove a BibItemId
1087 No verification is done to check if a BibItemId already exists
1088 Rationale: BibItems are only added in a loop within an article.
1089 The check is actually the existence of the article.
1091 Exception raised:
1092 - ValueError if the init params are empty
1093 - exceptions.ResourceDoesNotExist during undo if the BibItemId does not exist
1094 - RuntimeError during undo if resources are still deployed
1095 """
1097 def __init__(self, params=None):
1098 self.bibitem = None
1099 self.id_type = None
1100 self.id_value = None
1101 self.checked = True
1102 self.false_positive = False
1104 super().__init__(params)
1106 self.required_params.extend(["bibitem", "id_type", "id_value"])
1108 def set_bibitem(self, bibitem):
1109 self.bibitem = bibitem
1111 def internal_do(self):
1112 super().internal_do()
1114 bibitemid = BibItemId(
1115 bibitem=self.bibitem,
1116 id_type=self.id_type,
1117 id_value=self.id_value,
1118 checked=self.checked,
1119 false_positive=self.false_positive,
1120 )
1122 bibitemid.save()
1124 return bibitemid
1126 def internal_undo(self):
1127 super().internal_undo()
1129 try:
1130 bibitemid = BibItemId.objects.get(
1131 bibitem=self.bibitem, id_type=self.id_type, id_value=self.id_value
1132 )
1133 id = bibitemid.id
1134 bibitemid.delete()
1135 except BibItemId.DoesNotExist:
1136 raise exceptions.ResourceDoesNotExist(
1137 "The bibitemid " + self.value + " does not exist"
1138 )
1140 return id
1143class addFrontMatterDatabaseCmd(baseCmd):
1144 """
1145 addFrontMatterDatabaseCmd: adds/remove a FrontMatter
1147 No verification is done to check if a FrontMatter already exists
1148 Rationale: FrontMatters are only added in a loop within an article.
1149 The check is actually the existence of the article.
1151 Exception raised:
1152 - ValueError if the init params are empty
1153 - exceptions.ResourceDoesNotExist during undo if the FrontMatter does not exist
1154 - RuntimeError during undo if resources are still deployed
1155 """
1157 def __init__(self, params=None):
1158 self.value_xml = ""
1159 self.value_html = ""
1160 self.foreword_html = ""
1161 self.resource = None
1163 super().__init__(params)
1165 self.required_params.extend(["value_xml", "resource"])
1167 def set_resource(self, resource):
1168 self.resource = resource
1170 def internal_do(self):
1171 super().internal_do()
1173 frontmatter = FrontMatter(
1174 resource=self.resource,
1175 value_xml=self.value_xml,
1176 value_html=self.value_html,
1177 foreword_html=self.foreword_html,
1178 )
1180 frontmatter.save()
1182 return frontmatter
1184 def internal_undo(self):
1185 super().internal_undo()
1187 try:
1188 frontmatter = FrontMatter.objects.get(resource=self.resource)
1189 id = frontmatter.id
1190 frontmatter.delete()
1191 except FrontMatter.DoesNotExist:
1192 raise exceptions.ResourceDoesNotExist(
1193 "The front-matter " + self.text + " does not exist"
1194 )
1196 return id
1199class addRelationshipDatabaseCmd(baseCmd):
1200 """
1201 addRelationshipDatabaseCmd: adds/remove a Relationship
1203 Relationship relates 2 resources (ex: articles) with a relation. ex "follows", "followed-by"
1205 RelationName are created with a fixture (see app/ptf/apps/ptf/fixtures/initial_data.json
1206 Example { "left" : "follows", "right" : "followed-by" }
1207 A related-article of an article has 1 relation name (ex "follows" or "followed-by")
1208 You need to know if the relation was stored in the left or right attribute of a RelationName,
1209 so that you can create/search the Relationship with the correct object/subject.
1210 Ex: with A "follows" B, A is the subject and B the object because "follows" is a RelationName.left attribute
1211 with A "followed-by" B, A is the object the B the subject because
1212 "followed-by" is a RelationName.right attribute
1213 A Relationship relates 2 resources with a RelationName
1216 Exception raised:
1217 - ValueError if the init params are empty
1218 - exceptions.ResourceExists during do if the Relationship already exists
1219 - exceptions.ResourceDoesNotExist during undo if the Relationship does not exist
1220 - RuntimeError during undo if resources are still deployed
1221 """
1223 def __init__(self, params=None):
1224 self.subject_resource = None
1225 self.subject_pid = None
1226 self.object_resource = None
1227 self.object_pid = None
1228 self.relationname = None
1230 super().__init__(params)
1232 self.required_params.extend(["subject_pid", "object_pid", "relationname"])
1234 def set_subject_resource(self, resource):
1235 self.subject_resource = resource
1236 # self.subject_pid = resource.pid
1238 def set_object_resource(self, resource):
1239 self.object_resource = resource
1240 # self.object_pid = resource.pid
1242 def set_relationname(self, relationname):
1243 self.relationname = relationname
1245 def internal_do(self):
1246 super().internal_do()
1248 try:
1249 relationship = Relationship.objects.get(
1250 subject_pid=self.subject_pid,
1251 object_pid=self.object_pid,
1252 rel_info=self.relationname,
1253 )
1254 # la première fois que l'on crée la relation une des 2 ressourcesID est a priori None
1255 # la deuxième fois (la relation symétrique) il faut compléter la
1256 # RelationShip
1257 if relationship.resource is not None and relationship.related is not None:
1258 raise exceptions.ResourceExists(
1259 "The Relationship {} {} {} already exists".format(
1260 self.subject_pid, self.relationname.left, self.object_pid
1261 )
1262 )
1263 if self.subject_resource is not None:
1264 relationship.resource = self.subject_resource
1265 if self.object_resource is not None:
1266 relationship.related = self.object_resource
1267 relationship.save()
1269 except Relationship.DoesNotExist:
1270 relationship = Relationship(
1271 subject_pid=self.subject_pid,
1272 object_pid=self.object_pid,
1273 resource=self.subject_resource,
1274 related=self.object_resource,
1275 rel_info=self.relationname,
1276 )
1278 relationship.save()
1280 return relationship
1282 def internal_undo(self):
1283 super().internal_undo()
1285 try:
1286 relationship = Relationship.objects.get(
1287 subject_pid=self.subject_pid,
1288 object_pid=self.object_pid,
1289 rel_info=self.relationname,
1290 )
1291 id = relationship.id
1293 # Create relationship is typically a 2 steps process
1294 # (1: create the relationship with only 1 resource. 2: update the relationship with the 2nd resource)
1295 # Undo is also a 2 steps process
1296 # (1: unset a resource. 2: delete the relationship)
1297 if relationship.resource is not None and relationship.related is not None:
1298 # Both left and right resources are set: unset the resource
1299 # that was given as param
1300 if self.subject_resource is None:
1301 relationship.related = None
1302 else:
1303 relationship.resource = None
1304 relationship.save()
1305 else:
1306 relationship.delete()
1307 except Relationship.DoesNotExist:
1308 raise exceptions.ResourceDoesNotExist(
1309 "The relationship " + self.relationname + " does not exist"
1310 )
1312 return id
1315class addResourceDatabaseCmd(baseCmd):
1316 """
1317 addResourceDatabaseCmd: base class for all resources
1319 Exception raised:
1320 - exceptions.ResourceDoesNotExist during undo if the Resource does not exist
1321 """
1323 def __init__(self, params=None):
1324 self.xobj = None # model_data object
1326 self.provider = None
1327 self._prod_deployed_date = None
1329 super().__init__(params)
1331 self.required_params.extend(["xobj", "provider"])
1333 # May raise ValueError
1334 def check_params(self):
1335 super().check_params()
1337 if hasattr(self.xobj, "pid") and not self.xobj.pid and not self.xobj.sid: 1337 ↛ 1338line 1337 didn't jump to line 1338, because the condition on line 1337 was never true
1338 raise ValueError("pid et sid sont vides")
1340 def set_provider(self, provider):
1341 self.provider = provider
1343 # May raise Provider.DoesNotExist
1344 def set_provider_by_name_or_id(self, provider_name="", pid_type="", sid_type=None):
1345 self.provider = Provider.objects.get(
1346 name=provider_name, pid_type=pid_type, sid_type=sid_type
1347 )
1349 def post_do(self, resource):
1350 super().post_do(resource)
1351 self.object_to_be_deleted = resource
1353 site = model_helpers.get_or_create_site(settings.SITE_ID)
1354 if site: 1354 ↛ 1360line 1354 didn't jump to line 1360, because the condition on line 1354 was never false
1355 resource.deploy(site, self._prod_deployed_date)
1357 # Creation of SiteMembership for production website on ptf_tools is handled in DeployJatsIssue
1358 # Restoration of SiteMembership is handled in importExtraDataPtfCmd
1360 for id_type, id_value in self.xobj.ids:
1361 if ( 1361 ↛ 1360line 1361 didn't jump to line 1360
1362 id_type != self.provider.pid_type
1363 and id_type != self.provider.sid_type
1364 and (id_type != "numdam-id" or self.provider.pid_type != "mathdoc-id")
1365 ):
1366 try:
1367 # May raise Resource.DoesNotExist
1368 resource_id = ResourceId.objects.get(
1369 resource=resource, id_type=id_type, id_value=id_value
1370 )
1371 except ResourceId.DoesNotExist:
1372 resource_id = ResourceId(resource=resource, id_type=id_type, id_value=id_value)
1373 resource_id.save()
1375 for id_type, id_value in self.xobj.extids:
1376 if ( 1376 ↛ 1375line 1376 didn't jump to line 1375
1377 id_type != self.provider.pid_type
1378 and id_type != self.provider.sid_type
1379 and (id_type != "numdam-id" or self.provider.pid_type != "mathdoc-id")
1380 ):
1381 try:
1382 # May raise Resource.DoesNotExist
1383 ExtId.objects.get(resource=resource, id_type=id_type, id_value=id_value)
1384 except ExtId.DoesNotExist:
1385 ext_id = ExtId(resource=resource, id_type=id_type, id_value=id_value)
1386 ext_id.save()
1388 seq = 1
1389 for a in self.xobj.abstracts:
1390 value_xml = a["value_xml"] if "value_xml" in a else ""
1391 value_html = a["value_html"] if "value_html" in a else ""
1392 value_tex = a["value_tex"] if "value_tex" in a else ""
1394 la = Abstract(
1395 resource=resource,
1396 tag=a["tag"],
1397 lang=a["lang"],
1398 seq=seq,
1399 value_xml=value_xml,
1400 value_html=value_html,
1401 value_tex=value_tex,
1402 )
1403 la.save()
1404 seq += 1
1406 add_contributors(contributors=self.xobj.contributors, resource=resource)
1408 for i, kwd in enumerate(self.xobj.kwds):
1409 k = Kwd(
1410 resource=resource, lang=kwd["lang"], type=kwd["type"], value=kwd["value"], seq=i
1411 )
1412 k.save()
1414 for i, subj in enumerate(self.xobj.subjs):
1415 s = Subj(
1416 resource=resource, lang=subj["lang"], type=subj["type"], value=subj["value"], seq=i
1417 )
1418 s.save()
1420 seq = 1
1421 for a in self.xobj.awards:
1422 abbrev = a["abbrev"]
1423 award_id = a["award_id"]
1425 award = Award(resource=resource, abbrev=abbrev, award_id=award_id, seq=seq)
1426 award.save()
1427 seq += 1
1429 # TODO custom meta
1431 def pre_undo(self):
1432 super().pre_undo()
1434 # None value not detected in check_params (required_delete_params)
1435 # => undo was already called
1436 if self.object_to_be_deleted is None:
1437 raise exceptions.ResourceDoesNotExist("The object to be deleted no longer exists")
1439 # Django automatically deletes related objects such as ResourceIds,
1440 # Abstracts...
1442 # Author are deleted by signals (see models.py)
1443 # Another solution would be to do it here
1445 # Undeploy the resource in all sites
1446 for site in self.object_to_be_deleted.sites.all():
1447 self.object_to_be_deleted.undeploy(site)
1449 def internal_undo(self):
1450 super().internal_undo()
1452 id = self.object_to_be_deleted.id
1453 self.object_to_be_deleted.delete()
1455 return id
1457 def post_undo(self):
1458 super().internal_undo()
1460 self.object_to_be_deleted = None # prevents a 2nd attempt to delete
1463class addPublisherDatabaseCmd(baseCmd):
1464 """
1465 addPublisherDatabaseCmd: adds/remove a publisher
1467 Exception raised:
1468 - ValueError if the init params are empty
1469 - exceptions.ResourceExists during do if the Publisher already exists
1470 - exceptions.ResourceDoesNotExist during undo if the Publisher does not exist
1471 """
1473 def __init__(self, params=None):
1474 self.xobj = None # model_data object
1475 self.object_to_be_deleted = None
1477 super().__init__(params)
1479 self.required_params.extend(["xobj"])
1480 self.required_delete_params.append("object_to_be_deleted")
1482 def set_object_to_be_deleted(self, obj):
1483 self.object_to_be_deleted = obj
1485 def internal_do(self):
1486 super().internal_do()
1488 # A Publisher is a resource. Therefore it needs a provider (that provides the publisher id/key)
1489 # As we are creating the key, Mathdoc is the provider
1490 provider = Provider.objects.get(name="mathdoc", pid_type="mathdoc-id")
1491 key = model_helpers.make_key(self.xobj.name)
1493 try:
1494 Publisher.objects.get(pub_key=key)
1495 raise exceptions.ResourceExists("The publisher " + self.xobj.name + " already exists")
1496 except Publisher.DoesNotExist:
1497 publisher = Publisher(
1498 pub_key=key,
1499 pub_name=self.xobj.name,
1500 pub_loc=self.xobj.loc,
1501 pid=key,
1502 provider=provider,
1503 )
1504 publisher.save()
1506 self.object_to_be_deleted = publisher
1507 return publisher
1509 def internal_undo(self):
1510 super().internal_undo()
1512 # None value not detected in check_params (required_delete_params)
1513 # => undo was already called
1514 if self.object_to_be_deleted is None:
1515 raise exceptions.ResourceDoesNotExist("The object to be deleted no longer exists")
1517 self.object_to_be_deleted.refresh_from_db()
1519 if self.object_to_be_deleted.publishes.count():
1520 raise RuntimeError(
1521 "Impossible de supprimer ce publisher car il a encore des resources qui sont publiées par ce publisher"
1522 )
1524 id = self.object_to_be_deleted.id
1525 self.object_to_be_deleted.delete()
1526 self.object_to_be_deleted = None
1528 return id
1531class addContainerDatabaseCmd(addResourceDatabaseCmd):
1532 """
1533 addContainerDatabaseCmd: adds/remove a container
1535 an Container needs a Collection
1537 Exception raised:
1538 - ValueError if the init params are empty
1539 - exceptions.ResourceExists during do if the container already exists
1540 - exceptions.ResourceDoesNotExist during undo if the Container does not exist
1541 """
1543 def __init__(self, params=None):
1544 self.last_modified = None
1545 self.collection = None
1546 self._publisher = None
1548 super().__init__(params)
1550 self.required_params.extend(["collection"])
1552 def add_collection(self, collection):
1553 if not self.collection: 1553 ↛ exitline 1553 didn't return from function 'add_collection', because the condition on line 1553 was never false
1554 self.collection = collection
1556 def pre_do(self):
1557 super().pre_do()
1559 self._publisher = add_publisher(self.xobj)
1561 def internal_do(self):
1562 super().internal_do()
1564 vseries = volume = number = seq = ""
1565 if hasattr(self.xobj, "volume"):
1566 vseries = self.xobj.vseries
1567 volume = self.xobj.volume
1568 number = self.xobj.number
1569 seq = self.xobj.seq
1570 elif len(self.xobj.incollection) > 0: 1570 ↛ 1579line 1570 didn't jump to line 1579, because the condition on line 1570 was never false
1571 # Books do not have vseries/volume/number, but a list of incollection
1572 # Set vseries/volume/number from the 1st incollection (the main collection)
1573 incol = self.xobj.incollection[0]
1574 vseries = incol.vseries
1575 volume = ""
1576 number = incol.volume
1577 seq = incol.seq
1579 if settings.CONTAINER_SEQUENCED: 1579 ↛ 1580line 1579 didn't jump to line 1580, because the condition on line 1579 was never true
1580 seq = make_int(volume) if volume else make_int(self.xobj.year)
1582 last_modified = model_helpers.parse_date_str(self.xobj.last_modified_iso_8601_date_str)
1583 if self.xobj.prod_deployed_date_iso_8601_date_str:
1584 self._prod_deployed_date = model_helpers.parse_date_str(
1585 self.xobj.prod_deployed_date_iso_8601_date_str
1586 )
1588 with_online_first = (
1589 self.xobj.with_online_first if hasattr(self.xobj, "with_online_first") else False
1590 )
1592 try:
1593 Container.objects.get(
1594 pid=self.xobj.pid,
1595 provider__pid_type=self.provider.pid_type,
1596 my_collection__pid=self.collection.pid,
1597 )
1598 raise exceptions.ResourceExists("The container " + self.xobj.pid + " already exists")
1600 except Container.DoesNotExist:
1601 container = Container(
1602 ctype=self.xobj.ctype,
1603 doi=self.xobj.doi,
1604 pid=self.xobj.pid,
1605 lang=self.xobj.lang,
1606 title_xml=self.xobj.title_xml,
1607 title_tex=self.xobj.title_tex,
1608 title_html=self.xobj.title_html,
1609 trans_lang=self.xobj.trans_lang,
1610 trans_title_tex=self.xobj.trans_title_tex,
1611 trans_title_html=self.xobj.trans_title_html,
1612 provider=self.provider,
1613 my_publisher=self._publisher,
1614 my_collection=self.collection,
1615 year=self.xobj.year,
1616 vseries=vseries,
1617 vseries_int=make_int(vseries),
1618 volume=volume,
1619 volume_int=make_int(volume),
1620 number=number,
1621 number_int=make_int(number),
1622 seq=seq,
1623 last_modified=last_modified,
1624 with_online_first=with_online_first,
1625 body_html=self.xobj.body_html,
1626 body_tex=self.xobj.body_tex,
1627 body_xml=self.xobj.body_xml,
1628 )
1630 container.save()
1632 return container
1634 def post_do(self, container):
1635 super().post_do(container)
1637 if hasattr(self.xobj, "incollection"):
1638 for incol in self.xobj.incollection:
1639 # Ignore the first incollection which was treated as the main collection
1640 if incol.pid != self.collection.pid:
1641 collection = model_helpers.get_collection(incol.pid)
1642 if collection: 1642 ↛ 1638line 1642 didn't jump to line 1638, because the condition on line 1642 was never false
1643 collection_membership = CollectionMembership(
1644 collection=collection,
1645 container=container,
1646 seq=incol.seq,
1647 vseries=incol.vseries,
1648 volume="",
1649 number=incol.volume,
1650 vseries_int=make_int(incol.vseries),
1651 volume_int=0,
1652 number_int=make_int(incol.volume),
1653 )
1654 collection_membership.save()
1656 add_biblio(self.xobj, container)
1657 add_counts(self.xobj, container, add_total=True)
1658 add_relations(self.xobj, container)
1659 add_frontmatter(self.xobj, container)
1661 def post_undo(self):
1662 collection = self.object_to_be_deleted.get_collection()
1663 super().post_undo()
1665 if self._publisher is not None:
1666 if self._publisher.publishes.count() == 0:
1667 self._publisher.delete()
1668 self._publisher = None
1670 if collection.parent and collection.content.count() == 0:
1671 # Child collection that was created on the fly is removed automatically
1672 # if it no longer has any content
1673 collection.delete()
1676class addArticleDatabaseCmd(addResourceDatabaseCmd):
1677 """
1678 addArticleDatabaseCmd: adds/remove an article
1680 an article needs a container (book or issue)
1682 Exception raised:
1683 - ValueError if the init params are empty
1684 - exceptions.ResourceExists during do if the article already exists
1685 - exceptions.ResourceDoesNotExist during undo if the Article does not exist
1686 """
1688 def __init__(self, params=None):
1689 # parents are used for book parts.
1690 self.pseq = 0 # parent seq
1691 self.parent = None # article parent
1693 # Container containing the article
1694 self.container = None
1695 self.collection = None
1697 self.assign_doi = False
1698 self.seq = 0
1700 self.translated_articles = []
1702 super().__init__(params)
1704 def check_params(self):
1705 super().check_params()
1707 check_title = True
1708 if hasattr(self.xobj, "doi") and self.xobj.doi and self.xobj.doi.find("pcjournal") > 0:
1709 check_title = False
1710 if "original_article" in self.required_params: 1710 ↛ 1712line 1710 didn't jump to line 1712, because the condition on line 1710 was never true
1711 # A Translation may not have a title
1712 check_title = False
1713 if ( 1713 ↛ 1719line 1713 didn't jump to line 1719
1714 check_title
1715 and self.is_add_cmd
1716 and not self.xobj.title_tex
1717 and not self.xobj.trans_title_tex
1718 ):
1719 raise ValueError("title_tex et trans_title_tex sont vides")
1721 def set_container(self, container):
1722 self.container = container
1723 self.collection = container.my_collection
1724 self.set_provider(container.provider)
1726 def set_collection(self, collection):
1727 self.collection = collection
1728 self.set_provider(collection.provider)
1730 def set_parent(self, parent):
1731 self.parent = parent
1733 def parse_dates(self):
1734 dates = {
1735 "accepted": None,
1736 "received": None,
1737 "revised": None,
1738 "online": None,
1739 "published": None,
1740 }
1742 for date_entry in self.xobj.history_dates:
1743 if date_entry["date"] is None: 1743 ↛ 1744line 1743 didn't jump to line 1744, because the condition on line 1743 was never true
1744 raise ValueError(
1745 f"The date {date_entry['type']} of the article {self.xobj.pid} is None"
1746 )
1748 date = model_helpers.parse_date_str(date_entry["date"])
1749 dates[date_entry["type"]] = date
1751 if self.xobj.date_published_iso_8601_date_str:
1752 dates["published"] = model_helpers.parse_date_str(
1753 self.xobj.date_published_iso_8601_date_str
1754 )
1756 if self.xobj.prod_deployed_date_iso_8601_date_str:
1757 self._prod_deployed_date = model_helpers.parse_date_str(
1758 self.xobj.prod_deployed_date_iso_8601_date_str
1759 )
1761 return dates
1763 def add_translations(self, xobj, article):
1764 if hasattr(xobj, "translations") and xobj.translations is not None: 1764 ↛ exitline 1764 didn't return from function 'add_translations', because the condition on line 1764 was never false
1765 for xarticle in xobj.translations: 1765 ↛ 1766line 1765 didn't jump to line 1766, because the loop on line 1765 never started
1766 cmd = addTranslatedArticleDatabaseCmd({"xobj": xarticle})
1767 cmd.set_original_article(article)
1768 cmd.set_provider(article.provider)
1769 trans_article = cmd.do()
1770 self.translated_articles.append(trans_article)
1772 def internal_do(self):
1773 super().internal_do()
1775 doi = self.xobj.doi
1776 if self.assign_doi and not doi and self.container:
1777 colid = self.container.my_collection.pid
1778 doi = model_helpers.assign_doi(colid)
1780 seq = self.xobj.seq or self.seq
1781 dates = self.parse_dates()
1783 try:
1784 Article.objects.get(
1785 pid=self.xobj.pid, doi=doi, provider=self.provider, my_container=self.container
1786 )
1787 raise exceptions.ResourceExists("The article " + self.xobj.pid + " already exists")
1788 except Article.DoesNotExist:
1789 article = Article(
1790 pid=self.xobj.pid,
1791 doi=doi,
1792 lang=self.xobj.lang,
1793 title_xml=self.xobj.title_xml,
1794 title_tex=self.xobj.title_tex,
1795 title_html=self.xobj.title_html,
1796 trans_lang=self.xobj.trans_lang,
1797 trans_title_tex=self.xobj.trans_title_tex,
1798 trans_title_html=self.xobj.trans_title_html,
1799 provider=self.provider,
1800 my_container=self.container,
1801 fpage=self.xobj.fpage,
1802 lpage=self.xobj.lpage,
1803 seq=seq,
1804 atype=self.xobj.atype,
1805 page_range=self.xobj.page_range,
1806 page_type=self.xobj.page_type,
1807 elocation=self.xobj.elocation,
1808 article_number=self.xobj.article_number,
1809 talk_number=self.xobj.talk_number,
1810 pseq=self.pseq,
1811 parent=self.parent,
1812 date_accepted=dates["accepted"],
1813 date_received=dates["received"],
1814 date_revised=dates["revised"],
1815 date_online_first=dates["online"],
1816 date_published=dates["published"],
1817 coi_statement=self.xobj.coi_statement,
1818 funding_statement_html=self.xobj.funding_statement_html,
1819 funding_statement_xml=self.xobj.funding_statement_xml,
1820 footnotes_html=self.xobj.footnotes_html,
1821 footnotes_xml=self.xobj.footnotes_xml,
1822 body_html=self.xobj.body_html,
1823 body_tex=self.xobj.body_tex,
1824 body_xml=self.xobj.body_xml,
1825 )
1827 article.save()
1829 if doi:
1830 collection = self.collection
1831 doi_number = model_helpers.get_number_from_doi(doi)
1832 if doi_number > collection.last_doi:
1833 collection.last_doi = doi_number
1834 collection.save()
1836 return article
1838 def post_do(self, article):
1839 super().post_do(article)
1841 add_biblio(self.xobj, article)
1842 add_counts(self.xobj, article, add_total=True)
1843 add_relations(self.xobj, article)
1844 self.add_translations(self.xobj, article)
1847class addCollectionDatabaseCmd(addResourceDatabaseCmd):
1848 """
1849 addCollectionDatabaseCmd: adds/remove a collection
1851 Exception raised:
1852 - ValueError if the init params are empty
1853 - exceptions.ResourceExists during do if the book already exists
1854 - exceptions.ResourceDoesNotExist during undo if the book does not exist
1855 """
1857 def __init__(self, params=None):
1858 # self.coltype = None
1859 # self.wall = 5
1860 self.parent = None
1862 super().__init__(params)
1864 def set_parent(self, parent):
1865 self.parent = parent
1867 def internal_do(self):
1868 super().internal_do()
1870 title_sort = (
1871 self.xobj.title_tex if len(self.xobj.title_tex) < 129 else self.xobj.title_tex[0:127]
1872 )
1874 try:
1875 col = Collection.objects.get(
1876 pid=self.xobj.pid,
1877 title_tex=self.xobj.title_tex,
1878 provider__pid_type=self.provider.pid_type,
1879 )
1880 except Collection.DoesNotExist:
1881 col = Collection.objects.create(
1882 coltype=self.xobj.coltype,
1883 abbrev=self.xobj.abbrev,
1884 wall=self.xobj.wall,
1885 pid=self.xobj.pid,
1886 lang=self.xobj.lang,
1887 title_xml=self.xobj.title_xml,
1888 title_tex=self.xobj.title_tex,
1889 title_html=self.xobj.title_html,
1890 title_sort=title_sort,
1891 trans_lang=self.xobj.trans_lang,
1892 trans_title_tex=self.xobj.trans_title_tex,
1893 trans_title_html=self.xobj.trans_title_html,
1894 provider=self.provider,
1895 parent=self.parent,
1896 )
1897 else:
1898 raise exceptions.ResourceExists(f"The collection pid:{self.xobj.pid} already exists")
1899 return col
1901 # def internal_undo(self):
1902 # super().internal_undo()
1903 #
1904 # try:
1905 # col = Collection.objects.get(pid=self.pid,
1906 # provider__pid_type=self.provider.pid_type)
1907 # id = col.id
1908 # if col.parent and not col.ancestors.all().count() :
1909 # col.parent = None
1910 # col.delete()
1911 #
1912 #
1913 # elif not col.parent and not col.ancestors.all().count() :
1914 # col.delete()
1915 #
1916 # except Collection.DoesNotExist:
1917 # raise exceptions.ResourceDoesNotExist(
1918 # "The collection " + self.pid + " does not exist")
1919 #
1920 # return id
1923class addTranslatedArticleDatabaseCmd(addArticleDatabaseCmd):
1924 """
1925 addTranslatedArticleDatabaseCmd: adds/remove a translated article
1926 """
1928 def __init__(self, params=None):
1929 super().__init__(params)
1931 self.original_article = None
1933 self.required_params = ["xobj", "original_article"]
1935 def set_original_article(self, original_article):
1936 self.original_article = original_article
1938 def internal_do(self):
1939 # DO NOT CALL the parent internal_do or it will create an Article
1941 dates = self.parse_dates()
1943 try:
1944 TranslatedArticle.objects.get(pid=self.xobj.pid)
1945 raise exceptions.ResourceExists(
1946 "The translated article " + self.xobj.pid + " already exists"
1947 )
1948 except Article.DoesNotExist:
1949 article = TranslatedArticle(
1950 original_article=self.original_article,
1951 pid=self.xobj.pid,
1952 doi=self.xobj.doi,
1953 lang=self.xobj.lang,
1954 title_xml=self.xobj.title_xml,
1955 title_tex=self.xobj.title_tex,
1956 title_html=self.xobj.title_html,
1957 trans_lang=self.xobj.trans_lang,
1958 trans_title_tex=self.xobj.trans_title_tex,
1959 trans_title_html=self.xobj.trans_title_html,
1960 provider=self.provider,
1961 my_container=None,
1962 fpage=self.xobj.fpage,
1963 lpage=self.xobj.lpage,
1964 seq=self.xobj.seq,
1965 atype=self.xobj.atype,
1966 page_range=self.xobj.page_range,
1967 page_type=self.xobj.page_type,
1968 elocation=self.xobj.elocation,
1969 article_number=self.xobj.article_number,
1970 talk_number=self.xobj.talk_number,
1971 pseq=self.pseq,
1972 parent=self.parent,
1973 date_accepted=dates["accepted"],
1974 date_received=dates["received"],
1975 date_revised=dates["revised"],
1976 date_online_first=dates["online"],
1977 date_published=dates["published"],
1978 coi_statement=self.xobj.coi_statement,
1979 funding_statement_html=self.xobj.funding_statement_html,
1980 funding_statement_xml=self.xobj.funding_statement_xml,
1981 footnotes_html=self.xobj.footnotes_html,
1982 footnotes_xml=self.xobj.footnotes_xml,
1983 body_html=self.xobj.body_html,
1984 body_tex=self.xobj.body_tex,
1985 body_xml=self.xobj.body_xml,
1986 )
1988 article.save()
1990 return article
1992 def post_do(self, container):
1993 super().post_do(container)
1995 if hasattr(self.xobj, "incollection"):
1996 for incol in self.xobj.incollection:
1997 # Ignore the first incollection which was treated as the main collection
1998 if incol.pid != self.collection.pid:
1999 collection = model_helpers.get_collection(incol.pid)
2000 if collection:
2001 collection_membership = CollectionMembership(
2002 collection=collection,
2003 container=container,
2004 seq=incol.seq,
2005 vseries=incol.vseries,
2006 volume="",
2007 number=incol.volume,
2008 vseries_int=make_int(incol.vseries),
2009 volume_int=0,
2010 number_int=make_int(incol.volume),
2011 )
2012 collection_membership.save()
2014 add_biblio(self.xobj, container)
2015 add_counts(self.xobj, container, add_total=True)
2016 add_relations(self.xobj, container)
2017 add_frontmatter(self.xobj, container)
2019 def post_undo(self):
2020 collection = self.object_to_be_deleted.get_collection()
2021 super().post_undo()
2023 if self._publisher is not None:
2024 if self._publisher.publishes.count() == 0:
2025 self._publisher.delete()
2026 self._publisher = None
2028 if collection.parent and collection.content.count() == 0:
2029 # Child collection that was created on the fly is removed automatically
2030 # if it no longer has any content
2031 collection.delete()
2034##########################################################################
2035##########################################################################
2036#
2037# Update Commands
2038#
2039##########################################################################
2040##########################################################################
2043class updateCollectionDatabaseCmd(addResourceDatabaseCmd):
2044 """
2045 updateCollectionDatabaseCmd: updates a Collection (journal, acta)
2047 a Collection needs a Provider
2049 Exception raised:
2050 - ValueError if the init params are empty
2051 - exceptions.ResourceDoesNotExist during do if the Collection does not exist
2052 """
2054 def __init__(self, params=None):
2055 super().__init__(params)
2057 def internal_do(self):
2058 super().internal_do()
2060 try:
2061 collection = Collection.objects.get(
2062 pid=self.xobj.pid, provider__pid_type=self.provider.pid_type
2063 )
2064 except Collection.DoesNotExist:
2065 raise exceptions.ResourceDoesNotExist(f"The journal {self.xobj.pid} does not exist")
2067 # delete objects in direct relation with the collection
2068 # the new related objects (extlink, resourceid...) will be added in
2069 # addResourceDatabaseCmd::post_do
2070 collection.extlink_set.all().delete()
2071 collection.resourceid_set.all().delete()
2072 collection.abstract_set.all().delete()
2074 title_sort = (
2075 self.xobj.title_tex if len(self.xobj.title_tex) < 129 else self.xobj.title_tex[0:127]
2076 )
2078 collection.coltype = self.xobj.coltype
2079 collection.lang = self.xobj.lang
2080 collection.title_xml = self.xobj.title_xml
2081 collection.title_tex = self.xobj.title_tex
2082 collection.title_html = self.xobj.title_html
2083 collection.title_sort = title_sort
2084 collection.abbrev = self.xobj.abbrev
2086 collection.wall = self.xobj.wall
2087 collection.save()
2089 return collection
2092class updateExtLinkDatabaseCmd(baseCmd):
2093 """
2094 An extlink is a link to an external object (website, image...)
2095 updateExtLinkDatabaseCmd:
2096 - updates an ExtLink, or
2097 - creates the object if it does not exist, or
2098 - deletes the object if it exists and the new location value is empty
2100 Exception raised:
2101 - ValueError if the init params are empty
2102 """
2104 def __init__(self, params=None):
2105 self.rel = None # 'website' or 'small_icon'
2106 self.mimetype = None
2107 self.location = None
2108 self.metadata = None
2109 self.seq = None
2110 self.resource = None
2111 self.base = None
2113 super().__init__(params)
2115 self.required_params.extend(["rel", "resource"])
2117 def set_resource(self, resource):
2118 self.resource = resource
2120 def set_base(self, base):
2121 self.base = base
2123 def internal_do(self):
2124 super().internal_do()
2126 extlink = None
2128 try:
2129 extlink = ExtLink.objects.get(resource=self.resource, rel=self.rel)
2130 self.seq = extlink.seq
2132 except ExtLink.DoesNotExist:
2133 if self.location:
2134 if not self.seq:
2135 self.seq = ExtLink.objects.filter(resource=self.resource).count() + 1
2137 extlink = ExtLink(resource=self.resource, rel=self.rel, seq=self.seq)
2138 extlink.save()
2140 if self.location:
2141 extlink.location = self.location
2143 if self.rel in ["website", "test_website"]:
2144 self.metadata = "website"
2146 if self.base:
2147 extlink.base = self.base
2148 if self.mimetype:
2149 extlink.mimetype = self.mimetype
2150 if self.metadata:
2151 extlink.metadata = self.metadata
2153 extlink.seq = self.seq
2155 extlink.save()
2156 elif extlink:
2157 extlink.delete()
2158 extlink = None
2160 return extlink
2163class updateResourceIdDatabaseCmd(baseCmd):
2164 """
2165 A ResourceId is another id of the resource (doi, issn...)
2166 updateResourceIdDatabaseCmd:
2167 - updates an ResourceId, or
2168 - creates the object if it does not exist, or
2169 - deletes the object if it exists and the new location value is empty
2171 Exception raised:
2172 - ValueError if the init params are empty
2173 """
2175 def __init__(self, params={}):
2176 self.id_type = None # 'doi', 'issn', 'e-issn'
2177 self.id_value = None
2178 self.resource = None
2180 super().__init__(params)
2182 self.required_params.extend(["id_type", "resource"])
2184 def set_resource(self, resource):
2185 self.resource = resource
2187 def internal_do(self):
2188 super().internal_do()
2190 resourceid = None
2191 id_type = self.id_type
2192 id_value = self.id_value
2194 if id_type == "ojs-id": 2194 ↛ 2209line 2194 didn't jump to line 2209, because the condition on line 2194 was never false
2195 # ojs-id (aka article folder name in /cedram_dev) may not be unique
2196 # create an internal id
2197 if id_value == "edito": 2197 ↛ 2198line 2197 didn't jump to line 2198, because the condition on line 2197 was never true
2198 qs = ResourceId.objects.filter(
2199 id_type="ojs-id", id_value__startswith=id_value + "$$"
2200 )
2201 count = qs.count()
2202 if count:
2203 id_value = id_value + "$$" + str(count + 1)
2204 else:
2205 qs = ResourceId.objects.filter(id_type="ojs-id", id_value__startswith=id_value)
2206 count = qs.count()
2207 if count: 2207 ↛ 2208line 2207 didn't jump to line 2208, because the condition on line 2207 was never true
2208 id_value = id_value + "$$" + str(count + 1)
2209 try:
2210 resourceid = ResourceId.objects.get(resource=self.resource, id_type=id_type)
2212 except ResourceId.DoesNotExist:
2213 if id_value: 2213 ↛ 2216line 2213 didn't jump to line 2216, because the condition on line 2213 was never false
2214 resourceid = ResourceId(resource=self.resource, id_type=id_type, id_value=id_value)
2216 if id_value: 2216 ↛ 2219line 2216 didn't jump to line 2219, because the condition on line 2216 was never false
2217 resourceid.id_value = id_value
2218 resourceid.save()
2219 elif resourceid:
2220 resourceid.delete()
2221 resourceid = None
2223 return resourceid
2226class deleteResourceDatabaseCmd(baseCmd):
2227 """
2228 deleteResourceDatabaseCmd: base class for all resources
2229 NOT USED. TODO: remove
2230 """
2232 def __init__(self, params=None):
2233 self.pid = None # primary id given by the provider
2234 self.sid = None # surrogate id given by the provider
2235 self.provider = None
2237 super().__init__(params)
2239 def pre_do(self):
2240 super().pre_do()
2242 if self.pid is None and self.sid is None:
2243 raise ValueError("pid et sid sont vides")
2245 if self.provider is None:
2246 raise ValueError("provider est vide")
2248 def set_provider(self, provider):
2249 self.provider = provider
2251 # May raise Provider.DoesNotExist
2252 def set_provider_by_name_or_id(self, provider_name="", pid_type="", sid_type=None):
2253 self.provider = Provider.objects.get(
2254 name=provider_name, pid_type=pid_type, sid_type=sid_type
2255 )
2258class publishArticleDatabaseCmd(baseCmd):
2259 """
2260 Publish an article <=> Create a pub-date
2261 @return: list of updated articles
2262 """
2264 def __init__(self, params=None):
2265 self.article = None
2266 self.container = None
2267 self.pre_publish = False # Publish on the test website
2268 self.update_db = True
2269 super().__init__(params)
2271 self.required_params.extend(["article"])
2273 def set_article(self, article):
2274 self.article = article
2275 self.container = article.my_container
2276 if self.container is None and article.classname == "TranslatedArticle":
2277 self.container = self.article.original_article.my_container
2279 def publish_article(self, article, update_articles):
2280 # In a collection with standalone articles, the article number is based on
2281 # the publication order.
2282 # It has to be updated when we publish because of the articles excluded for publication
2283 update_article_number = False
2284 # TODO: use a param instead of checking PCJ
2285 if self.container.my_collection.pid == "PCJ" and not self.pre_publish: 2285 ↛ 2286line 2285 didn't jump to line 2286, because the condition on line 2285 was never true
2286 update_article_number = True
2288 article_number = (
2289 self.container.article_set.filter(date_published__isnull=False).count() + 1
2290 )
2292 if (not article.date_published and not self.pre_publish) or ( 2292 ↛ exitline 2292 didn't return from function 'publish_article', because the condition on line 2292 was never false
2293 not article.date_pre_published and self.pre_publish
2294 ):
2295 today = model_helpers.parse_date_str(timezone.now().isoformat())
2297 # Les articles numérisés n'ont pas à avoir de date_published
2298 # Les anciens articles issus de Cedrics ont déjà une date_published.
2299 # Les nouveaux articles du Centre Mersenne sont publiés à partir de 2019.
2300 year = article.get_year()
2301 fyear, lyear = model_helpers.get_first_last_years(year)
2302 try:
2303 fyear = int(fyear)
2304 except ValueError:
2305 fyear = 0
2307 if fyear > 2016 and not self.container.with_online_first:
2308 if self.pre_publish: 2308 ↛ 2309line 2308 didn't jump to line 2309, because the condition on line 2308 was never true
2309 article.date_pre_published = today
2310 else:
2311 article.date_published = today
2312 if update_article_number: 2312 ↛ 2313line 2312 didn't jump to line 2313, because the condition on line 2312 was never true
2313 article.article_number = "e" + str(article_number)
2314 article_number += 1
2315 if self.update_db: 2315 ↛ 2317line 2315 didn't jump to line 2317, because the condition on line 2315 was never false
2316 article.save()
2317 update_articles.append(article)
2318 elif fyear == 0 or self.container.with_online_first: 2318 ↛ 2319line 2318 didn't jump to line 2319, because the condition on line 2318 was never true
2319 if not article.date_online_first and not self.pre_publish:
2320 # Online First
2321 article.date_online_first = today
2322 if self.update_db:
2323 article.save()
2324 update_articles.append(article)
2325 elif self.pre_publish:
2326 article.date_pre_published = today
2327 if self.update_db:
2328 article.save()
2329 update_articles.append(article)
2331 def internal_do(self):
2332 update_articles = []
2334 # In a collection with standalone articles, the article number is based on
2335 # the publication order.
2336 # It has to be updated when we publish because of the articles excluded for publication
2337 update_article_number = False
2338 # TODO: use a param instead of checking PCJ
2339 if self.container.my_collection.pid == "PCJ" and not self.pre_publish:
2340 update_article_number = True
2342 self.publish_article(self.article, update_articles)
2344 # TODO: update in upload articles ?
2346 # PCJ: update the article seq, it is used by the breadcrumb
2347 if update_article_number:
2348 i = 1
2349 for article in self.container.article_set.exclude(do_not_publish=True).order_by(
2350 "-date_published"
2351 ):
2352 article.seq = i
2353 i += 1
2354 article.save()
2356 return update_articles
2359class publishContainerDatabaseCmd(publishArticleDatabaseCmd):
2360 """
2361 Publish a container <=> Create a pub-date for all articles/book-parts of the container
2362 @var : fake : if True, return list of potentially updated articles BUT don't update database
2363 @return: list of updated articles
2364 """
2366 def __init__(self, params=None):
2367 super().__init__(params)
2369 self.required_params = ["container"]
2371 def set_container(self, container):
2372 self.container = container
2374 def internal_do(self):
2375 update_articles = []
2377 # In a collection with standalone articles, the article number is based on
2378 # the publication order.
2379 # It has to be updated when we publish because of the articles excluded for publication
2380 update_article_number = False
2381 # TODO: use a param instead of checking PCJ
2382 if self.container.my_collection.pid == "PCJ" and not self.pre_publish: 2382 ↛ 2383line 2382 didn't jump to line 2383, because the condition on line 2382 was never true
2383 update_article_number = True
2385 for article in self.container.article_set.exclude(do_not_publish=True):
2386 self.publish_article(article, update_articles)
2388 # PCJ: update the article seq, it is used by the breadcrumb
2389 if update_article_number: 2389 ↛ 2390line 2389 didn't jump to line 2390, because the condition on line 2389 was never true
2390 i = 1
2391 for article in self.container.article_set.exclude(do_not_publish=True).order_by(
2392 "-date_published"
2393 ):
2394 article.seq = i
2395 i += 1
2396 article.save()
2398 return update_articles
2400 # TODO Le container(book) peut également avoir une date de publication
2403def convert_contribs(pid, delete=False):
2404 if pid == "PCJ":
2405 # PCJ: pid start with "10_24072"
2406 pid = "10_24072"
2408 if delete:
2409 revert_contribs(pid)
2411 if pid is not None:
2412 qs = Contrib.objects.filter(
2413 Q(group__resource__pid__startswith=pid)
2414 | Q(group__bibitem__resource__pid__startswith=pid)
2415 )
2416 else:
2417 qs = Contrib.objects.all()[0:100]
2419 total = qs.count()
2420 i = 1
2421 percent = 0
2423 for contrib in qs:
2424 if int(i / total * 100) > percent:
2425 percent += 1
2426 if percent % 5 == 0:
2427 print(pid, percent)
2428 i += 1
2430 # contrib_fields_list = Contrib.get_fields_list()
2431 # contrib_fields = {
2432 # attr_name: getattr(contrib, attr_name) for attr_name in contrib_fields_list
2433 # }
2435 # Augment the contrib attributes to match Contribution fields
2436 role = contrib.contrib_type
2437 if not role:
2438 role = contrib.group.content_type
2439 if not role:
2440 role = "author"
2441 if role[-1] == "s":
2442 role = role[0:-1]
2443 contrib.corresponding = role == "corresponding"
2444 contrib.role = role if role != "corresponding" else "author"
2446 ref_name = contrib.last_name if contrib.last_name else None
2447 if ref_name is None:
2448 ref_name = contrib.string_name if contrib.string_name else None
2449 letter = get_first_letter(ref_name) if ref_name else ""
2450 contrib.first_letter = letter
2452 contrib.deceased_before_publication = contrib.deceased
2453 contrib.idref = None
2454 contrib.mid = None
2456 contribution_fields_list = Contribution.get_fields_list()
2457 contributions_fields = {
2458 attr_name: getattr(contrib, attr_name) for attr_name in contribution_fields_list
2459 }
2461 contribution = Contribution(
2462 resource=contrib.group.resource, bibitem=contrib.group.bibitem, **contributions_fields
2463 )
2464 contribution.save()
2466 for contrib_address in contrib.contribaddress_set.all():
2467 contrib_address.contribution = contribution
2468 contrib_address.save()
2470 qs = Contribution.objects.filter(
2471 Q(resource__pid__startswith=pid) | Q(bibitem__resource__pid__startswith=pid)
2472 )
2473 print(qs.count())
2476def revert_contribs(pid):
2477 print(f"Delete Contribution for {pid}", end=" ")
2478 Contribution.objects.filter(
2479 Q(resource__pid__startswith=pid) | Q(bibitem__resource__pid__startswith=pid)
2480 ).delete()
2481 print("done")