datatracker/ietf/doc/factories.py

473 lines
17 KiB
Python

# Copyright The IETF Trust 2016-2020, All Rights Reserved
# -*- coding: utf-8 -*-
import debug # pyflakes:ignore
import factory
import factory.fuzzy
import datetime
from typing import Optional # pyflakes:ignore
from django.conf import settings
from ietf.doc.models import ( Document, DocEvent, NewRevisionDocEvent, DocAlias, State, DocumentAuthor,
StateDocEvent, BallotPositionDocEvent, BallotDocEvent, BallotType, IRSGBallotDocEvent, TelechatDocEvent,
DocumentActionHolder, BofreqEditorDocEvent, BofreqResponsibleDocEvent )
from ietf.group.models import Group
from ietf.person.factories import PersonFactory
from ietf.group.factories import RoleFactory
from ietf.utils.text import xslugify
def draft_name_generator(type_id,group,n):
return '%s-%s-%s-%s%d'%(
type_id,
'bogusperson',
group.acronym if group else 'netherwhere',
'musings',
n,
)
class BaseDocumentFactory(factory.django.DjangoModelFactory):
class Meta:
model = Document
title = factory.Faker('sentence',nb_words=5)
abstract = factory.Faker('paragraph', nb_sentences=5)
rev = '00'
std_level_id = None # type: Optional[str]
intended_std_level_id = None
time = datetime.datetime.now()
expires = factory.LazyAttribute(lambda o: o.time+datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE))
pages = factory.fuzzy.FuzzyInteger(2,400)
@factory.lazy_attribute_sequence
def name(self, n):
return draft_name_generator(self.type_id,self.group,n)
newrevisiondocevent = factory.RelatedFactory('ietf.doc.factories.NewRevisionDocEventFactory','doc')
@factory.post_generation
def other_aliases(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
alias = DocAliasFactory(name=obj.name)
alias.docs.add(obj)
if create and extracted:
for name in extracted:
alias = DocAliasFactory(name=name)
alias.docs.add(obj)
@factory.post_generation
def states(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
if create and extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if obj.type_id == 'draft':
if not obj.states.filter(type_id='draft-iesg').exists():
obj.set_state(State.objects.get(type_id='draft-iesg', slug='idexists'))
@factory.post_generation
def authors(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
if create and extracted:
order = 0
for person in extracted:
DocumentAuthor.objects.create(document=obj, person=person, email=person.email(), order=order)
order += 1
@factory.post_generation
def relations(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
if create and extracted:
for (rel_id, doc) in extracted:
if isinstance(doc, Document):
docalias = doc.docalias.first()
elif isinstance(doc, DocAlias):
docalias = doc
else:
continue
obj.relateddocument_set.create(relationship_id=rel_id, target=docalias)
@factory.post_generation
def create_revisions(obj, create, extracted, **kwargs): # pylint: disable=no-self-argument
"""Create additional revisions of the document
Argument should be an iterable of revisions. Remember that range() is exclusive on the end
index, so range(1, 10) stops at 9.
"""
if create and extracted:
for rev in extracted:
e = NewRevisionDocEventFactory(doc=obj, rev=f'{rev:02d}')
obj.rev = f'{rev:02d}'
obj.save_with_history([e])
@classmethod
def _after_postgeneration(cls, obj, create, results=None):
"""Save again the instance if creating and at least one hook ran."""
if create and results:
# Some post-generation hooks ran, and may have modified us.
obj._has_an_event_so_saving_is_allowed = True
obj.save()
#TODO remove this - rename BaseDocumentFactory to DocumentFactory
class DocumentFactory(BaseDocumentFactory):
type_id = 'draft'
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
class IndividualDraftFactory(BaseDocumentFactory):
type_id = 'draft'
group = factory.SubFactory('ietf.group.factories.GroupFactory',acronym='none')
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='active'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class IndividualRfcFactory(IndividualDraftFactory):
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
else:
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
class WgDraftFactory(BaseDocumentFactory):
type_id = 'draft'
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='wg')
stream_id = 'ietf'
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='active'))
obj.set_state(State.objects.get(type_id='draft-stream-ietf',slug='wg-doc'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class WgRfcFactory(WgDraftFactory):
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
std_level_id = 'ps'
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
obj.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
class RgDraftFactory(BaseDocumentFactory):
type_id = 'draft'
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='rg')
stream_id = 'irtf'
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='active'))
obj.set_state(State.objects.get(type_id='draft-stream-irtf',slug='active'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class RgRfcFactory(RgDraftFactory):
alias2 = factory.RelatedFactory('ietf.doc.factories.DocAliasFactory','document',name=factory.Sequence(lambda n: 'rfc%04d'%(n+1000)))
std_level_id = 'inf'
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
if not obj.get_state('draft-stream-irtf'):
obj.set_state(State.objects.get(type_id='draft-stream-irtf', slug='pub'))
if not obj.get_state('draft-iesg'):
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
else:
obj.set_state(State.objects.get(type_id='draft',slug='rfc'))
obj.set_state(State.objects.get(type_id='draft-stream-irtf', slug='pub'))
obj.set_state(State.objects.get(type_id='draft-iesg',slug='idexists'))
class CharterFactory(BaseDocumentFactory):
type_id = 'charter'
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='wg')
name = factory.LazyAttribute(lambda o: 'charter-ietf-%s'%o.group.acronym)
@factory.post_generation
def set_group_charter_document(obj, create, extracted, **kwargs):
if not create:
return
obj.group.charter = extracted or obj
obj.group.save()
class ConflictReviewFactory(BaseDocumentFactory):
type_id='conflrev'
@factory.post_generation
def review_of(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
obj.relateddocument_set.create(relationship_id='conflrev',target=extracted.docalias.first())
else:
obj.relateddocument_set.create(relationship_id='conflrev',target=DocumentFactory(type_id='draft',group=Group.objects.get(type_id='individ')).docalias.first())
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for state in extracted:
obj.set_state(state)
else:
obj.set_state(State.objects.get(type_id='conflrev',slug='iesgeval'))
# This is very skeletal. It is enough for the tests that use it now, but when it's needed, it will need to be improved with, at least, a group generator that backs the object with a review team.
class ReviewFactory(BaseDocumentFactory):
type_id = 'review'
name = factory.LazyAttribute(lambda o: 'review-doesnotexist-00-%s-%s'%(o.group.acronym,datetime.date.today().isoformat()))
group = factory.SubFactory('ietf.group.factories.GroupFactory',type_id='review')
class DocAliasFactory(factory.django.DjangoModelFactory):
class Meta:
model = DocAlias
@factory.post_generation
def document(self, create, extracted, **kwargs):
if create and extracted:
self.docs.add(extracted)
@factory.post_generation
def docs(self, create, extracted, **kwargs):
if create and extracted:
for doc in extracted:
if not doc in self.docs.all():
self.docs.add(doc)
class DocEventFactory(factory.django.DjangoModelFactory):
class Meta:
model = DocEvent
type = 'added_comment'
by = factory.SubFactory('ietf.person.factories.PersonFactory')
doc = factory.SubFactory(DocumentFactory)
desc = factory.Faker('sentence',nb_words=6)
@factory.lazy_attribute
def rev(self):
return self.doc.rev
class TelechatDocEventFactory(DocEventFactory):
class Meta:
model = TelechatDocEvent
telechat_date = datetime.datetime.today()+datetime.timedelta(days=14)
type = 'scheduled_for_telechat'
class NewRevisionDocEventFactory(DocEventFactory):
class Meta:
model = NewRevisionDocEvent
type = 'new_revision'
rev = '00'
@factory.lazy_attribute
def desc(self):
return 'New version available %s-%s'%(self.doc.name,self.rev)
class StateDocEventFactory(DocEventFactory):
class Meta:
model = StateDocEvent
type = 'changed_state'
state_type_id = 'draft-iesg'
@factory.post_generation
def state(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
(state_type_id, state_slug) = extracted
obj.state = State.objects.get(type_id=state_type_id,slug=state_slug)
else:
obj.state = State.objects.get(type_id='draft-iesg',slug='ad-eval')
obj.save()
# All of these Ballot* factories are extremely skeletal. Flesh them out as needed by tests.
class BallotTypeFactory(factory.django.DjangoModelFactory):
class Meta:
model = BallotType
django_get_or_create = ('slug','doc_type_id')
doc_type_id = 'draft'
slug = 'approve'
class BallotDocEventFactory(DocEventFactory):
class Meta:
model = BallotDocEvent
ballot_type = factory.SubFactory(BallotTypeFactory)
type = 'created_ballot'
class IRSGBallotDocEventFactory(BallotDocEventFactory):
class Meta:
model = IRSGBallotDocEvent
duedate = datetime.datetime.now() + datetime.timedelta(days=14)
ballot_type = factory.SubFactory(BallotTypeFactory, slug='irsg-approve')
class BallotPositionDocEventFactory(DocEventFactory):
class Meta:
model = BallotPositionDocEvent
type = 'changed_ballot_position'
# This isn't right - it needs to build a ballot for the same doc as this position
# For now, deal with this in test code by building BallotDocEvent and BallotPositionDocEvent
# separately and passing the same doc into thier factories.
ballot = factory.SubFactory(BallotDocEventFactory)
balloter = factory.SubFactory('ietf.person.factories.PersonFactory')
pos_id = 'discuss'
class DocumentActionHolderFactory(factory.django.DjangoModelFactory):
class Meta:
model = DocumentActionHolder
document = factory.SubFactory(WgDraftFactory)
person = factory.SubFactory('ietf.person.factories.PersonFactory')
class DocumentAuthorFactory(factory.django.DjangoModelFactory):
class Meta:
model = DocumentAuthor
document = factory.SubFactory(DocumentFactory)
person = factory.SubFactory('ietf.person.factories.PersonFactory')
email = factory.LazyAttribute(lambda obj: obj.person.email())
affiliation = factory.Faker('company')
country = factory.Faker('country')
order = factory.LazyAttribute(lambda o: o.document.documentauthor_set.count() + 1)
class WgDocumentAuthorFactory(DocumentAuthorFactory):
document = factory.SubFactory(WgDraftFactory)
class BofreqEditorDocEventFactory(DocEventFactory):
class Meta:
model = BofreqEditorDocEvent
type = "changed_editors"
doc = factory.SubFactory('ietf.doc.factories.BofreqFactory')
@factory.post_generation
def editors(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
obj.editors.set(extracted)
else:
obj.editors.set(PersonFactory.create_batch(3))
obj.desc = f'Changed editors to {", ".join(obj.editors.values_list("name",flat=True)) or "(None)"}'
class BofreqResponsibleDocEventFactory(DocEventFactory):
class Meta:
model = BofreqResponsibleDocEvent
type = "changed_responsible"
doc = factory.SubFactory('ietf.doc.factories.BofreqFactory')
@factory.post_generation
def responsible(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
obj.responsible.set(extracted)
else:
ad = RoleFactory(group__type_id='area',name_id='ad').person
obj.responsible.set([ad])
obj.desc = f'Changed responsible leadership to {", ".join(obj.responsible.values_list("name",flat=True)) or "(None)"}'
class BofreqFactory(BaseDocumentFactory):
type_id = 'bofreq'
title = factory.Faker('sentence')
name = factory.LazyAttribute(lambda o: 'bofreq-%s-%s'%(xslugify(o.requester_lastname), xslugify(o.title)))
bofreqeditordocevent = factory.RelatedFactory('ietf.doc.factories.BofreqEditorDocEventFactory','doc')
bofreqresponsibledocevent = factory.RelatedFactory('ietf.doc.factories.BofreqResponsibleDocEventFactory','doc')
class Params:
requester_lastname = factory.Faker('last_name')
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
else:
obj.set_state(State.objects.get(type_id='bofreq',slug='proposed'))
class ProceedingsMaterialDocFactory(BaseDocumentFactory):
type_id = 'procmaterials'
abstract = ''
expires = None
@factory.post_generation
def states(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for (state_type_id,state_slug) in extracted:
obj.set_state(State.objects.get(type_id=state_type_id,slug=state_slug))
else:
obj.set_state(State.objects.get(type_id='procmaterials', slug='active'))