diff --git a/scipost_django/journals/factories.py b/scipost_django/journals/factories.py index 02689f39c69f5ca06a7c283590561a987f9e8ddc..9ddc58483d115e99e3f556a46c4247b5d994659e 100644 --- a/scipost_django/journals/factories.py +++ b/scipost_django/journals/factories.py @@ -8,23 +8,35 @@ from string import ascii_lowercase import factory import pytz + +from common.faker import LazyAwareDate, LazyRandEnum, fake + from common.helpers import ( - random_digits, random_external_doi, random_external_journal_abbrev, ) from faker import Faker +from funders.factories import FunderFactory, GrantFactory from journals.constants import ( + CC_LICENSES, ISSUES_AND_VOLUMES, ISSUES_ONLY, JOURNAL_STRUCTURE, PUBLICATION_PUBLISHED, ) +from journals.models import journal +from journals.models.autogenerated_file import AutogeneratedFileContentTemplate +from journals.models.deposits import DOAJDeposit, Deposit, GenericDOIDeposit +from journals.models.resource import PublicationResource +from journals.models.submission_template import SubmissionTemplate +from journals.models.update import PublicationUpdate +from ontology.factories import SpecialtyFactory from .models import Issue, Journal, Publication, Reference, Volume class ReferenceFactory(factory.django.DjangoModelFactory): + publication = factory.SubFactory("journals.factories.JournalPublicationFactory") reference_number = factory.LazyAttribute( lambda o: o.publication.references.count() + 1 ) @@ -48,14 +60,34 @@ class ReferenceFactory(factory.django.DjangoModelFactory): class JournalFactory(factory.django.DjangoModelFactory): college = factory.SubFactory("colleges.factories.CollegeFactory") - name = factory.Sequence(lambda n: "Fake Journal %s" % ascii_lowercase[n]) - doi_label = factory.Sequence(lambda n: "SciPost%s" % ascii_lowercase[n]) - issn = factory.lazy_attribute(lambda n: random_digits(8)) - structure = factory.Iterator(JOURNAL_STRUCTURE, getter=lambda c: c[0]) + name = factory.LazyAttributeSequence( + lambda self, n: f"SciPost {self.college.name} {n}" + ) + name_abbrev = factory.LazyAttribute( + lambda self: "SciPost" + "".join([w[:2] for w in self.name.split()[1:]]) + ) + doi_label = factory.SelfAttribute("name_abbrev") + issn = factory.Faker("numerify", text="########") + structure = LazyRandEnum(JOURNAL_STRUCTURE) + list_order = factory.LazyAttribute(lambda self: self.college.journals.count() + 1) + + active = True + submission_allowed = True + + oneliner = factory.Faker("sentence") + description = factory.Faker("paragraph") + scope = factory.Faker("paragraph") + acceptance_criteria = factory.Faker("paragraph") + submission_insert = factory.Faker("paragraph") + + template_latex_tgz = factory.django.FileField() + template_docx = factory.django.FileField() + + cost_info = {"default": 500} class Meta: model = Journal - django_get_or_create = ("name",) + django_get_or_create = ("name", "doi_label") @classmethod def SciPostPhysics(cls): @@ -73,16 +105,28 @@ class JournalFactory(factory.django.DjangoModelFactory): structure=ISSUES_ONLY, ) + @factory.post_generation + def specialties(self, create, extracted, **kwargs): + if not create: + return + if extracted: + self.specialties.add(*extracted) + else: + specialties = SpecialtyFactory.create_batch( + 3, acad_field=self.college.acad_field + ) + self.specialties.add(*specialties) + class VolumeFactory(factory.django.DjangoModelFactory): in_journal = factory.SubFactory(JournalFactory) - doi_label = factory.lazy_attribute( - lambda o: "%s.%i" % (o.in_journal.doi_label, o.number) + number = factory.LazyAttribute(lambda self: self.in_journal.volumes.count() + 1) + doi_label = factory.LazyAttribute( + lambda self: f"{self.in_journal.doi_label}.{self.number}" ) - number = factory.lazy_attribute(lambda o: o.in_journal.volumes.count() + 1) - start_date = factory.Faker("date_time_this_decade") - until_date = factory.lazy_attribute( - lambda o: o.start_date + datetime.timedelta(weeks=26) + start_date = LazyAwareDate("date_time_this_decade") + until_date = factory.LazyAttribute( + lambda self: fake.aware.date_between(start_date=self.start_date, end_date="+1y") ) class Meta: @@ -91,103 +135,89 @@ class VolumeFactory(factory.django.DjangoModelFactory): class IssueFactory(factory.django.DjangoModelFactory): - in_volume = factory.SubFactory(VolumeFactory) - number = factory.LazyAttribute(lambda o: o.in_volume.issues.count() + 1) + class Meta: + model = Issue + abstract = True + + class Params: + parent = None + + number = factory.LazyAttribute(lambda self: self.parent.issues.count() + 1) doi_label = factory.LazyAttribute( - lambda o: "%s.%i" % (o.in_volume.doi_label, o.number) + lambda self: "%s.%i" % (self.parent.doi_label, self.number) ) + slug = factory.LazyAttribute( + lambda self: "issue-" + self.doi_label.replace(".", "-") + ) + + +class VolumeIssueFactory(IssueFactory): + class Params: + parent = factory.SubFactory(VolumeFactory) + + in_volume = factory.SelfAttribute("parent") start_date = factory.LazyAttribute( - lambda o: Faker().date_time_between( - start_date=o.in_volume.start_date, - end_date=o.in_volume.until_date, + lambda self: Faker().date_time_between( + start_date=self.parent.start_date, + end_date=self.parent.until_date, tzinfo=pytz.UTC, ) ) until_date = factory.LazyAttribute( - lambda o: o.start_date + datetime.timedelta(weeks=4) + lambda self: fake.aware.date_between(start_date=self.start_date, end_date="+1y") ) - class Meta: - model = Issue - django_get_or_create = ("in_volume", "number") - - -class PublicationFactory(factory.django.DjangoModelFactory): - accepted_submission = factory.SubFactory( - "submissions.factories.PublishedSubmissionFactory", generate_publication=False + path = factory.LazyAttribute( + lambda self: f"JOURNALS/{self.in_volume.in_journal.doi_label}/{self.in_volume.number}/{self.number}" ) - paper_nr = 9999 - pdf_file = factory.Faker("file_name", extension="pdf") - status = PUBLICATION_PUBLISHED - submission_date = factory.Faker("date_this_year") - acceptance_date = factory.Faker("date_this_year") - publication_date = factory.Faker("date_this_year") - acad_field = factory.SelfAttribute("accepted_submission.acad_field") - title = factory.SelfAttribute("accepted_submission.title") - abstract = factory.SelfAttribute("accepted_submission.abstract") +class JournalIssueFactory(IssueFactory): + class Params: + parent = factory.SubFactory(JournalFactory, structure=ISSUES_ONLY) - # Dates - submission_date = factory.LazyAttribute( - lambda o: o.accepted_submission.submission_date - ) - acceptance_date = factory.LazyAttribute( - lambda o: o.accepted_submission.latest_activity - ) - publication_date = factory.LazyAttribute( - lambda o: o.accepted_submission.latest_activity - ) - latest_activity = factory.LazyAttribute( - lambda o: o.accepted_submission.latest_activity + in_journal = factory.SelfAttribute("parent") + + path = factory.LazyAttribute( + lambda self: f"JOURNALS/{self.in_journal.doi_label}/{self.number}" ) - # Authors - author_list = factory.LazyAttribute(lambda o: o.accepted_submission.author_list) +class BasePublicationFactory(factory.django.DjangoModelFactory): class Meta: model = Publication + abstract = True django_get_or_create = ("accepted_submission",) - - class Params: - journal = None + exclude = ("pub_container",) @factory.lazy_attribute - def in_issue(self): - # Make sure Issues, Journals and doi are correct. - if self.journal: - journal = Journal.objects.get(doi_label=self.journal) - else: - journal = Journal.objects.order_by("?").first() + def pub_container(self): + issue = getattr(self, "in_issue", None) + journal = getattr(self, "in_journal", None) + return issue or journal - if journal.has_issues: - return Issue.objects.for_journal(journal.name).order_by("?").first() - return None + # Publication data + # TODO: This should be a PublishedSubmissionFactory + accepted_submission = factory.SubFactory( + "submissions.factories.SubmissionFactory" # , generate_publication=False + ) + status = PUBLICATION_PUBLISHED @factory.lazy_attribute - def in_journal(self): - # Make sure Issues, Journals and doi are correct. - if self.journal: - journal = Journal.objects.get(doi_label=self.journal) - elif not self.in_issue: - journal = ( - Journal.objects.has_individual_publications().order_by("?").first() - ) - else: - return None + def paper_nr(self): + if self.pub_container: + return self.pub_container.publications.count() + 1 - if not journal.has_issues: - # Keep this logic in case self.journal is set. - return journal - return None + # Core fields + title = factory.SelfAttribute("accepted_submission.title") + author_list = factory.SelfAttribute("accepted_submission.author_list") + abstract = factory.SelfAttribute("accepted_submission.abstract") + pdf_file = factory.django.FileField() - @factory.lazy_attribute - def paper_nr(self): - if self.in_issue: - return self.in_issue.publications.count() + 1 - elif self.in_journal: - return self.in_journal.publications.count() + 1 + # Ontology-based semantic linking + acad_field = factory.SelfAttribute("accepted_submission.acad_field") + approaches = factory.SelfAttribute("accepted_submission.approaches") @factory.post_generation def specialties(self, create, extracted, **kwargs): @@ -196,43 +226,193 @@ class PublicationFactory(factory.django.DjangoModelFactory): self.specialties.add(*self.accepted_submission.specialties.all()) @factory.post_generation - def approaches(self, create, extracted, **kwargs): + def topics(self, create, extracted, **kwargs): if not create: return - self.approaches = self.accepted_submission.approaches + self.topics.add(*self.accepted_submission.topics.all()) - @factory.lazy_attribute - def doi_label(self): - if self.in_issue: - return self.in_issue.doi_label + "." + str(self.paper_nr).rjust(3, "0") - elif self.in_journal: - return "%s.%i" % (self.in_journal.doi_label, self.paper_nr) + cc_license = LazyRandEnum(CC_LICENSES) + # Funders @factory.post_generation - def generate_publication(self, create, extracted, **kwargs): - if create and extracted is not False: + def grants(self, create, extracted, **kwargs): + if not create: return + if extracted: + self.grants.add(*extracted) - from journals.factories import PublicationFactory - - factory.RelatedFactory( - PublicationFactory, - "accepted_submission", - title=self.title, - author_list=self.author_list, - ) + grants = GrantFactory.create_batch(3) + self.grants.add(*grants) @factory.post_generation - def author_relations(self, create, extracted, **kwargs): + def funders_generic(self, create, extracted, **kwargs): if not create: return + if extracted: + self.funders_generic.add(*extracted) + + funders_generic = FunderFactory.create_batch(3) + self.funders_generic.add(*funders_generic) + + # Metadata + metadata = {} + metadata_xml = "" + metadata_DOAJ = {} + citedby = {} + number_of_citations = 0 + + @factory.lazy_attribute + def doi_label(self): + if self.pub_container: + return self.pub_container.doi_label + "." + str(self.paper_nr).rjust(3, "0") + + # Date fields + submission_date = factory.SelfAttribute("accepted_submission.submission_date") + acceptance_date = factory.SelfAttribute("accepted_submission.latest_activity") + publication_date = factory.SelfAttribute("accepted_submission.latest_activity") + latest_activity = factory.SelfAttribute("accepted_submission.latest_activity") + latest_citedby_update = factory.SelfAttribute("accepted_submission.latest_activity") + latest_metadata_update = factory.SelfAttribute( + "accepted_submission.latest_activity" + ) + + # @factory.post_generation + # def generate_publication(self, create, extracted, **kwargs): + # if create and extracted is not False: + # return + + # from journals.factories import PublicationFactory + + # factory.RelatedFactory( + # PublicationFactory, + # "accepted_submission", + # title=self.title, + # author_list=self.author_list, + # ) + + # @factory.post_generation + # def author_relations(self, create, extracted, **kwargs): + # if not create: + # return + + # # Append references + # for i in range(5): + # ReferenceFactory(publication=self) - # Append references - for i in range(5): - ReferenceFactory(publication=self) + # Copy author data from Submission + # for author in self.accepted_submission.authors.all(): + # self.authors.create(publication=self, profile=author) + # self.authors_claims.add(*self.accepted_submission.authors_claims.all()) + # self.authors_false_claims.add(*self.accepted_submission.authors_false_claims.all()) + + +class JournalPublicationFactory(BasePublicationFactory): + in_journal = factory.SubFactory(JournalFactory) + + +class VolumeIssuePublicationFactory(BasePublicationFactory): + in_issue = factory.SubFactory(VolumeIssueFactory) + in_journal = factory.SelfAttribute("in_issue.in_volume.in_journal") + + +class JournalIssuePublicationFactory(BasePublicationFactory): + in_issue = factory.SubFactory(JournalIssueFactory) + in_journal = factory.SelfAttribute("in_issue.in_journal") + + +class AutogeneratedFileContentTemplateFactory(factory.django.DjangoModelFactory): + class Meta: + model = AutogeneratedFileContentTemplate + + journal = factory.SubFactory(JournalFactory) + name = factory.Faker("word") + description = factory.Faker("sentence", nb_words=3) + content_template_string = factory.Faker("word") + + +class DepositFactory(factory.django.DjangoModelFactory): + class Meta: + model = Deposit - # Copy author data from Submission - # for author in self.accepted_submission.authors.all(): - # self.authors.create(publication=self, profile=author) - # self.authors_claims.add(*self.accepted_submission.authors_claims.all()) - # self.authors_false_claims.add(*self.accepted_submission.authors_false_claims.all()) + publication = factory.SubFactory(JournalPublicationFactory) + deposition_date = factory.SelfAttribute("publication.publication_date") + timestamp = factory.LazyAttribute( + lambda self: self.deposition_date.strftime("%Y%m%d%H%M%S") + ) + deposit_successful = True + response_text = "" + doi_batch_id = factory.Faker("word") + metadata_xml = "" + metadata_xml_file = factory.django.FileField() + response_text = "" + + +class DOAJDepositFactory(factory.django.DjangoModelFactory): + class Meta: + model = DOAJDeposit + + publication = factory.SubFactory(JournalPublicationFactory) + deposition_date = factory.SelfAttribute("publication.publication_date") + timestamp = factory.LazyAttribute( + lambda self: self.deposition_date.strftime("%Y%m%d%H%M%S") + ) + deposit_successful = True + metadata_DOAJ = {} + metadata_DOAJ_file = factory.django.FileField() + response_text = "" + + +class GenericDOIDepositFactory(factory.django.DjangoModelFactory): + class Meta: + model = GenericDOIDeposit + abstract = True + + deposition_date = LazyAwareDate("date_this_year") + timestamp = factory.LazyAttribute( + lambda self: self.deposition_date.strftime("%Y%m%d%H%M%S") + ) + deposit_successful = True + doi_batch_id = factory.Faker("word") + metadata_xml = "" + response = "" + + +class PublicationResourceFactory(factory.django.DjangoModelFactory): + class Meta: + model = PublicationResource + + _type = LazyRandEnum(PublicationResource.TYPE_CHOICES) + publication = factory.SubFactory(JournalPublicationFactory) + url = factory.Faker("uri") + comments = factory.Faker("sentence") + deprecated = False + + +class SubmissionTemplateFactory(factory.django.DjangoModelFactory): + class Meta: + model = SubmissionTemplate + + template_type = LazyRandEnum(SubmissionTemplate.TYPE_CHOICES) + template_file = factory.django.FileField() + journal = factory.SubFactory(JournalFactory) + date = LazyAwareDate("date_this_year") + instructions = factory.Faker("paragraph") + + +class PublicationUpdateFactory(factory.django.DjangoModelFactory): + class Meta: + model = PublicationUpdate + + publication = factory.SubFactory(JournalPublicationFactory) + number = factory.LazyAttribute(lambda self: self.publication.updates.count() + 1) + update_type = LazyRandEnum(PublicationUpdate.TYPE_CHOICES) + text = factory.Faker("paragraph") + publication_date = factory.LazyAttribute( + lambda self: fake.aware.date_between( + start_date=self.publication.publication_date, end_date="+1y" + ) + ) + doideposit_needs_updating = False + doi_label = factory.LazyAttribute( + lambda self: f"{self.publication.doi_label}.Upd.{self.number}" + ) diff --git a/scipost_django/journals/tests/test_factories.py b/scipost_django/journals/tests/test_factories.py new file mode 100644 index 0000000000000000000000000000000000000000..29088a64be244ef4db8d336169ef66019fefd043 --- /dev/null +++ b/scipost_django/journals/tests/test_factories.py @@ -0,0 +1,122 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + +from django.test import TestCase +from ..factories import ( + AutogeneratedFileContentTemplateFactory, + DOAJDepositFactory, + DepositFactory, + JournalIssueFactory, + JournalIssuePublicationFactory, + PublicationResourceFactory, + PublicationUpdateFactory, + SubmissionTemplateFactory, + VolumeIssuePublicationFactory, + JournalFactory, + JournalPublicationFactory, + ReferenceFactory, + VolumeFactory, + VolumeIssueFactory, +) + + +class TestJournalFactory(TestCase): + def test_can_create_journals(self): + journal = JournalFactory() + self.assertIsNotNone(journal) + + def test_default_journal_factory_has_college_specialties(self): + journal = JournalFactory() + college_specialties = journal.college.specialties.all() + journal_specialties = journal.specialties.all() + self.assertQuerysetEqual(college_specialties, journal_specialties) + + def test_can_create_scipost_phys(self): + scipost_phys = JournalFactory.SciPostPhysics() + self.assertEqual(scipost_phys.name, "SciPost Physics") + self.assertEqual(scipost_phys.doi_label, "SciPostPhys") + + +class TestReferenceFactory(TestCase): + def test_can_create_references(self): + reference = ReferenceFactory() + self.assertIsNotNone(reference) + + +class TestVolumeFactory(TestCase): + def test_can_create_volumes(self): + volume = VolumeFactory() + self.assertIsNotNone(volume) + + +class TestVolumeIssueFactory(TestCase): + def test_can_create_volume_issues(self): + volume_issue = VolumeIssueFactory() + self.assertIsNotNone(volume_issue) + + +class TestJournalIssueFactory(TestCase): + def test_can_create_journal_issues(self): + journal_issue = JournalIssueFactory() + self.assertIsNotNone(journal_issue) + + +class TestJournalPublicationFactory(TestCase): + def test_can_create_journal_publications(self): + journal_publication = JournalPublicationFactory() + self.assertIsNotNone(journal_publication) + + def test_can_create_scipostphys_publications(self): + publication = JournalPublicationFactory( + in_journal=JournalFactory.SciPostPhysics() + ) + self.assertIsNotNone(publication) + self.assertEqual(publication.in_journal.name, "SciPost Physics") + + +class TestVolumeIssuePublicationFactory(TestCase): + def test_can_create_volume_issue_publications(self): + volume_issue_publication = VolumeIssuePublicationFactory() + self.assertIsNotNone(volume_issue_publication) + + +class TestJournalIssuePublicationFactory(TestCase): + def test_can_create_journal_issue_publications(self): + journal_issue_publication = JournalIssuePublicationFactory() + self.assertIsNotNone(journal_issue_publication) + + +class TestAutogeneratedFileContentTemplateFactory(TestCase): + def test_can_create_autogen_file_content_templates(self): + autogen_file_content_template = AutogeneratedFileContentTemplateFactory() + self.assertIsNotNone(autogen_file_content_template) + + +class TestDepositFactory(TestCase): + def test_can_create_deposits(self): + deposit = DepositFactory() + self.assertIsNotNone(deposit) + + +class TestDOAJDepositFactory(TestCase): + def test_can_create_doaj_deposits(self): + doaj_deposit = DOAJDepositFactory() + self.assertIsNotNone(doaj_deposit) + + +class TestPublicationResourceFactory(TestCase): + def test_can_create_publication_resources(self): + publication_resource = PublicationResourceFactory() + self.assertIsNotNone(publication_resource) + + +class TestSubmissionTemplateFactory(TestCase): + def test_can_create_submission_templates(self): + submission_template = SubmissionTemplateFactory() + self.assertIsNotNone(submission_template) + + +class TestPublicationUpdateFactory(TestCase): + def test_can_create_publication_updates(self): + publication_update = PublicationUpdateFactory() + self.assertIsNotNone(publication_update)