diff --git a/ietf/idrfc/expire.py b/ietf/idrfc/expire.py index 884a91cc1..fc3a36e9f 100644 --- a/ietf/idrfc/expire.py +++ b/ietf/idrfc/expire.py @@ -4,14 +4,14 @@ from django.conf import settings from django.template.loader import render_to_string from django.db.models import Q -import datetime, os, shutil, glob, re +import datetime, os, shutil, glob, re, itertools from ietf.idtracker.models import InternetDraft, IDDates, IDStatus, IDState, DocumentComment, IDAuthor,WGChair from ietf.utils.mail import send_mail, send_mail_subj from ietf.idrfc.utils import log_state_changed, add_document_comment -from doc.models import Document, DocEvent, save_document_in_history -from name.models import IesgDocStateName, DocStateName, DocTagName -from person.models import Person, Email +from redesign.doc.models import Document, DocEvent, save_document_in_history, State +from redesign.name.models import DocTagName +from redesign.person.models import Person, Email INTERNET_DRAFT_DAYS_TO_EXPIRE = 185 @@ -36,7 +36,11 @@ def document_expires(doc): return None def expirable_documents(): - return Document.objects.filter(state="active").exclude(tags="rfc-rev").filter(Q(iesg_state=None) | Q(iesg_state__order__gte=42)) + d = Document.objects.filter(states__type="draft", states__slug="active").exclude(tags="rfc-rev") + # we need to get those that either don't have a state or have a + # state >= 42 (AD watching), unfortunately that doesn't appear to + # be possible to get to work directly in Django 1.1 + return itertools.chain(d.exclude(states__type="draft-iesg").distinct(), d.filter(states__type="draft-iesg", states__order__gte=42).distinct()) def get_soon_to_expire_ids(days): start_date = datetime.date.today() - datetime.timedelta(InternetDraft.DAYS_TO_EXPIRE - 1) @@ -104,7 +108,8 @@ def send_expire_warning_for_idREDESIGN(doc): if doc.group.type_id != "individ": cc = [e.formatted_email() for e in Email.objects.filter(role__group=doc.group, role__name="chair") if not e.address.startswith("unknown-email")] - state = doc.iesg_state.name if doc.iesg_state else "I-D Exists" + s = doc.get_state("draft-iesg") + state = s.name if s else "I-D Exists" frm = None request = None @@ -138,8 +143,9 @@ def send_expire_notice_for_idREDESIGN(doc): if not doc.ad: return - state = doc.iesg_state.name if doc.iesg_state else "I-D Exists" - + s = doc.get_state("draft-iesg") + state = s.name if s else "I-D Exists" + request = None to = doc.ad.formatted_email() send_mail(request, to, @@ -216,10 +222,10 @@ def expire_idREDESIGN(doc): save_document_in_history(doc) if doc.latest_event(type='started_iesg_process'): - dead_state = IesgDocStateName.objects.get(slug="dead") - if doc.iesg_state != dead_state: - prev = doc.iesg_state - doc.iesg_state = dead_state + dead_state = State.objects.get(type="draft-iesg", slug="dead") + prev = doc.get_state("draft-iesg") + if prev != dead_state: + doc.set_state(dead_state) log_state_changed(None, doc, system, prev) e = DocEvent(doc=doc, by=system) @@ -228,7 +234,7 @@ def expire_idREDESIGN(doc): e.save() doc.rev = new_revision # FIXME: incrementing the revision like this is messed up - doc.state = DocStateName.objects.get(slug="expired") + doc.set_state(State.objects.get(type="draft", slug="expired")) doc.time = datetime.datetime.now() doc.save() @@ -334,10 +340,10 @@ def clean_up_id_filesREDESIGN(): try: doc = Document.objects.get(name=filename, rev=revision) - if doc.state_id == "rfc": + if doc.get_state_slug() == "rfc": if ext != ".txt": move_file_to("unknown_ids") - elif doc.state_id in ("expired", "auth-rm", "repl", "ietf-rm"): + elif doc.get_state_slug() in ("expired", "repl", "auth-rm", "ietf-rm"): e = doc.latest_event(type__in=('expired_document', 'new_revision', "completed_resurrect")) expiration_date = e.time.date() if e and e.type == "expired_document" else None diff --git a/ietf/idrfc/idrfc_wrapper.py b/ietf/idrfc/idrfc_wrapper.py index ee7a39567..7479c3ace 100644 --- a/ietf/idrfc/idrfc_wrapper.py +++ b/ietf/idrfc/idrfc_wrapper.py @@ -121,11 +121,11 @@ class IdWrapper: def rfc_editor_state(self): if settings.USE_DB_REDESIGN_PROXY_CLASSES: - if self._draft.rfc_state: + s = self._draft.get_state("draft-rfceditor") + if s: # extract possible extra states tags = self._draft.tags.filter(slug__in=("iana-crd", "ref", "missref")) - s = [self._draft.rfc_state.name] + [t.slug.replace("-crd", "").upper() for t in tags] - return " ".join(s) + return " ".join([s.name] + [t.slug.replace("-crd", "").upper() for t in tags]) else: return None diff --git a/ietf/idrfc/lastcall.py b/ietf/idrfc/lastcall.py index 7b9723370..bcddb9e62 100644 --- a/ietf/idrfc/lastcall.py +++ b/ietf/idrfc/lastcall.py @@ -8,8 +8,7 @@ from ietf.idtracker.models import InternetDraft, DocumentComment, BallotInfo from ietf.idrfc.mails import * from ietf.idrfc.utils import * -from doc.models import Document, DocEvent, LastCallDocEvent, WriteupDocEvent, save_document_in_history -from name.models import IesgDocStateName +from doc.models import Document, DocEvent, LastCallDocEvent, WriteupDocEvent, save_document_in_history, State from person.models import Person def request_last_call(request, doc): @@ -47,7 +46,7 @@ def get_expired_last_calls(): def get_expired_last_callsREDESIGN(): today = datetime.date.today() - for d in Document.objects.filter(iesg_state="lc"): + for d in Document.objects.filter(states__type="draft-iesg", states__slug="lc"): e = d.latest_event(LastCallDocEvent, type="sent_last_call") if e and e.expires.date() <= today: yield d @@ -71,18 +70,18 @@ def expire_last_call(doc): email_last_call_expired(doc) def expire_last_callREDESIGN(doc): - state = IesgDocStateName.objects.get(slug="writeupw") + state = State.objects.get(type="draft-iesg", slug="writeupw") e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text") if e and "What does this protocol do and why" not in e.text: - # if it boiler-plate text has been removed, we assume the + # if boiler-plate text has been removed, we assume the # write-up has been written - state = IesgDocStateName.objects.get(slug="goaheadw") + state = State.objects.get(type="draft-iesg", slug="goaheadw") save_document_in_history(doc) - prev = doc.iesg_state - doc.iesg_state = state + prev = doc.get_state("draft-iesg") + doc.set_state(state) e = log_state_changed(None, doc, Person.objects.get(name="(System)"), prev) doc.time = e.time diff --git a/ietf/idrfc/mails.py b/ietf/idrfc/mails.py index e01b111f4..3a77ffa46 100644 --- a/ietf/idrfc/mails.py +++ b/ietf/idrfc/mails.py @@ -269,7 +269,7 @@ def generate_approval_mail_rfc_editor(request, doc): DO_NOT_PUBLISH_IESG_STATES = ("nopubadw", "nopubanw") def generate_approval_mailREDESIGN(request, doc): - if doc.iesg_state_id in DO_NOT_PUBLISH_IESG_STATES or doc.tags.filter(slug='via-rfc'): + if doc.get_state_slug("draft-iesg") in DO_NOT_PUBLISH_IESG_STATES or doc.tags.filter(slug='via-rfc'): mail = generate_approval_mail_rfc_editor(request, doc) else: mail = generate_approval_mail_approved(request, doc) @@ -320,7 +320,7 @@ def generate_approval_mail_approved(request, doc): else: contacts = "The IESG contact person is %s." % director.name - doc_type = "RFC" if doc.state_id == "rfc" else "Internet Draft" + doc_type = "RFC" if doc.get_state_slug() == "rfc" else "Internet Draft" return render_to_string("idrfc/approval_mail.txt", dict(doc=doc, @@ -338,8 +338,8 @@ def generate_approval_mail_approved(request, doc): def generate_approval_mail_rfc_editorREDESIGN(request, doc): full_status = full_intended_status(doc.intended_std_level.name) status = full_status.replace("a ", "").replace("an ", "") - disapproved = doc.iesg_state_id in DO_NOT_PUBLISH_IESG_STATES - doc_type = "RFC" if doc.state_id == "rfc" else "Internet Draft" + disapproved = doc.get_state_slug("draft-iesg") in DO_NOT_PUBLISH_IESG_STATES + doc_type = "RFC" if doc.get_state_slug() == "rfc" else "Internet Draft" return render_to_string("idrfc/approval_mail_rfc_editor.txt", dict(doc=doc, @@ -619,7 +619,7 @@ def email_last_call_expired(doc): cc="iesg-secretary@ietf.org") def email_last_call_expiredREDESIGN(doc): - text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.iesg_state.name + text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.get_state("draft-iesg").name send_mail(None, "iesg@ietf.org", diff --git a/ietf/idrfc/mirror_rfc_editor_queue.py b/ietf/idrfc/mirror_rfc_editor_queue.py index d63834b65..50399f0b8 100644 --- a/ietf/idrfc/mirror_rfc_editor_queue.py +++ b/ietf/idrfc/mirror_rfc_editor_queue.py @@ -197,8 +197,8 @@ import django.db.transaction def get_rfc_tag_mapping(): """Return dict with RFC Editor state name -> DocTagName""" - from name.models import DocTagName - from name.utils import name + from redesign.name.models import DocTagName + from redesign.name.utils import name return { 'IANA': name(DocTagName, 'iana-crd', 'IANA coordination', "RFC-Editor/IANA Registration Coordination"), @@ -207,22 +207,21 @@ def get_rfc_tag_mapping(): } def get_rfc_state_mapping(): - """Return dict with RFC Editor state name -> RfcDocStateName""" - from name.models import RfcDocStateName - from name.utils import name - + """Return dict with RFC Editor state name -> State""" + from redesign.doc.models import State, StateType + t = StateType.objects.get(slug="draft-rfceditor") return { - 'AUTH': name(RfcDocStateName, 'auth', 'AUTH', "Awaiting author action"), - 'AUTH48': name(RfcDocStateName, 'auth48', "AUTH48", "Awaiting final author approval"), - 'EDIT': name(RfcDocStateName, 'edit', 'EDIT', "Approved by the stream manager (e.g., IESG, IAB, IRSG, ISE), awaiting processing and publishing"), - 'IANA': name(RfcDocStateName, 'iana-crd', 'IANA', "RFC-Editor/IANA Registration Coordination"), - 'IESG': name(RfcDocStateName, 'iesg', 'IESG', "Holding for IESG action"), - 'ISR': name(RfcDocStateName, 'isr', 'ISR', "Independent Submission Review by the ISE "), - 'ISR-AUTH': name(RfcDocStateName, 'isr-auth', 'ISR-AUTH', "Independent Submission awaiting author update, or in discussion between author and ISE"), - 'REF': name(RfcDocStateName, 'ref', 'REF', "Holding for normative reference"), - 'RFC-EDITOR': name(RfcDocStateName, 'rfc-edit', 'RFC-EDITOR', "Awaiting final RFC Editor review before AUTH48"), - 'TO': name(RfcDocStateName, 'timeout', 'TO', "Time-out period during which the IESG reviews document for conflict/concurrence with other IETF working group work"), - 'MISSREF': name(RfcDocStateName, 'missref', 'MISSREF', "Awaiting missing normative reference"), + 'AUTH': State.objects.get_or_create(type=t, slug='auth', name='AUTH', desc="Awaiting author action")[0], + 'AUTH48': State.objects.get_or_create(type=t, slug='auth48', name="AUTH48", desc="Awaiting final author approval")[0], + 'EDIT': State.objects.get_or_create(type=t, slug='edit', name='EDIT', desc="Approved by the stream manager (e.g., IESG, IAB, IRSG, ISE), awaiting processing and publishing")[0], + 'IANA': State.objects.get_or_create(type=t, slug='iana-crd', name='IANA', desc="RFC-Editor/IANA Registration Coordination")[0], + 'IESG': State.objects.get_or_create(type=t, slug='iesg', name='IESG', desc="Holding for IESG action")[0], + 'ISR': State.objects.get_or_create(type=t, slug='isr', name='ISR', desc="Independent Submission Review by the ISE ")[0], + 'ISR-AUTH': State.objects.get_or_create(type=t, slug='isr-auth', name='ISR-AUTH', desc="Independent Submission awaiting author update, or in discussion between author and ISE")[0], + 'REF': State.objects.get_or_create(type=t, slug='ref', name='REF', desc="Holding for normative reference")[0], + 'RFC-EDITOR': State.objects.get_or_create(type=t, slug='rfc-edit', name='RFC-EDITOR', desc="Awaiting final RFC Editor review before AUTH48")[0], + 'TO': State.objects.get_or_create(type=t, slug='timeout', name='TO', desc="Time-out period during which the IESG reviews document for conflict/concurrence with other IETF working group work")[0], + 'MISSREF': State.objects.get_or_create(type=t, slug='missref', name='MISSREF', desc="Awaiting missing normative reference")[0], } @@ -237,10 +236,9 @@ def insert_into_databaseREDESIGN(drafts, refs): rfc_editor_tags = tags.values() log("removing old data...") - for d in Document.objects.exclude(rfc_state=None).filter(tags__in=rfc_editor_tags): + for d in Document.objects.filter(states__type="draft-rfceditor").distinct(): d.tags.remove(*rfc_editor_tags) - - Document.objects.exclude(rfc_state=None).update(rfc_state=None) + d.unset_state("draft-rfceditor") log("inserting new data...") @@ -254,8 +252,7 @@ def insert_into_databaseREDESIGN(drafts, refs): s = state.split(" ") if s: # first is state - d.rfc_state = states[s[0]] - d.save() + d.set_state(states[s[0]]) # remainding are tags for x in s[1:]: diff --git a/ietf/idrfc/mirror_rfc_index.py b/ietf/idrfc/mirror_rfc_index.py index 41a0be9d0..0f8cc62b7 100644 --- a/ietf/idrfc/mirror_rfc_index.py +++ b/ietf/idrfc/mirror_rfc_index.py @@ -178,11 +178,11 @@ import django.db.transaction @django.db.transaction.commit_on_success def insert_to_databaseREDESIGN(data): - from person.models import Person - from doc.models import Document, DocAlias, DocEvent, RelatedDocument - from group.models import Group - from name.models import DocTagName, DocRelationshipName - from name.utils import name + from redesign.person.models import Person + from redesign.doc.models import Document, DocAlias, DocEvent, RelatedDocument, State + from redesign.group.models import Group + from redesign.name.models import DocTagName, DocRelationshipName + from redesign.name.utils import name system = Person.objects.get(name="(System)") std_level_mapping = get_std_level_mapping() @@ -242,8 +242,8 @@ def insert_to_databaseREDESIGN(data): doc.std_level = std_level_mapping[current_status] changed = True - if doc.state_id != "rfc": - doc.state_id = "rfc" + if doc.get_state_slug() != "rfc": + doc.set_state(State.objects.filter(type="draft", slug="rfc")) changed = True if doc.stream != stream_mapping[stream]: diff --git a/ietf/idrfc/testsREDESIGN.py b/ietf/idrfc/testsREDESIGN.py index 8fb0633d9..806bae77d 100644 --- a/ietf/idrfc/testsREDESIGN.py +++ b/ietf/idrfc/testsREDESIGN.py @@ -62,14 +62,13 @@ class ChangeStateTestCase(django.test.TestCase): def test_change_state(self): draft = make_test_data() - draft.iesg_state = IesgDocStateName.objects.get(slug="ad-eval") - draft.save() - + draft.set_state(State.objects.get(type="draft-iesg", slug="ad-eval")) + url = urlreverse('doc_change_state', kwargs=dict(name=draft.name)) login_testing_unauthorized(self, "secretary", url) - first_state = draft.iesg_state - next_states = get_next_iesg_states(first_state) + first_state = draft.get_state("draft-iesg") + next_states = first_state.next_states # normal get r = self.client.get(url) @@ -82,23 +81,23 @@ class ChangeStateTestCase(django.test.TestCase): # faulty post - r = self.client.post(url, dict(state="foobarbaz")) + r = self.client.post(url, dict(state=State.objects.get(type="draft", slug="active").pk)) self.assertEquals(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(len(q('form ul.errorlist')) > 0) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state, first_state) + self.assertEquals(draft.get_state("draft-iesg"), first_state) # change state events_before = draft.docevent_set.count() mailbox_before = len(outbox) - r = self.client.post(url, dict(state="review-e")) + r = self.client.post(url, dict(state=State.objects.get(type="draft-iesg", slug="review-e").pk)) self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state_id, "review-e") + self.assertEquals(draft.get_state_slug("draft-iesg"), "review-e") self.assertEquals(draft.docevent_set.count(), events_before + 1) self.assertTrue("State changed" in draft.docevent_set.all()[0].desc) self.assertEquals(len(outbox), mailbox_before + 2) @@ -115,8 +114,7 @@ class ChangeStateTestCase(django.test.TestCase): def test_request_last_call(self): draft = make_test_data() - draft.iesg_state = IesgDocStateName.objects.get(slug="ad-eval") - draft.save() + draft.set_state(State.objects.get(type="draft-iesg", slug="ad-eval")) self.client.login(remote_user="secretary") url = urlreverse('doc_change_state', kwargs=dict(name=draft.name)) @@ -124,7 +122,7 @@ class ChangeStateTestCase(django.test.TestCase): mailbox_before = len(outbox) self.assertTrue(not draft.latest_event(type="changed_ballot_writeup_text")) - r = self.client.post(url, dict(state="lc-req")) + r = self.client.post(url, dict(state=State.objects.get(type="draft-iesg", slug="lc-req").pk)) self.assertContains(r, "Your request to issue the Last Call") # last call text @@ -189,7 +187,7 @@ class EditInfoTestCase(django.test.TestCase): status_date=str(date.today() + timedelta(2)), via_rfc_editor="1", ad=str(new_ad.pk), - create_in_state="pub-req", + create_in_state=State.objects.get(type="draft-iesg", slug="pub-req").pk, notify="test@example.com", note="New note", telechat_date="", @@ -214,7 +212,7 @@ class EditInfoTestCase(django.test.TestCase): data = dict(intended_std_level=str(draft.intended_std_level_id), status_date=str(date.today() + timedelta(2)), via_rfc_editor="1", - create_in_state="pub-req", + create_in_state=State.objects.get(type="draft-iesg", slug="pub-req").pk, ad=str(draft.ad_id), notify="test@example.com", note="", @@ -249,8 +247,8 @@ class EditInfoTestCase(django.test.TestCase): def test_start_iesg_process_on_draft(self): draft = make_test_data() draft.ad = None - draft.iesg_state = None draft.save() + draft.unset_state("draft-iesg") draft.docevent_set.all().delete() url = urlreverse('doc_edit_info', kwargs=dict(name=draft.name)) @@ -275,7 +273,7 @@ class EditInfoTestCase(django.test.TestCase): status_date=str(date.today() + timedelta(2)), via_rfc_editor="1", ad=ad.pk, - create_in_state="watching", + create_in_state=State.objects.get(type="draft-iesg", slug="watching").pk, notify="test@example.com", note="This is a note", telechat_date="", @@ -284,7 +282,7 @@ class EditInfoTestCase(django.test.TestCase): draft = Document.objects.get(name=draft.name) self.assertTrue(draft.tags.filter(slug="via-rfc")) - self.assertEquals(draft.iesg_state_id, "watching") + self.assertEquals(draft.get_state_slug("draft-iesg"), "watching") self.assertEquals(draft.ad, ad) self.assertEquals(draft.note, "This is a note") self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat")) @@ -299,8 +297,7 @@ class ResurrectTestCase(django.test.TestCase): def test_request_resurrect(self): draft = make_test_data() - draft.state_id = "expired" - draft.save() + draft.set_state(State.objects.get(type="draft", slug="expired")) url = urlreverse('doc_request_resurrect', kwargs=dict(name=draft.name)) @@ -331,8 +328,8 @@ class ResurrectTestCase(django.test.TestCase): def test_resurrect(self): draft = make_test_data() - draft.state_id = "expired" - draft.save() + draft.set_state(State.objects.get(type="draft", slug="expired")) + DocEvent.objects.create(doc=draft, type="requested_resurrect", by=Person.objects.get(name="Aread Irector")) @@ -357,7 +354,7 @@ class ResurrectTestCase(django.test.TestCase): draft = Document.objects.get(name=draft.name) self.assertEquals(draft.docevent_set.count(), events_before + 1) self.assertEquals(draft.latest_event().type, "completed_resurrect") - self.assertEquals(draft.state_id, "active") + self.assertEquals(draft.get_state_slug(), "active") self.assertEquals(len(outbox), mailbox_before + 1) class AddCommentTestCase(django.test.TestCase): @@ -515,9 +512,8 @@ class DeferBallotTestCase(django.test.TestCase): def test_defer_ballot(self): draft = make_test_data() - draft.iesg_state_id = "iesg-eva" - draft.save() - + draft.set_state(State.objects.get(type="draft-iesg", slug="iesg-eva")) + url = urlreverse('doc_defer_ballot', kwargs=dict(name=draft.name)) login_testing_unauthorized(self, "ad", url) @@ -532,7 +528,7 @@ class DeferBallotTestCase(django.test.TestCase): self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state_id, "defer") + self.assertEquals(draft.get_state_slug("draft-iesg"), "defer") self.assertEquals(len(outbox), mailbox_before + 2) self.assertTrue("State Update" in outbox[-2]['Subject']) @@ -541,9 +537,8 @@ class DeferBallotTestCase(django.test.TestCase): def test_undefer_ballot(self): draft = make_test_data() - draft.iesg_state_id = "defer" - draft.save() - + draft.set_state(State.objects.get(type="draft-iesg", slug="defer")) + url = urlreverse('doc_undefer_ballot', kwargs=dict(name=draft.name)) login_testing_unauthorized(self, "ad", url) @@ -556,7 +551,7 @@ class DeferBallotTestCase(django.test.TestCase): self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state_id, "iesg-eva") + self.assertEquals(draft.get_state_slug("draft-iesg"), "iesg-eva") class BallotWriteupsTestCase(django.test.TestCase): fixtures = ['names'] @@ -617,7 +612,7 @@ class BallotWriteupsTestCase(django.test.TestCase): last_call_text=draft.latest_event(WriteupDocEvent, type="changed_last_call_text").text, send_last_call_request="1")) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state_id, "lc-req") + self.assertEquals(draft.get_state_slug("draft-iesg"), "lc-req") self.assertEquals(len(outbox), mailbox_before + 3) self.assertTrue("Last Call" in outbox[-1]['Subject']) self.assertTrue(draft.name in outbox[-1]['Subject']) @@ -727,8 +722,7 @@ class BallotWriteupsTestCase(django.test.TestCase): self.assertTrue("Subject: Protocol Action" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text) # test regenerate when it's a disapprove - draft.iesg_state_id = "nopubadw" - draft.save() + draft.set_state(State.objects.get(type="draft-iesg", slug="nopubadw")) r = self.client.post(url, dict(regenerate_approval_text="1")) self.assertEquals(r.status_code, 200) @@ -740,8 +734,8 @@ class ApproveBallotTestCase(django.test.TestCase): def test_approve_ballot(self): draft = make_test_data() - draft.iesg_state_id = "iesg-eva" # make sure it's approvable - draft.save() + draft.set_state(State.objects.get(type="draft-iesg", slug="iesg-eva")) # make sure it's approvable + url = urlreverse('doc_approve_ballot', kwargs=dict(name=draft.name)) login_testing_unauthorized(self, "secretary", url) @@ -759,7 +753,7 @@ class ApproveBallotTestCase(django.test.TestCase): self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state_id, "ann") + self.assertEquals(draft.get_state_slug("draft-iesg"), "ann") self.assertEquals(len(outbox), mailbox_before + 4) self.assertTrue("Protocol Action" in outbox[-2]['Subject']) # the IANA copy @@ -767,8 +761,7 @@ class ApproveBallotTestCase(django.test.TestCase): def test_disapprove_ballot(self): draft = make_test_data() - draft.iesg_state_id = "nopubadw" - draft.save() + draft.set_state(State.objects.get(type="draft-iesg", slug="nopubadw")) url = urlreverse('doc_approve_ballot', kwargs=dict(name=draft.name)) login_testing_unauthorized(self, "secretary", url) @@ -780,7 +773,7 @@ class ApproveBallotTestCase(django.test.TestCase): self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state_id, "dead") + self.assertEquals(draft.get_state_slug("draft-iesg"), "dead") self.assertEquals(len(outbox), mailbox_before + 3) self.assertTrue("NOT be published" in str(outbox[-1])) @@ -789,9 +782,8 @@ class MakeLastCallTestCase(django.test.TestCase): def test_make_last_call(self): draft = make_test_data() - draft.iesg_state_id = "lc-req" - draft.save() - + draft.set_state(State.objects.get(type="draft-iesg", slug="lc-req")) + url = urlreverse('doc_make_last_call', kwargs=dict(name=draft.name)) login_testing_unauthorized(self, "secretary", url) @@ -813,7 +805,7 @@ class MakeLastCallTestCase(django.test.TestCase): self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state.slug, "lc") + self.assertEquals(draft.get_state_slug("draft-iesg"), "lc") self.assertEquals(draft.latest_event(LastCallDocEvent, "sent_last_call").expires.strftime("%Y-%m-%d"), expire_date) self.assertEquals(len(outbox), mailbox_before + 4) @@ -866,8 +858,7 @@ class ExpireIDsTestCase(django.test.TestCase): self.assertEquals(len(list(get_soon_to_expire_ids(14))), 0) # hack into expirable state - draft.iesg_state = None - draft.save() + draft.unset_state("draft-iesg") NewRevisionDocEvent.objects.create( type="new_revision", @@ -897,9 +888,8 @@ class ExpireIDsTestCase(django.test.TestCase): self.assertEquals(len(list(get_expired_ids())), 0) # hack into expirable state - draft.iesg_state = None - draft.save() - + draft.unset_state("draft-iesg") + NewRevisionDocEvent.objects.create( type="new_revision", by=Person.objects.get(name="Aread Irector"), @@ -911,9 +901,8 @@ class ExpireIDsTestCase(django.test.TestCase): self.assertEquals(len(list(get_expired_ids())), 1) - draft.iesg_state = IesgDocStateName.objects.get(slug="watching") - draft.save() - + draft.set_state(State.objects.get(type="draft-iesg", slug="watching")) + self.assertEquals(len(list(get_expired_ids())), 1) # test notice @@ -933,9 +922,9 @@ class ExpireIDsTestCase(django.test.TestCase): expire_id(draft) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.state_id, "expired") + self.assertEquals(draft.get_state_slug(), "expired") self.assertEquals(int(draft.rev), int(revision_before) + 1) - self.assertEquals(draft.iesg_state_id, "dead") + self.assertEquals(draft.get_state_slug("draft-iesg"), "dead") self.assertTrue(draft.latest_event(type="expired_document")) self.assertTrue(not os.path.exists(os.path.join(self.id_dir, txt))) self.assertTrue(os.path.exists(os.path.join(self.archive_dir, txt))) @@ -968,7 +957,7 @@ class ExpireIDsTestCase(django.test.TestCase): # RFC draft - draft.state = DocStateName.objects.get(slug="rfc") + draft.set_state(State.objects.get(type="draft", slug="rfc")) draft.save() txt = "%s-%s.txt" % (draft.name, draft.rev) @@ -986,7 +975,7 @@ class ExpireIDsTestCase(django.test.TestCase): # expire draft - draft.state = DocStateName.objects.get(slug="expired") + draft.set_state(State.objects.get(type="draft", slug="expired")) draft.save() e = DocEvent() @@ -1028,11 +1017,10 @@ class ExpireLastCallTestCase(django.test.TestCase): def test_expire_last_call(self): from ietf.idrfc.lastcall import get_expired_last_calls, expire_last_call - # check that non-expirable drafts aren't expired + # check that non-expirable drafts aren't expired draft = make_test_data() - draft.iesg_state_id = "lc" - draft.save() + draft.set_state(State.objects.get(type="draft-iesg", slug="lc")) secretary = Person.objects.get(name="Sec Retary") @@ -1067,7 +1055,7 @@ class ExpireLastCallTestCase(django.test.TestCase): expire_last_call(drafts[0]) draft = Document.objects.get(name=draft.name) - self.assertEquals(draft.iesg_state.slug, "writeupw") + self.assertEquals(draft.get_state_slug("draft-iesg"), "writeupw") self.assertEquals(draft.docevent_set.count(), events_before + 1) self.assertEquals(len(outbox), mailbox_before + 1) self.assertTrue("Last Call Expired" in outbox[-1]["Subject"]) diff --git a/ietf/idrfc/utils.py b/ietf/idrfc/utils.py index c19629081..e2b699810 100644 --- a/ietf/idrfc/utils.py +++ b/ietf/idrfc/utils.py @@ -65,18 +65,20 @@ def log_state_changed(request, doc, by, email_watch_list=True, note=''): def log_state_changedREDESIGN(request, doc, by, prev_iesg_state, note=''): from doc.models import DocEvent + state = doc.get_state("draft-iesg") + e = DocEvent(doc=doc, by=by) e.type = "changed_document" e.desc = u"State changed to %s from %s" % ( - doc.iesg_state.name, - prev_iesg_state.name if prev_iesg_state else "None") + state.name, + prev_iesg_state.name if prev_iesg_state else "I-D Exists") if note: e.desc += "
%s" % note - if doc.iesg_state_id == "lc": + if state.slug == "lc": writeup = doc.latest_event(WriteupDocEvent, type="changed_last_call_text") - if writeup: + if writeup and writeup.text: e.desc += "

The following Last Call Announcement was sent out:

" e.desc += writeup.text.replace("\n", "

") diff --git a/ietf/idrfc/views_ballot.py b/ietf/idrfc/views_ballot.py index 3ca0dee83..205ad3776 100644 --- a/ietf/idrfc/views_ballot.py +++ b/ietf/idrfc/views_ballot.py @@ -25,8 +25,8 @@ from ietf.idrfc.utils import * from ietf.idrfc.lastcall import request_last_call from ietf.idrfc.idrfc_wrapper import BallotWrapper -from doc.models import Document, DocEvent, BallotPositionDocEvent, LastCallDocEvent, save_document_in_history -from name.models import BallotPositionName, IesgDocStateName +from redesign.doc.models import * +from redesign.name.models import BallotPositionName BALLOT_CHOICES = (("yes", "Yes"), @@ -227,7 +227,7 @@ def edit_positionREDESIGN(request, name): """Vote and edit discuss and comment on Internet Draft as Area Director.""" doc = get_object_or_404(Document, docalias__name=name) started_process = doc.latest_event(type="started_iesg_process") - if not doc.iesg_state or not started_process: + if not doc.get_state("draft-iesg") or not started_process: raise Http404() ad = login = request.user.get_profile() @@ -337,7 +337,7 @@ def edit_positionREDESIGN(request, name): form = EditPositionForm(initial=initial) ballot_deferred = None - if doc.iesg_state_id == "defer": + if doc.get_state_slug("draft-iesg") == "defer": ballot_deferred = doc.latest_event(type="changed_document", desc__startswith="State changed to IESG Evaluation - Defer") return render_to_response('idrfc/edit_positionREDESIGN.html', @@ -543,7 +543,7 @@ def defer_ballot(request, name): def defer_ballotREDESIGN(request, name): """Signal post-pone of Internet Draft ballot, notifying relevant parties.""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.iesg_state: + if not doc.get_state("draft-iesg"): raise Http404() login = request.user.get_profile() @@ -552,8 +552,8 @@ def defer_ballotREDESIGN(request, name): if request.method == 'POST': save_document_in_history(doc) - prev = doc.iesg_state - doc.iesg_state = IesgDocStateName.objects.get(slug='defer') + prev = doc.get_state("draft-iesg") + doc.set_state(State.objects.get(type="draft-iesg", slug='defer')) e = log_state_changed(request, doc, login, prev) doc.time = e.time @@ -608,7 +608,7 @@ def undefer_ballot(request, name): def undefer_ballotREDESIGN(request, name): """Delete deferral of Internet Draft ballot.""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.iesg_state: + if not doc.get_state("draft-iesg"): raise Http404() login = request.user.get_profile() @@ -617,8 +617,8 @@ def undefer_ballotREDESIGN(request, name): if request.method == 'POST': save_document_in_history(doc) - prev = doc.iesg_state - doc.iesg_state = IesgDocStateName.objects.get(slug='iesg-eva') + prev = doc.get_state("draft-iesg") + doc.set_state(State.objects.get(type="draft-iesg", slug='iesg-eva')) e = log_state_changed(request, doc, login, prev) doc.time = e.time @@ -748,7 +748,7 @@ class LastCallTextFormREDESIGN(forms.Form): def lastcalltextREDESIGN(request, name): """Editing of the last call text""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.iesg_state: + if not doc.get_state("draft-iesg"): raise Http404() login = request.user.get_profile() @@ -775,8 +775,8 @@ def lastcalltextREDESIGN(request, name): if "send_last_call_request" in request.POST: save_document_in_history(doc) - prev = doc.iesg_state - doc.iesg_state = IesgDocStateName.objects.get(slug='lc-req') + prev = doc.get_state("draft-iesg") + doc.set_state(State.objects.get(type="draft-iesg", slug='lc-req')) e = log_state_changed(request, doc, login, prev) doc.time = e.time @@ -797,10 +797,11 @@ def lastcalltextREDESIGN(request, name): # make sure form has the updated text form = LastCallTextForm(initial=dict(last_call_text=e.text)) - - can_request_last_call = doc.iesg_state.order < 27 - can_make_last_call = doc.iesg_state.order < 20 - can_announce = doc.iesg_state.order > 19 + + s = doc.get_state("draft-iesg") + can_request_last_call = s.order < 27 + can_make_last_call = s.order < 20 + can_announce = s.order > 19 need_intended_status = "" if not doc.intended_std_level: @@ -1039,7 +1040,7 @@ class ApprovalTextFormREDESIGN(forms.Form): def ballot_approvaltextREDESIGN(request, name): """Editing of approval text""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.iesg_state: + if not doc.get_state("draft-iesg"): raise Http404() login = request.user.get_profile() @@ -1069,7 +1070,7 @@ def ballot_approvaltextREDESIGN(request, name): # make sure form has the updated text form = ApprovalTextForm(initial=dict(approval_text=existing.text)) - can_announce = doc.iesg_state.order > 19 + can_announce = doc.get_state("draft-iesg").order > 19 need_intended_status = "" if not doc.intended_std_level: need_intended_status = doc.file_tag() @@ -1162,7 +1163,7 @@ def approve_ballot(request, name): def approve_ballotREDESIGN(request, name): """Approve ballot, sending out announcement, changing state.""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.iesg_state: + if not doc.get_state("draft-iesg"): raise Http404() login = request.user.get_profile() @@ -1188,15 +1189,15 @@ def approve_ballotREDESIGN(request, name): if request.method == 'POST': if action == "do_not_publish": - new_state = IesgDocStateName.objects.get(slug="dead") + new_state = State.objects.get(type="draft-iesg", slug="dead") else: - new_state = IesgDocStateName.objects.get(slug="ann") + new_state = State.objects.get(type="draft-iesg", slug="ann") # fixup document save_document_in_history(doc) - prev = doc.iesg_state - doc.iesg_state = new_state + prev = doc.get_state("draft-iesg") + doc.set_state(new_state) e = DocEvent(doc=doc, by=login) if action == "do_not_publish": @@ -1208,7 +1209,7 @@ def approve_ballotREDESIGN(request, name): e.save() - change_description = e.desc + " and state has been changed to %s" % doc.iesg_state.name + change_description = e.desc + " and state has been changed to %s" % doc.get_state("draft-iesg").name e = log_state_changed(request, doc, login, prev) @@ -1296,7 +1297,7 @@ def make_last_call(request, name): def make_last_callREDESIGN(request, name): """Make last call for Internet Draft, sending out announcement.""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.iesg_state: + if not doc.get_state("draft-iesg"): raise Http404() login = request.user.get_profile() @@ -1314,14 +1315,14 @@ def make_last_callREDESIGN(request, name): save_document_in_history(doc) - prev = doc.iesg_state - doc.iesg_state = IesgDocStateName.objects.get(slug='lc') + prev = doc.get_state("draft-iesg") + doc.set_state(State.objects.get(type="draft-iesg", slug='lc')) e = log_state_changed(request, doc, login, prev) doc.time = e.time doc.save() - change_description = "Last call has been made for %s and state has been changed to %s" % (doc.name, doc.iesg_state.name) + change_description = "Last call has been made for %s and state has been changed to %s" % (doc.name, doc.get_state("draft-iesg").name) email_state_changed(request, doc, change_description) email_owner(request, doc, doc.ad, login, change_description) diff --git a/ietf/idrfc/views_edit.py b/ietf/idrfc/views_edit.py index 363dba609..e2cdf6793 100644 --- a/ietf/idrfc/views_edit.py +++ b/ietf/idrfc/views_edit.py @@ -23,9 +23,9 @@ from ietf.idrfc.mails import * from ietf.idrfc.utils import * from ietf.idrfc.lastcall import request_last_call -from doc.models import Document, DocEvent, StatusDateDocEvent, TelechatDocEvent, save_document_in_history, DocHistory -from name.models import IesgDocStateName, IntendedStdLevelName, DocTagName, get_next_iesg_states, DocStateName -from person.models import Person, Email +from redesign.doc.models import * +from redesign.name.models import IntendedStdLevelName, DocTagName +from redesign.person.models import Person, Email class ChangeStateForm(forms.Form): state = forms.ModelChoiceField(IDState.objects.all(), empty_label=None, required=True) @@ -85,7 +85,7 @@ def change_state(request, name): context_instance=RequestContext(request)) class ChangeStateFormREDESIGN(forms.Form): - state = forms.ModelChoiceField(IesgDocStateName.objects.all(), empty_label=None, required=True) + state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg"), empty_label=None, required=True) # FIXME: no tags yet #substate = forms.ModelChoiceField(IDSubState.objects.all(), required=False) comment = forms.CharField(widget=forms.Textarea, required=False) @@ -95,7 +95,7 @@ def change_stateREDESIGN(request, name): """Change state of Internet Draft, notifying parties as necessary and logging the change as a comment.""" doc = get_object_or_404(Document, docalias__name=name) - if (not doc.latest_event(type="started_iesg_process")) or doc.state_id == "expired": + if (not doc.latest_event(type="started_iesg_process")) or doc.get_state_slug() == "expired": raise Http404() login = request.user.get_profile() @@ -105,11 +105,11 @@ def change_stateREDESIGN(request, name): if form.is_valid(): state = form.cleaned_data['state'] comment = form.cleaned_data['comment'] - if state != doc.iesg_state: + prev = doc.get_state("draft-iesg") + if state != prev: save_document_in_history(doc) - prev = doc.iesg_state - doc.iesg_state = state + doc.set_state(state) e = log_state_changed(request, doc, login, prev, comment) @@ -119,7 +119,7 @@ def change_stateREDESIGN(request, name): email_state_changed(request, doc, e.desc) email_owner(request, doc, doc.ad, login, e.desc) - if doc.iesg_state_id == "lc-req": + if state.slug == "lc-req": request_last_call(request, doc) return render_to_response('idrfc/last_call_requested.html', @@ -130,14 +130,16 @@ def change_stateREDESIGN(request, name): return HttpResponseRedirect(doc.get_absolute_url()) else: - form = ChangeStateForm(initial=dict(state=doc.iesg_state_id)) + state = doc.get_state("draft-iesg") + form = ChangeStateForm(initial=dict(state=state.pk if state else None)) - next_states = get_next_iesg_states(doc.iesg_state) + state = doc.get_state("draft-iesg") + next_states = state.next_states.all() if state else None prev_state = None - - hists = DocHistory.objects.filter(doc=doc).exclude(iesg_state=doc.iesg_state).order_by("-time")[:1] + + hists = doc.history_set.exclude(states=doc.get_state("draft-iesg")).order_by('-time')[:1] if hists: - prev_state = hists[0].iesg_state + prev_state = hists[0].get_state("draft-iesg") return render_to_response('idrfc/change_stateREDESIGN.html', dict(form=form, @@ -383,7 +385,7 @@ class EditInfoFormREDESIGN(forms.Form): status_date = forms.DateField(required=False, help_text="Format is YYYY-MM-DD") via_rfc_editor = forms.BooleanField(required=False, label="Via IRTF or RFC Editor") ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'), label="Responsible AD", empty_label=None, required=True) - create_in_state = forms.ModelChoiceField(IesgDocStateName.objects.filter(slug__in=("pub-req", "watching")), empty_label=None, required=True) + create_in_state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg", slug__in=("pub-req", "watching")), empty_label=None, required=True) notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False) note = forms.CharField(widget=forms.Textarea, label="IESG note", required=False) telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False) @@ -447,15 +449,14 @@ def edit_infoREDESIGN(request, name): """Edit various Internet Draft attributes, notifying parties as necessary and logging changes as document events.""" doc = get_object_or_404(Document, docalias__name=name) - if doc.state_id == "expired": + if doc.get_state_slug() == "expired": raise Http404() login = request.user.get_profile() new_document = False - if not doc.iesg_state: # FIXME: should probably receive "new document" as argument to view instead of this + if not doc.get_state("draft-iesg"): # FIXME: should probably receive "new document" as argument to view instead of this new_document = True - doc.iesg_state = IesgDocStateName.objects.get(slug="pub-req") doc.notify = get_initial_notify(doc) e = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat") @@ -471,11 +472,12 @@ def edit_infoREDESIGN(request, name): r = form.cleaned_data if new_document: + doc.set_state(r['create_in_state']) + # fix so Django doesn't barf in the diff below because these # fields can't be NULL doc.ad = r['ad'] - doc.iesg_state = r['create_in_state'] - + replaces = Document.objects.filter(docalias__relateddocument__source=doc, docalias__relateddocument__relationship="replaces") if replaces: # this should perhaps be somewhere else, e.g. the @@ -491,7 +493,7 @@ def edit_infoREDESIGN(request, name): e.type = "started_iesg_process" e.by = login e.doc = doc - e.desc = "IESG process started in state %s" % doc.iesg_state.name + e.desc = "IESG process started in state %s" % doc.get_state("draft-iesg").name e.save() orig_ad = doc.ad @@ -619,7 +621,7 @@ def request_resurrect(request, name): def request_resurrectREDESIGN(request, name): """Request resurrect of expired Internet Draft.""" doc = get_object_or_404(Document, docalias__name=name) - if doc.state_id != "expired": + if doc.get_state_slug() != "expired": raise Http404() login = request.user.get_profile() @@ -674,7 +676,7 @@ def resurrect(request, name): def resurrectREDESIGN(request, name): """Resurrect expired Internet Draft.""" doc = get_object_or_404(Document, docalias__name=name) - if doc.state_id != "expired": + if doc.get_state_slug() != "expired": raise Http404() login = request.user.get_profile() @@ -691,7 +693,7 @@ def resurrectREDESIGN(request, name): e.desc = "Resurrection was completed" e.save() - doc.state = DocStateName.objects.get(slug="active") + doc.set_state(State.objects.get(type="draft", slug="active")) doc.time = datetime.datetime.now() doc.save() return HttpResponseRedirect(doc.get_absolute_url()) @@ -738,7 +740,7 @@ def add_comment(request, name): def add_commentREDESIGN(request, name): """Add comment to Internet Draft.""" doc = get_object_or_404(Document, docalias__name=name) - if not doc.iesg_state: + if not doc.get_state("draft-iesg"): raise Http404() login = request.user.get_profile() diff --git a/ietf/idrfc/views_search.py b/ietf/idrfc/views_search.py index 05cdab68a..6f6502b75 100644 --- a/ietf/idrfc/views_search.py +++ b/ietf/idrfc/views_search.py @@ -290,7 +290,7 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: addInputEvents(area.widget) ad = forms.ChoiceField(choices=(), required=False) addInputEvents(ad.widget) - state = forms.ModelChoiceField(IesgDocStateName.objects.all(), empty_label="any state", required=False) + state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg"), empty_label="any state", required=False) addInputEvents(state.widget) subState = forms.ChoiceField(choices=(), required=False) addInputEvents(subState.widget) @@ -360,18 +360,15 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: Q(title__icontains=query["name"])).distinct() # rfc/active/old check buttons - allowed = [] - disallowed = [] + allowed_states = [] + if query["rfcs"]: + allowed_states.append("rfc") + if query["activeDrafts"]: + allowed_states.append("active") + if query["oldDrafts"]: + allowed_states.extend(['repl', 'expired', 'auth-rm', 'ietf-rm']) - def add(allow, states): - l = allowed if allow else disallowed - l.extend(states) - - add(query["rfcs"], ['rfc']) - add(query["activeDrafts"], ['active']) - add(query["oldDrafts"], ['repl', 'expired', 'auth-rm', 'ietf-rm']) - - docs = docs.filter(state__in=allowed).exclude(state__in=disallowed) + docs = docs.filter(states__type="draft", states__slug__in=allowed_states) # radio choices by = query["by"] @@ -388,13 +385,13 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: docs = docs.filter(ad=query["ad"]) elif by == "state": if query["state"]: - docs = docs.filter(iesg_state=query["state"]) + docs = docs.filter(states=query["state"]) if query["subState"]: docs = docs.filter(tags=query["subState"]) # evaluate and fill in values with aggregate queries to avoid # too many individual queries - results = list(docs.select_related("state", "iesg_state", "ad", "ad__person", "std_level", "intended_std_level", "group")[:MAX]) + results = list(docs.select_related("states", "ad", "ad__person", "std_level", "intended_std_level", "group")[:MAX]) rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[r.pk for r in results]).values_list("document_id", "name")) # canonical name @@ -452,7 +449,7 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: if rfc_num != None: res.append(2) - elif d.state_id == "active": + elif d.get_state_slug() == "active": res.append(1) else: res.append(3) @@ -465,15 +462,15 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: if rfc_num != None: res.append(rfc_num) else: - res.append(d.state) + res.append(d.get_state().order) elif sort_by == "ipr": res.append(d.name) elif sort_by == "ad": if rfc_num != None: res.append(rfc_num) - elif d.state_id == "active": - if d.iesg_state: - res.append(d.iesg_state.order) + elif d.get_state_slug() == "active": + if d.get_state("draft-iesg"): + res.append(get_state("draft-iesg").order) else: res.append(0) else: @@ -599,7 +596,7 @@ def by_ad(request, name): @cache_page(15*60) # 15 minutes def all(request): if settings.USE_DB_REDESIGN_PROXY_CLASSES: - active = (dict(filename=n) for n in InternetDraft.objects.filter(state="active").order_by("name").values_list('name', flat=True)) + active = (dict(filename=n) for n in InternetDraft.objects.filter(states__type="draft", states__slug="active").order_by("name").values_list('name', flat=True)) rfc1 = (dict(filename=d, rfc_number=int(n[3:])) for d, n in DocAlias.objects.filter(document__state="rfc", name__startswith="rfc").exclude(document__name__startswith="rfc").order_by("document__name").values_list('document__name','name').distinct()) rfc2 = (dict(rfc_number=r, draft=None) for r in sorted(int(n[3:]) for n in Document.objects.filter(type="draft", name__startswith="rfc").values_list('name', flat=True))) dead = InternetDraft.objects.exclude(state__in=("active", "rfc")).select_related("state").order_by("name") diff --git a/ietf/idtracker/feeds.py b/ietf/idtracker/feeds.py index 00bf8fff5..4b4a5f678 100644 --- a/ietf/idtracker/feeds.py +++ b/ietf/idtracker/feeds.py @@ -59,7 +59,7 @@ class InLastCall(Feed): def items(self): if settings.USE_DB_REDESIGN_PROXY_CLASSES: - ret = list(IDInternal.objects.filter(iesg_state='lc')) + ret = list(IDInternal.objects.filter(states__type="draft-iesg", states__slug="lc")) else: ret = list(IDInternal.objects.filter(primary_flag=1).filter(cur_state__state='In Last Call')) ret.sort(key=lambda item: (item.document().lc_expiration_date or datetime.date.today())) diff --git a/ietf/idtracker/models.py b/ietf/idtracker/models.py index 607c0674c..611881a57 100644 --- a/ietf/idtracker/models.py +++ b/ietf/idtracker/models.py @@ -1152,8 +1152,8 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES: IESGLoginOld = IESGLogin IETFWGOld = IETFWG IRTFOld = IRTF - from redesign.doc.proxy import InternetDraft, IDInternal, BallotInfo, Rfc - from redesign.name.proxy import IDState, IDSubState + from redesign.doc.proxy import InternetDraft, IDInternal, BallotInfo, Rfc, IDState + from redesign.name.proxy import IDSubState from redesign.group.proxy import Area, Acronym, IETFWG, IRTF from redesign.person.proxy import IESGLogin diff --git a/ietf/idtracker/views.py b/ietf/idtracker/views.py index d525274d8..a8dcbe562 100644 --- a/ietf/idtracker/views.py +++ b/ietf/idtracker/views.py @@ -29,7 +29,7 @@ IESG to do anything with the document. def status(request): if settings.USE_DB_REDESIGN_PROXY_CLASSES: - drafts = list(IDInternal.objects.exclude(iesg_state=None).exclude(iesg_state__in=('pub', 'dead', 'watching', 'rfcqueue')).order_by('iesg_state__order')) + drafts = list(IDInternal.objects.filter(states__type="draft-iesg").exclude(states__type="draft-iesg", states__slug__in=('pub', 'dead', 'watching', 'rfcqueue')).distinct().order_by('states__order')) drafts.sort(key=lambda d: (d.cur_state_id, d.status_date or datetime.date.min, d.b_sent_date or datetime.date.min)) # sadly we can't use the generic view because it only works with a queryset... return render_to_response('idtracker/status_of_items.html', dict(object_list=drafts, title="IESG Status of Items"), context_instance=RequestContext(request)) @@ -39,7 +39,7 @@ def status(request): def last_call(request): if settings.USE_DB_REDESIGN_PROXY_CLASSES: - drafts = list(IDInternal.objects.exclude(iesg_state=None).filter(iesg_state__in=('lc', 'writeupw', 'goaheadw')).order_by('iesg_state__order')) + drafts = list(IDInternal.objects.filter(states__type="draft-iesg", states__slug__in=('lc', 'writeupw', 'goaheadw')).distinct().order_by('states__order')) drafts.sort(key=lambda d: (d.cur_state_id, d.status_date or datetime.date.min, d.b_sent_date or datetime.date.min)) # sadly we can't use the generic view because it only works with a queryset... return render_to_response('idtracker/status_of_items.html', dict(object_list=drafts, title="Documents in Last Call", lastcall=1), context_instance=RequestContext(request)) diff --git a/ietf/iesg/views.py b/ietf/iesg/views.py index 1867a8bf1..fee0d080f 100644 --- a/ietf/iesg/views.py +++ b/ietf/iesg/views.py @@ -483,7 +483,7 @@ def discusses(request): if settings.USE_DB_REDESIGN_PROXY_CLASSES: res = [] - for d in IDInternal.objects.filter(iesg_state__in=("pub-req", "ad-eval", "review-e", "lc-req", "lc", "writeupw", "goaheadw", "iesg-eva", "defer", "watching"), docevent__ballotpositiondocevent__pos="discuss").distinct(): + for d in IDInternal.objects.filter(states__type="draft-iesg", states__slug__in=("pub-req", "ad-eval", "review-e", "lc-req", "lc", "writeupw", "goaheadw", "iesg-eva", "defer", "watching"), docevent__ballotpositiondocevent__pos="discuss").distinct(): found = False for p in d.positions.all(): if p.discuss: diff --git a/ietf/ietfworkflows/tests.py b/ietf/ietfworkflows/tests.py index 46fd61953..3632a1831 100644 --- a/ietf/ietfworkflows/tests.py +++ b/ietf/ietfworkflows/tests.py @@ -25,7 +25,7 @@ class EditStreamInfoTestCase(django.test.TestCase): draft = make_test_data() draft.stream_id = "ise" draft.group = Group.objects.get(type="individ") - draft.unset_state(State.objects.get(type="draft-stream-ietf", slug="wg-doc")) + draft.unset_state("draft-stream-ietf") draft.save() url = urlreverse('edit_adopt', kwargs=dict(name=draft.name)) diff --git a/ietf/ietfworkflows/utils.py b/ietf/ietfworkflows/utils.py index 17e0efdcb..ac3bab79a 100644 --- a/ietf/ietfworkflows/utils.py +++ b/ietf/ietfworkflows/utils.py @@ -328,18 +328,25 @@ def update_state(doc, comment, person, to_state, estimated_date=None, extra_noti e.desc = u"%s changed to %s from %s" % (to_state.type.label, to_state, from_state) e.save() - if estimated_date: - t = DocReminderTypeName.objects.get(slug="stream-s") - try: - reminder = DocReminder.objects.get(event__doc=doc, type=t, - active=True) - except DocReminder.DoesNotExist: - reminder = DocReminder(type=t) + # reminder + reminder_type = DocReminderTypeName.objects.get(slug="stream-s") + try: + reminder = DocReminder.objects.get(event__doc=doc, type=reminder_type, + active=True) + except DocReminder.DoesNotExist: + reminder = None - reminder.event = e - reminder.due = estimated_date - reminder.active = True - reminder.save() + if estimated_date: + if not reminder: + reminder = DocReminder(type=reminder_type) + + reminder.event = e + reminder.due = estimated_date + reminder.active = True + reminder.save() + elif reminder: + reminder.active = False + reminder.save() receivers = get_notification_receivers(doc, extra_notify) send_mail(None, receivers, settings.DEFAULT_FROM_EMAIL, diff --git a/ietf/submit/tests.py b/ietf/submit/tests.py index ee05d79a9..053d23913 100644 --- a/ietf/submit/tests.py +++ b/ietf/submit/tests.py @@ -177,7 +177,7 @@ class SubmitTestCase(django.test.TestCase): self.assertTrue(name in confirmation["Subject"]) # dig out confirmation link - msg = confirmation.get_payload(i=1).get_payload(i=0).get_payload(decode=True) + msg = confirmation.get_payload(decode=True) line_start = "I-D Submission Tool URL:" self.assertTrue(line_start in msg) confirm_url = None diff --git a/ietf/submit/utils.py b/ietf/submit/utils.py index bc6031854..0853f324a 100644 --- a/ietf/submit/utils.py +++ b/ietf/submit/utils.py @@ -108,8 +108,7 @@ def perform_postREDESIGN(submission): draft.rev = submission.revision draft.pages = submission.txt_page_count draft.abstract = submission.abstract - was_rfc = draft.state_id == "rfc" - draft.state_id = "active" + was_rfc = draft.get_state_slug() == "rfc" if draft.name.startswith("draft-iab-"): stream_slug = "iab" @@ -121,10 +120,12 @@ def perform_postREDESIGN(submission): stream_slug = "ietf" draft.stream = DocStreamName.objects.get(slug=stream_slug) + draft.save() + + draft.set_state(State.objects.get(type="draft", slug="active")) if draft.stream_id == "ietf": # automatically set state "WG Document" - draft.set_state(State.objects.get(type="draft_stream_%s" % draft.stream_id, slug="wg-doc")) - draft.save() + draft.set_state(State.objects.get(type="draft-stream-%s" % draft.stream_id, slug="wg-doc")) DocAlias.objects.get_or_create(name=submission.filename, document=draft) @@ -162,7 +163,7 @@ def perform_postREDESIGN(submission): submission.status_id = POSTED announce_to_lists(submission) - if draft.iesg_state != None and not was_rfc: + if draft.get_state("draft-iesg") != None and not was_rfc: announce_new_version(submission, draft, state_change_msg) announce_to_authors(submission) diff --git a/ietf/utils/test_data.py b/ietf/utils/test_data.py index 05344b8b5..fe5125359 100644 --- a/ietf/utils/test_data.py +++ b/ietf/utils/test_data.py @@ -153,8 +153,6 @@ def make_test_data(): time=datetime.datetime.now(), type_id="draft", title="Optimizing Martian Network Topologies", - state_id="active", - iesg_state_id="pub-req", stream_id="ietf", group=group, abstract="Techniques for achieving near-optimal Martian networks.", @@ -167,6 +165,8 @@ def make_test_data(): note="", ) + draft.set_state(State.objects.get(type="draft", slug="active")) + draft.set_state(State.objects.get(type="draft-iesg", slug="pub-req")) draft.set_state(State.objects.get(type="draft-stream-%s" % draft.stream_id, slug="wg-doc")) doc_alias = DocAlias.objects.create( @@ -244,7 +244,7 @@ def make_test_data(): type_id="ietf", date=datetime.date.today() + datetime.timedelta(days=180), city="New York", - country="United States", + country="US", time_zone="US/Eastern", break_area="Lounge", reg_area="Lobby", diff --git a/ietf/wgchairs/tests.py b/ietf/wgchairs/tests.py index 721b3bb9f..ce46ccffe 100644 --- a/ietf/wgchairs/tests.py +++ b/ietf/wgchairs/tests.py @@ -110,10 +110,9 @@ class ManageShepherdsTestCase(django.test.TestCase): from redesign.doc.models import Document common = dict(group=group, - state_id="active", ad=Person.objects.get(user__username="ad"), type_id="draft") - Document.objects.create(name="test-no-shepherd", + Document.objects.create(name="test-shepherd-no", title="No shepherd", shepherd=None, **common) @@ -124,6 +123,8 @@ class ManageShepherdsTestCase(django.test.TestCase): Document.objects.create(name="test-shepherd-other", title="Shepherd other", shepherd=Person.objects.get(user__username="plain"), **common) + for d in Document.objects.filter(name__startswith="test-shepherd"): + d.set_state(State.objects.get(type="draft", slug="active")) # get and make sure they are divided correctly r = self.client.get(url) diff --git a/ietf/wgchairs/views.py b/ietf/wgchairs/views.py index 62a1c994f..6172b7de8 100644 --- a/ietf/wgchairs/views.py +++ b/ietf/wgchairs/views.py @@ -226,7 +226,7 @@ def wg_shepherd_documents(request, acronym): current_person = get_person_for_user(user) if settings.USE_DB_REDESIGN_PROXY_CLASSES: - base_qs = InternetDraft.objects.filter(group=wg, state="active").select_related("status").order_by('title') + base_qs = InternetDraft.objects.filter(group=wg, states__type="draft", states__slug="active").select_related("status").order_by('title') else: form = SearchForm({'by': 'group', 'group': str(wg.group_acronym.acronym), 'activeDrafts': 'on'}) diff --git a/redesign/doc/admin.py b/redesign/doc/admin.py index ede87d30c..df59432be 100644 --- a/redesign/doc/admin.py +++ b/redesign/doc/admin.py @@ -26,7 +26,7 @@ class StatesWidget(forms.SelectMultiple): requires 'instance' have been set on the widget.""" def render(self, name, value, attrs=None, choices=()): - types = StateType.objects.filter(slug__in=get_state_types(self.instance)) + types = StateType.objects.filter(slug__in=get_state_types(self.instance)).order_by("slug") categorized_choices = [] for t in types: @@ -78,12 +78,16 @@ class DocumentForm(forms.ModelForm): model = Document class DocumentAdmin(admin.ModelAdmin): - list_display = ['name', 'rev', 'state', 'group', 'pages', 'intended_std_level', 'author_list', 'time'] + list_display = ['name', 'rev', 'group', 'pages', 'intended_std_level', 'author_list', 'time'] search_fields = ['name'] + list_filter = ['type'] raw_id_fields = ['authors', 'related', 'group', 'shepherd', 'ad'] inlines = [DocAliasInline] form = DocumentForm + def state(self, instance): + return self.get_state() + admin.site.register(Document, DocumentAdmin) class DocHistoryAdmin(admin.ModelAdmin): @@ -92,6 +96,9 @@ class DocHistoryAdmin(admin.ModelAdmin): ordering = ['time', 'doc', 'rev'] raw_id_fields = ['doc', 'authors', 'related', 'group', 'shepherd', 'ad'] + def state(self, instance): + return self.get_state() + admin.site.register(DocHistory, DocHistoryAdmin) class DocAliasAdmin(admin.ModelAdmin): diff --git a/redesign/doc/models.py b/redesign/doc/models.py index 824c0cfa8..fb71c6057 100644 --- a/redesign/doc/models.py +++ b/redesign/doc/models.py @@ -37,20 +37,15 @@ class State(models.Model): class DocumentInfo(models.Model): """Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement""" time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True - # Document related + type = models.ForeignKey(DocTypeName, blank=True, null=True) # Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki, External ... title = models.CharField(max_length=255) - # State - states = models.ManyToManyField(State, blank=True) - state = models.ForeignKey(DocStateName, blank=True, null=True) # Active/Expired/RFC/Replaced/Withdrawn + states = models.ManyToManyField(State, blank=True) # plain state (Active/Expired/...), IESG state, stream state tags = models.ManyToManyField(DocTagName, blank=True, null=True) # Revised ID Needed, ExternalParty, AD Followup, ... stream = models.ForeignKey(DocStreamName, blank=True, null=True) # IETF, IAB, IRTF, Independent Submission group = models.ForeignKey(Group, blank=True, null=True) # WG, RG, IAB, IESG, Edu, Tools - iesg_state = models.ForeignKey(IesgDocStateName, verbose_name="IESG state", blank=True, null=True) # - iana_state = models.ForeignKey(IanaDocStateName, verbose_name="IANA state", blank=True, null=True) - rfc_state = models.ForeignKey(RfcDocStateName, verbose_name="RFC state", blank=True, null=True) - # Other + abstract = models.TextField() rev = models.CharField(verbose_name="revision", max_length=16, blank=True) pages = models.IntegerField(blank=True, null=True) @@ -74,6 +69,8 @@ class DocumentInfo(models.Model): raise NotImplemented def set_state(self, state): + """Switch state type implicit in state to state. This just + sets the state, doesn't log the change.""" already_set = self.states.filter(type=state.type) others = [s for s in already_set if s != state] if others: @@ -81,20 +78,37 @@ class DocumentInfo(models.Model): if state not in already_set: self.states.add(state) - def unset_state(self, state): - self.states.remove(state) + def unset_state(self, state_type): + """Unset state of type so no state of that type is any longer set.""" + self.states.remove(*self.states.filter(type=state_type)) + + def get_state(self, state_type=None): + """Get state of type, or default state for document type if not specified.""" + if state_type == None: + state_type = self.type_id - def get_state(self, state_type): try: return self.states.get(type=state_type) except State.DoesNotExist: return None - class Meta: - abstract = True + def get_state_slug(self, state_type=None): + """Get state of type, or default if not specified, returning + the slug of the state or None. This frees the caller of having + to check against None before accessing the slug for a + comparison.""" + s = self.get_state(state_type) + if s: + return s.slug + else: + return None + def author_list(self): return ", ".join(email.address for email in self.authors.all()) + class Meta: + abstract = True + class RelatedDocument(models.Model): source = models.ForeignKey('Document') target = models.ForeignKey('DocAlias') @@ -128,7 +142,7 @@ class Document(DocumentInfo): def get_absolute_url(self): name = self.name - if self.state == "rfc": + if self.get_state_slug() == "rfc": aliases = self.docalias_set.filter(name__startswith="rfc") if aliases: name = aliases[0].name @@ -152,7 +166,7 @@ class Document(DocumentInfo): def canonical_name(self): name = self.name - if self.type_id == "draft" and self.state_id == "rfc": + if self.type_id == "draft" and self.get_state() == "rfc": a = self.docalias_set.filter(name__startswith="rfc") if a: name = a[0].name diff --git a/redesign/doc/proxy.py b/redesign/doc/proxy.py index 7d93031cc..64a92fcba 100644 --- a/redesign/doc/proxy.py +++ b/redesign/doc/proxy.py @@ -12,12 +12,12 @@ class InternetDraft(Document): objects = TranslatingManager(dict(filename="name", filename__contains="name__contains", id_document_tag="pk", - status=lambda v: ("state", { 1: 'active', 2: 'expired', 3: 'rfc', 4: 'auth-rm', 5: 'repl', 6: 'ietf-rm'}[v]), + status=lambda v: ("states__slug", { 1: 'active', 2: 'expired', 3: 'rfc', 4: 'auth-rm', 5: 'repl', 6: 'ietf-rm'}[v], "states__type", "draft"), job_owner="ad", rfc_number=lambda v: ("docalias__name", "rfc%s" % v), - cur_state="iesg_state__order", + cur_state=lambda v: ("states__order", v, 'states__type', 'draft-iesg'), idinternal__primary_flag=None, - idinternal__cur_state__state="iesg_state__name", + idinternal__cur_state__state=lambda v: ("states__name", v, 'states__type', 'draft-iesg'), ), always_filter=dict(type="draft")) DAYS_TO_EXPIRE=185 @@ -89,11 +89,12 @@ class InternetDraft(Document): #status = models.ForeignKey(IDStatus) @property def status(self): - return IDStatus().from_object(self.state) if self.state else None + s = self.get_state() + return IDStatus().from_object(s) if s else None @property def status_id(self): - return { 'active': 1, 'repl': 5, 'expired': 2, 'rfc': 3, 'auth-rm': 4, 'ietf-rm': 6 }[self.state_id] + return { 'active': 1, 'repl': 5, 'expired': 2, 'rfc': 3, 'auth-rm': 4, 'ietf-rm': 6 }[self.get_state_slug()] #intended_status = models.ForeignKey(IDIntendedStatus) @property @@ -180,7 +181,7 @@ class InternetDraft(Document): e = self.latest_event(type="started_iesg_process") if e: start = e.time - if self.state_id == "rfc" and self.name.startswith("draft") and not hasattr(self, "viewing_as_rfc"): + if self.get_state_slug() == "rfc" and self.name.startswith("draft") and not hasattr(self, "viewing_as_rfc"): previous_process = self.latest_event(type="started_iesg_process", time__lt=e.time) if previous_process: start = previous_process.time @@ -211,7 +212,7 @@ class InternetDraft(Document): e = self.changed_ballot_position else: e = self.latest_event(type="changed_ballot_position") - return self if self.iesg_state or e else None + return self if e or self.get_state("draft-iesg") else None # reverse relationship @property @@ -238,7 +239,7 @@ class InternetDraft(Document): return self.docstate() def revision_display(self): r = int(self.revision) - if self.state_id != 'active' and not self.expired_tombstone: + if self.get_state_slug() != 'active' and not self.expired_tombstone: r = max(r - 1, 0) return "%02d" % r def expiration(self): @@ -296,7 +297,7 @@ class InternetDraft(Document): #rfc_flag = models.IntegerField(null=True) @property def rfc_flag(self): - return self.state_id == "rfc" + return self.get_state_slug() == "rfc" #ballot = models.ForeignKey(BallotInfo, related_name='drafts', db_column="ballot_id") @property @@ -345,17 +346,23 @@ class InternetDraft(Document): #cur_state = models.ForeignKey(IDState, db_column='cur_state', related_name='docs') @property def cur_state(self): - return IDState().from_object(self.iesg_state) if self.iesg_state else None + s = self.get_state("draft-iesg") + return IDState().from_object(s) if s else None @property def cur_state_id(self): - return self.iesg_state.order if self.iesg_state else None + s = self.get_state("draft-iesg") + return s.order if s else None #prev_state = models.ForeignKey(IDState, db_column='prev_state', related_name='docs_prev') @property def prev_state(self): - ds = self.history_set.exclude(iesg_state=self.iesg_state).order_by('-time')[:1] - return IDState().from_object(ds[0].iesg_state) if ds else None + ds = self.history_set.exclude(states=self.get_state("draft-iesg")).order_by('-time')[:1] + if ds: + s = ds[0].get_state("draft-iesg") + if s: + return IDState().from_object(s) if ds else None + return None #assigned_to = models.CharField(blank=True, max_length=25) # unused @@ -491,20 +498,19 @@ class InternetDraft(Document): def ballot_others(self): return [] def docstate(self): - if self.iesg_state: - return self.iesg_state.name + s = self.get_state("draft-iesg") + if s: + return s.name else: return "I-D Exists" - def change_state(self, state, sub_state): - self.iesg_state = state - # things from BallotInfo #active = models.BooleanField() @property def active(self): # taken from BallotWrapper - return self.latest_event(type="sent_ballot_announcement") and self.iesg_state and self.iesg_state.name in ['In Last Call', 'Waiting for Writeup', 'Waiting for AD Go-Ahead', 'IESG Evaluation', 'IESG Evaluation - Defer'] and (self.state_id == "rfc" or self.state_id == "active") + s = self.get_state("draft-iesg") + return self.latest_event(type="sent_ballot_announcement") and s and s.name in ['In Last Call', 'Waiting for Writeup', 'Waiting for AD Go-Ahead', 'IESG Evaluation', 'IESG Evaluation - Defer'] and (self.get_state_slug() in ("rfc", "active")) #an_sent = models.BooleanField() @property @@ -528,7 +534,7 @@ class InternetDraft(Document): @property def defer(self): # we're deferred if we're in the deferred state - return self.iesg_state and self.iesg_state.name == "IESG Evaluation - Defer" + return self.get_state_slug("draft-iesg") == "defer" #defer_by = models.ForeignKey(IESGLogin, db_column='defer_by', related_name='deferred', null=True) @property @@ -916,3 +922,82 @@ class ObjectHistoryEntryProxy(DocEvent): class Meta: proxy = True + +class IDStatus(State): + def from_object(self, base): + for f in base._meta.fields: + setattr(self, f.name, getattr(base, f.name)) + return self + + #status_id = models.AutoField(primary_key=True) + + #status = models.CharField(max_length=25, db_column='status_value') + @property + def status(self): + return self.name + + def __unicode__(self): + return super(self.__class__, self).__unicode__() + + class Meta: + proxy = True + +class IDState(State): + PUBLICATION_REQUESTED = 10 + LAST_CALL_REQUESTED = 15 + IN_LAST_CALL = 16 + WAITING_FOR_WRITEUP = 18 + WAITING_FOR_AD_GO_AHEAD = 19 + IESG_EVALUATION = 20 + IESG_EVALUATION_DEFER = 21 + APPROVED_ANNOUNCEMENT_SENT = 30 + AD_WATCHING = 42 + DEAD = 99 + DO_NOT_PUBLISH_STATES = (33, 34) + + objects = TranslatingManager(dict(pk="order", + document_state_id="order", + document_state_id__in="order__in")) + + def from_object(self, base): + for f in base._meta.fields: + setattr(self, f.name, getattr(base, f.name)) + return self + + #document_state_id = models.AutoField(primary_key=True) + @property + def document_state_id(self): + return self.order + + #state = models.CharField(max_length=50, db_column='document_state_val') + @property + def state(self): + return self.name + + #equiv_group_flag = models.IntegerField(null=True, blank=True) # unused + #description = models.TextField(blank=True, db_column='document_desc') + @property + def description(self): + return self.desc + + @property + def nextstate(self): + # simulate related queryset + return IDState.objects.filter(pk__in=[x.pk for x in self.next_states]) + + @property + def next_state(self): + # simulate IDNextState + return self + + def __str__(self): + return self.state + + @staticmethod + def choices(): + return [(state.pk, state.name) for state in IDState.objects.all()] + + class Meta: + proxy = True + + diff --git a/redesign/group/proxy.py b/redesign/group/proxy.py index cf87bc0e2..562fc4a68 100644 --- a/redesign/group/proxy.py +++ b/redesign/group/proxy.py @@ -177,7 +177,7 @@ class IETFWG(Group): def active_drafts(self): from redesign.doc.proxy import InternetDraft - return InternetDraft.objects.filter(group=self, state="active") + return InternetDraft.objects.filter(group=self, states__type="draft", states__slug="active") # def choices(): # return [(wg.group_acronym_id, wg.group_acronym.acronym) for wg in IETFWG.objects.all().filter(group_type__type='WG').select_related().order_by('acronym.acronym')] # choices = staticmethod(choices) diff --git a/redesign/importing/import-document-state.py b/redesign/importing/import-document-state.py index ac1239905..1011c2f71 100755 --- a/redesign/importing/import-document-state.py +++ b/redesign/importing/import-document-state.py @@ -47,9 +47,10 @@ connection.queries = DontSaveQueries() # Regarding history, we currently don't try to create DocumentHistory # objects, we just import the comments as events. -# imports InternetDraft, IDInternal, BallotInfo, Position, -# IESGComment, IESGDiscuss, DocumentComment, IDAuthor, idrfc.RfcIndex, -# idrfc.DraftVersions, StreamedID +# imports drafts and RFCs, more specifically InternetDraft, +# IDInternal, BallotInfo, Position, IESGComment, IESGDiscuss, +# DocumentComment, IDAuthor, idrfc.RfcIndex, idrfc.DraftVersions, +# StreamedID def alias_doc(name, doc): @@ -85,36 +86,35 @@ intended_std_level_mapping["Draft"] = intended_std_level_mapping["Draft Standard std_level_mapping = get_std_level_mapping() state_mapping = { - 'Active': name(DocStateName, "active", "Active"), - 'Expired': name(DocStateName, "expired", "Expired"), - 'RFC': name(DocStateName, "rfc", "RFC"), - 'Withdrawn by Submitter': name(DocStateName, "auth-rm", "Withdrawn by Submitter"), - 'Replaced': name(DocStateName, "repl", "Replaced"), - 'Withdrawn by IETF': name(DocStateName, "ietf-rm", "Withdrawn by IETF"), + 'Active': State.objects.get(type="draft", slug="active"), + 'Expired': State.objects.get(type="draft", slug="expired"), + 'RFC': State.objects.get(type="draft", slug="rfc"), + 'Withdrawn by Submitter': State.objects.get(type="draft", slug="auth-rm"), + 'Replaced': State.objects.get(type="draft", slug="repl"), + 'Withdrawn by IETF': State.objects.get(type="draft", slug="ietf-rm"), } iesg_state_mapping = { - 'RFC Published': name(IesgDocStateName, "pub", "RFC Published", 'The ID has been published as an RFC.', order=32), - 'Dead': name(IesgDocStateName, "dead", "Dead", 'Document is "dead" and is no longer being tracked. (E.g., it has been replaced by another document with a different name, it has been withdrawn, etc.)', order=99), - 'Approved-announcement to be sent': name(IesgDocStateName, "approved", "Approved-announcement to be sent", 'The IESG has approved the document for publication, but the Secretariat has not yet sent out on official approval message.', order=27), - 'Approved-announcement sent': name(IesgDocStateName, "ann", "Approved-announcement sent", 'The IESG has approved the document for publication, and the Secretariat has sent out the official approval message to the RFC editor.', order=30), - 'AD is watching': name(IesgDocStateName, "watching", "AD is watching", 'An AD is aware of the document and has chosen to place the document in a separate state in order to keep a closer eye on it (for whatever reason). Documents in this state are still not being actively tracked in the sense that no formal request has been made to publish or advance the document. The sole difference between this state and "I-D Exists" is that an AD has chosen to put it in a separate state, to make it easier to keep track of (for the AD\'s own reasons).', order=42), - 'IESG Evaluation': name(IesgDocStateName, "iesg-eva", "IESG Evaluation", 'The document is now (finally!) being formally reviewed by the entire IESG. Documents are discussed in email or during a bi-weekly IESG telechat. In this phase, each AD reviews the document and airs any issues they may have. Unresolvable issues are documented as "discuss" comments that can be forwarded to the authors/WG. See the description of substates for additional details about the current state of the IESG discussion.', order=20), - 'AD Evaluation': name(IesgDocStateName, "ad-eval", "AD Evaluation", 'A specific AD (e.g., the Area Advisor for the WG) has begun reviewing the document to verify that it is ready for advancement. The shepherding AD is responsible for doing any necessary review before starting an IETF Last Call or sending the document directly to the IESG as a whole.', order=11), - 'Last Call Requested': name(IesgDocStateName, "lc-req", "Last Call Requested", 'The AD has requested that the Secretariat start an IETF Last Call, but the the actual Last Call message has not been sent yet.', order=15), - 'In Last Call': name(IesgDocStateName, "lc", "In Last Call", 'The document is currently waiting for IETF Last Call to complete. Last Calls for WG documents typically last 2 weeks, those for individual submissions last 4 weeks.', order=16), - 'Publication Requested': name(IesgDocStateName, "pub-req", "Publication Requested", 'A formal request has been made to advance/publish the document, following the procedures in Section 7.5 of RFC 2418. The request could be from a WG chair, from an individual through the RFC Editor, etc. (The Secretariat (iesg-secretary@ietf.org) is copied on these requests to ensure that the request makes it into the ID tracker.) A document in this state has not (yet) been reviewed by an AD nor has any official action been taken on it yet (other than to note that its publication has been requested.', order=10), - 'RFC Ed Queue': name(IesgDocStateName, "rfcqueue", "RFC Ed Queue", 'The document is in the RFC editor Queue (as confirmed by http://www.rfc-editor.org/queue.html).', order=31), - 'IESG Evaluation - Defer': name(IesgDocStateName, "defer", "IESG Evaluation - Defer", 'During a telechat, one or more ADs requested an additional 2 weeks to review the document. A defer is designed to be an exception mechanism, and can only be invoked once, the first time the document comes up for discussion during a telechat.', order=21), - 'Waiting for Writeup': name(IesgDocStateName, "writeupw", "Waiting for Writeup", 'Before a standards-track or BCP document is formally considered by the entire IESG, the AD must write up a protocol action. The protocol action is included in the approval message that the Secretariat sends out when the document is approved for publication as an RFC.', order=18), - 'Waiting for AD Go-Ahead': name(IesgDocStateName, "goaheadw", "Waiting for AD Go-Ahead", 'As a result of the IETF Last Call, comments may need to be responded to and a revision of the ID may be needed as well. The AD is responsible for verifying that all Last Call comments have been adequately addressed and that the (possibly revised) document is in the ID directory and ready for consideration by the IESG as a whole.', order=19), - 'Expert Review': name(IesgDocStateName, "review-e", "Expert Review", 'An AD sometimes asks for an external review by an outside party as part of evaluating whether a document is ready for advancement. MIBs, for example, are reviewed by the "MIB doctors". Other types of reviews may also be requested (e.g., security, operations impact, etc.). Documents stay in this state until the review is complete and possibly until the issues raised in the review are addressed. See the "note" field for specific details on the nature of the review.', order=12), - 'DNP-waiting for AD note': name(IesgDocStateName, "nopubadw", "DNP-waiting for AD note", 'Do Not Publish: The IESG recommends against publishing the document, but the writeup explaining its reasoning has not yet been produced. DNPs apply primarily to individual submissions received through the RFC editor. See the "note" field for more details on who has the action item.', order=33), - 'DNP-announcement to be sent': name(IesgDocStateName, "nopubanw", "DNP-announcement to be sent", 'The IESG recommends against publishing the document, the writeup explaining its reasoning has been produced, but the Secretariat has not yet sent out the official "do not publish" recommendation message.', order=34), + 'RFC Published': State.objects.get(type="draft-iesg", slug="pub"), + 'Dead': State.objects.get(type="draft-iesg", slug="dead"), + 'Approved-announcement to be sent': State.objects.get(type="draft-iesg", slug="approved"), + 'Approved-announcement sent': State.objects.get(type="draft-iesg", slug="ann"), + 'AD is watching': State.objects.get(type="draft-iesg", slug="watching"), + 'IESG Evaluation': State.objects.get(type="draft-iesg", slug="iesg-eva"), + 'AD Evaluation': State.objects.get(type="draft-iesg", slug="ad-eval"), + 'Last Call Requested': State.objects.get(type="draft-iesg", slug="lc-req"), + 'In Last Call': State.objects.get(type="draft-iesg", slug="lc"), + 'Publication Requested': State.objects.get(type="draft-iesg", slug="pub-req"), + 'RFC Ed Queue': State.objects.get(type="draft-iesg", slug="rfcqueue"), + 'IESG Evaluation - Defer': State.objects.get(type="draft-iesg", slug="defer"), + 'Waiting for Writeup': State.objects.get(type="draft-iesg", slug="writeupw"), + 'Waiting for AD Go-Ahead': State.objects.get(type="draft-iesg", slug="goaheadw"), + 'Expert Review': State.objects.get(type="draft-iesg", slug="review-e"), + 'DNP-waiting for AD note': State.objects.get(type="draft-iesg", slug="nopubadw"), + 'DNP-announcement to be sent': State.objects.get(type="draft-iesg", slug="nopubanw"), None: None, # FIXME: consider introducing the ID-exists state } - ballot_position_mapping = { 'No Objection': name(BallotPositionName, 'noobj', 'No Objection'), 'Yes': name(BallotPositionName, 'yes', 'Yes'), @@ -265,12 +265,13 @@ re_comment_discuss_by_tag = re.compile(r" by [\w-]+ [\w-]+$") def import_from_idinternal(d, idinternal): d.time = idinternal.event_date - d.iesg_state = iesg_state_mapping[idinternal.cur_state.state] d.ad = iesg_login_to_person(idinternal.job_owner) d.notify = idinternal.state_change_notice_to or "" d.note = (idinternal.note or "").replace('
', '\n').strip().replace('\n', '
') d.save() + d.set_state(iesg_state_mapping[idinternal.cur_state.state]) + # extract events last_note_change_text = "" started_iesg_process = "" @@ -798,9 +799,10 @@ for index, o in enumerate(all_drafts.iterator()): d.time = o.revision_date d.type = type_draft d.title = o.title - d.state = state_mapping[o.status.status] d.group = Group.objects.get(acronym=o.group.acronym) + d.set_state(state_mapping[o.status.status]) + # try guess stream to have a default for old submissions if o.filename.startswith("draft-iab-"): d.stream = stream_mapping["IAB"] @@ -812,13 +814,13 @@ for index, o in enumerate(all_drafts.iterator()): d.stream = stream_mapping["IETF"] try: - d.stream = stream_mapping[StreamedID.objects.get(draft=o).stream.name] + old_stream = StreamedID.objects.get(draft=o).stream + if old_stream: + d.stream = stream_mapping[old_stream.name] except StreamedID.DoesNotExist: pass - d.iesg_state = iesg_state_mapping[None] - d.iana_state = None - d.rfc_state = None + d.unset_state("draft-iesg") s = workflows.utils.get_state(o) if s: try: @@ -1063,7 +1065,8 @@ for index, o in enumerate(all_rfcs.iterator()): d.time = datetime.datetime.now() d.title = o.title d.std_level = std_level_mapping[o.current_status] - d.state = state_mapping['RFC'] + d.set_state(state_mapping["RFC"]) + d.stream = stream_mapping[o.stream] if not d.group and o.wg: d.group = Group.objects.get(acronym=o.wg) diff --git a/redesign/importing/import-states.py b/redesign/importing/import-states.py index f382c835b..a113479da 100755 --- a/redesign/importing/import-states.py +++ b/redesign/importing/import-states.py @@ -14,16 +14,76 @@ management.setup_environ(settings) import workflows.models from ietf.ietfworkflows.models import StateDescription +from ietf.idrfc.mirror_rfc_editor_queue import get_rfc_state_mapping from redesign.doc.models import * -# import states for documents from workflows.Workflow and -# ietfworkflows.StateDescription +# adds states for documents and import states from workflows.Workflow +# and ietfworkflows.StateDescription # state types -ietf_state_type, _ = StateType.objects.get_or_create(slug="draft-stream-ietf", label="WG state") -irtf_state_type, _ = StateType.objects.get_or_create(slug="draft-stream-irtf", label="RG state") -ise_state_type, _ = StateType.objects.get_or_create(slug="draft-stream-ise", label="ISE state") -iab_state_type, _ = StateType.objects.get_or_create(slug="draft-stream-iab", label="IAB state") +draft_type, _ = StateType.objects.get_or_create(slug="draft", label="State") +draft_iesg_type, _ = StateType.objects.get_or_create(slug="draft-iesg", label="IESG state") +draft_iana_type, _ = StateType.objects.get_or_create(slug="draft-iana", label="IANA state") +draft_rfc_type, _ = StateType.objects.get_or_create(slug="draft-rfceditor", label="RFC Editor state") +ietf_type, _ = StateType.objects.get_or_create(slug="draft-stream-ietf", label="WG state") +irtf_type, _ = StateType.objects.get_or_create(slug="draft-stream-irtf", label="RG state") +ise_type, _ = StateType.objects.get_or_create(slug="draft-stream-ise", label="ISE state") +iab_type, _ = StateType.objects.get_or_create(slug="draft-stream-iab", label="IAB state") + +# draft states +print "Importing draft states" +State.objects.get_or_create(type=draft_type, slug="active", name="Active", order=1) +State.objects.get_or_create(type=draft_type, slug="expired", name="Expired", order=2) +State.objects.get_or_create(type=draft_type, slug="rfc", name="RFC", order=3) +State.objects.get_or_create(type=draft_type, slug="repl", name="Replaced", order=4) +State.objects.get_or_create(type=draft_type, slug="auth-rm", name="Withdrawn by Submitter", order=5) +State.objects.get_or_create(type=draft_type, slug="ietf-rm", name="Withdrawn by IETF", order=6) + +# IESG draft states +State.objects.get_or_create(type=draft_iesg_type, slug="pub", name="RFC Published", desc='The ID has been published as an RFC.', order=32) +State.objects.get_or_create(type=draft_iesg_type, slug="dead", name="Dead", desc='Document is "dead" and is no longer being tracked. (E.g., it has been replaced by another document with a different name, it has been withdrawn, etc.)', order=99) +State.objects.get_or_create(type=draft_iesg_type, slug="approved", name="Approved-announcement to be sent", desc='The IESG has approved the document for publication, but the Secretariat has not yet sent out on official approval message.', order=27) +State.objects.get_or_create(type=draft_iesg_type, slug="ann", name="Approved-announcement sent", desc='The IESG has approved the document for publication, and the Secretariat has sent out the official approval message to the RFC editor.', order=30) +State.objects.get_or_create(type=draft_iesg_type, slug="watching", name="AD is watching", desc='An AD is aware of the document and has chosen to place the document in a separate state in order to keep a closer eye on it (for whatever reason). Documents in this state are still not being actively tracked in the sense that no formal request has been made to publish or advance the document. The sole difference between this state and "I-D Exists" is that an AD has chosen to put it in a separate state, to make it easier to keep track of (for the AD\'s own reasons).', order=42) +State.objects.get_or_create(type=draft_iesg_type, slug="iesg-eva", name="IESG Evaluation", desc='The document is now (finally!) being formally reviewed by the entire IESG. Documents are discussed in email or during a bi-weekly IESG telechat. In this phase, each AD reviews the document and airs any issues they may have. Unresolvable issues are documented as "discuss" comments that can be forwarded to the authors/WG. See the description of substates for additional details about the current state of the IESG discussion.', order=20) +State.objects.get_or_create(type=draft_iesg_type, slug="ad-eval", name="AD Evaluation", desc='A specific AD (e.g., the Area Advisor for the WG) has begun reviewing the document to verify that it is ready for advancement. The shepherding AD is responsible for doing any necessary review before starting an IETF Last Call or sending the document directly to the IESG as a whole.', order=11) +State.objects.get_or_create(type=draft_iesg_type, slug="lc-req", name="Last Call Requested", desc='The AD has requested that the Secretariat start an IETF Last Call, but the the actual Last Call message has not been sent yet.', order=15) +State.objects.get_or_create(type=draft_iesg_type, slug="lc", name="In Last Call", desc='The document is currently waiting for IETF Last Call to complete. Last Calls for WG documents typically last 2 weeks, those for individual submissions last 4 weeks.', order=16) +State.objects.get_or_create(type=draft_iesg_type, slug="pub-req", name="Publication Requested", desc='A formal request has been made to advance/publish the document, following the procedures in Section 7.5 of RFC 2418. The request could be from a WG chair, from an individual through the RFC Editor, etc. (The Secretariat (iesg-secretary@ietf.org) is copied on these requests to ensure that the request makes it into the ID tracker.) A document in this state has not (yet) been reviewed by an AD nor has any official action been taken on it yet (other than to note that its publication has been requested.', order=10) +State.objects.get_or_create(type=draft_iesg_type, slug="rfcqueue", name="RFC Ed Queue", desc='The document is in the RFC editor Queue (as confirmed by http://www.rfc-editor.org/queue.html).', order=31) +State.objects.get_or_create(type=draft_iesg_type, slug="defer", name="IESG Evaluation - Defer", desc='During a telechat, one or more ADs requested an additional 2 weeks to review the document. A defer is designed to be an exception mechanism, and can only be invoked once, the first time the document comes up for discussion during a telechat.', order=21) +State.objects.get_or_create(type=draft_iesg_type, slug="writeupw", name="Waiting for Writeup", desc='Before a standards-track or BCP document is formally considered by the entire IESG, the AD must write up a protocol action. The protocol action is included in the approval message that the Secretariat sends out when the document is approved for publication as an RFC.', order=18) +State.objects.get_or_create(type=draft_iesg_type, slug="goaheadw", name="Waiting for AD Go-Ahead", desc='As a result of the IETF Last Call, comments may need to be responded to and a revision of the ID may be needed as well. The AD is responsible for verifying that all Last Call comments have been adequately addressed and that the (possibly revised) document is in the ID directory and ready for consideration by the IESG as a whole.', order=19) +State.objects.get_or_create(type=draft_iesg_type, slug="review-e", name="Expert Review", desc='An AD sometimes asks for an external review by an outside party as part of evaluating whether a document is ready for advancement. MIBs, for example, are reviewed by the "MIB doctors". Other types of reviews may also be requested (e.g., security, operations impact, etc.). Documents stay in this state until the review is complete and possibly until the issues raised in the review are addressed. See the "note" field for specific details on the nature of the review.', order=12) +State.objects.get_or_create(type=draft_iesg_type, slug="nopubadw", name="DNP-waiting for AD note", desc='Do Not Publish: The IESG recommends against publishing the document, but the writeup explaining its reasoning has not yet been produced. DNPs apply primarily to individual submissions received through the RFC editor. See the "note" field for more details on who has the action item.', order=33) +State.objects.get_or_create(type=draft_iesg_type, slug="nopubanw", name="DNP-announcement to be sent", desc='The IESG recommends against publishing the document, the writeup explaining its reasoning has been produced, but the Secretariat has not yet sent out the official "do not publish" recommendation message.', order=34) + +for s in State.objects.filter(type=draft_iesg_type): + n = { + "pub-req": ("ad-eval", "watching", "dead"), + "ad-eval": ("watching", "lc-req", "review-e", "iesg-eva"), + "review-e": ("ad-eval", ), + "lc-req": ("lc", ), + "lc": ("writeupw", "goaheadw"), + "writeupw": ("goaheadw", ), + "goaheadw": ("iesg-eva", ), + "iesg-eva": ("nopubadw", "defer", "ann"), + "defer": ("iesg-eva", ), + "ann": ("approved", ), + "approved": ("rfcqueue", ), + "rfcqueue": ("pub", ), + "pub": ("dead", ), + "nopubadw": ("nopubanw", ), + "nopubanw": ("dead", ), + "watching": ("pub-req", ), + "dead": ("pub-req", ), + } + + s.next_states = State.objects.filter(type=draft_iesg_type, slug__in=n[s.slug]) + +# import RFC Editor queue states +print "importing RFC Editor states" +get_rfc_state_mapping() # WG states, we can get them from the state descriptions wg_doc_state_slug = { @@ -41,59 +101,59 @@ wg_doc_state_slug = { for o in StateDescription.objects.all().order_by('order'): print "importing StateDescription", o.state.name - s, _ = State.objects.get_or_create(type=ietf_state_type, slug=wg_doc_state_slug[o.state.name], name=o.state.name) + s, _ = State.objects.get_or_create(type=ietf_type, slug=wg_doc_state_slug[o.state.name], name=o.state.name) s.desc = o.definition.replace(" ", " ").replace("\n ", "\n").replace("\n\n", "DUMMY").replace("\n", "").replace("DUMMY", "\n\n") # get rid of linebreaks, but keep paragraphs s.order = o.order s.save() # IAB print "importing IAB stream states" -State.objects.get_or_create(type=iab_state_type, slug="candidat", name="Candidate IAB Document", desc="A document being considered for the IAB stream.", order=1) -State.objects.get_or_create(type=iab_state_type, slug="active", name="Active IAB Document", desc="This document has been adopted by the IAB and is being actively developed.", order=2) -State.objects.get_or_create(type=iab_state_type, slug="parked", name="Parked IAB Document", desc="This document has lost its author or editor, is waiting for another document to be written, or cannot currently be worked on by the IAB for some other reason. Annotations probably explain why this document is parked.", order=3) -State.objects.get_or_create(type=iab_state_type, slug="review-i", name="IAB Review", desc="This document is awaiting the IAB itself to come to internal consensus.", order=4) -State.objects.get_or_create(type=iab_state_type, slug="review-c", name="Community Review", desc="This document has completed internal consensus within the IAB and is now under community review.", order=5) -State.objects.get_or_create(type=iab_state_type, slug="approved", name="Approved by IAB, To Be Sent to RFC Editor", desc="The consideration of this document is complete, but it has not yet been sent to the RFC Editor for publication (although that is going to happen soon).", order=6) -State.objects.get_or_create(type=iab_state_type, slug="diff-org", name="Sent to a Different Organization for Publication", desc="The IAB does not expect to publish the document itself, but has passed it on to a different organization that might continue work on the document. The expectation is that the other organization will eventually publish the document.", order=7) -State.objects.get_or_create(type=iab_state_type, slug="rfc-edit", name="Sent to the RFC Editor", desc="The IAB processing of this document is complete and it has been sent to the RFC Editor for publication. The document may be in the RFC Editor's queue, or it may have been published as an RFC; this state doesn't distinguish between different states occurring after the document has left the IAB.", order=8) -State.objects.get_or_create(type=iab_state_type, slug="pub", name="Published RFC", desc="The document has been published as an RFC.", order=9) -State.objects.get_or_create(type=iab_state_type, slug="dead", name="Dead IAB Document", desc="This document was an active IAB document, but for some reason it is no longer being pursued for the IAB stream. It is possible that the document might be revived later, possibly in another stream.", order=10) +State.objects.get_or_create(type=iab_type, slug="candidat", name="Candidate IAB Document", desc="A document being considered for the IAB stream.", order=1) +State.objects.get_or_create(type=iab_type, slug="active", name="Active IAB Document", desc="This document has been adopted by the IAB and is being actively developed.", order=2) +State.objects.get_or_create(type=iab_type, slug="parked", name="Parked IAB Document", desc="This document has lost its author or editor, is waiting for another document to be written, or cannot currently be worked on by the IAB for some other reason. Annotations probably explain why this document is parked.", order=3) +State.objects.get_or_create(type=iab_type, slug="review-i", name="IAB Review", desc="This document is awaiting the IAB itself to come to internal consensus.", order=4) +State.objects.get_or_create(type=iab_type, slug="review-c", name="Community Review", desc="This document has completed internal consensus within the IAB and is now under community review.", order=5) +State.objects.get_or_create(type=iab_type, slug="approved", name="Approved by IAB, To Be Sent to RFC Editor", desc="The consideration of this document is complete, but it has not yet been sent to the RFC Editor for publication (although that is going to happen soon).", order=6) +State.objects.get_or_create(type=iab_type, slug="diff-org", name="Sent to a Different Organization for Publication", desc="The IAB does not expect to publish the document itself, but has passed it on to a different organization that might continue work on the document. The expectation is that the other organization will eventually publish the document.", order=7) +State.objects.get_or_create(type=iab_type, slug="rfc-edit", name="Sent to the RFC Editor", desc="The IAB processing of this document is complete and it has been sent to the RFC Editor for publication. The document may be in the RFC Editor's queue, or it may have been published as an RFC; this state doesn't distinguish between different states occurring after the document has left the IAB.", order=8) +State.objects.get_or_create(type=iab_type, slug="pub", name="Published RFC", desc="The document has been published as an RFC.", order=9) +State.objects.get_or_create(type=iab_type, slug="dead", name="Dead IAB Document", desc="This document was an active IAB document, but for some reason it is no longer being pursued for the IAB stream. It is possible that the document might be revived later, possibly in another stream.", order=10) # IRTF print "importing IRTF stream states" -State.objects.get_or_create(type=irtf_state_type, slug="candidat", name="Candidate RG Document", desc="This document is under consideration in an RG for becoming an IRTF document. A document in this state does not imply any RG consensus and does not imply any precedence or selection. It's simply a way to indicate that somebody has asked for a document to be considered for adoption by an RG.", order=1) -State.objects.get_or_create(type=irtf_state_type, slug="active", name="Active RG Document", desc="This document has been adopted by the RG and is being actively developed.", order=2) -State.objects.get_or_create(type=irtf_state_type, slug="parked", name="Parked RG Document", desc="This document has lost its author or editor, is waiting for another document to be written, or cannot currently be worked on by the RG for some other reason.", order=3) -State.objects.get_or_create(type=irtf_state_type, slug="rg-lc", name="In RG Last Call", desc="The document is in its final review in the RG.", order=4) -State.objects.get_or_create(type=irtf_state_type, slug="sheph-w", name="Waiting for Document Shepherd", desc="IRTF documents have document shepherds who help RG documents through the process after the RG has finished with the document.", order=5) -State.objects.get_or_create(type=irtf_state_type, slug="chair-w", name="Waiting for IRTF Chair", desc="The IRTF Chair is meant to be performing some task such as sending a request for IESG Review.", order=6) -State.objects.get_or_create(type=irtf_state_type, slug="irsg-w", name="Awaiting IRSG Reviews", desc="The document shepherd has taken the document to the IRSG and solicited reviews from one or more IRSG members.", order=7) -State.objects.get_or_create(type=irtf_state_type, slug="irsgpoll", name="In IRSG Poll", desc="The IRSG is taking a poll on whether or not the document is ready to be published.", order=8) -State.objects.get_or_create(type=irtf_state_type, slug="iesg-rev", name="In IESG Review", desc="The IRSG has asked the IESG to do a review of the document, as described in RFC5742.", order=9) -State.objects.get_or_create(type=irtf_state_type, slug="rfc-edit", name="Sent to the RFC Editor", desc="The RG processing of this document is complete and it has been sent to the RFC Editor for publication. The document may be in the RFC Editor's queue, or it may have been published as an RFC; this state doesn't distinguish between different states occurring after the document has left the RG.", order=10) -State.objects.get_or_create(type=irtf_state_type, slug="pub", name="Published RFC", desc="The document has been published as an RFC.", order=11) -State.objects.get_or_create(type=irtf_state_type, slug="iesghold", name="Document on Hold Based On IESG Request", desc="The IESG has requested that the document be held pending further review, as specified in RFC 5742, and the IRTF has agreed to such a hold.", order=12) -State.objects.get_or_create(type=irtf_state_type, slug="dead", name="Dead IRTF Document", desc="This document was an active IRTF document, but for some reason it is no longer being pursued for the IRTF stream. It is possible that the document might be revived later, possibly in another stream.", order=13) +State.objects.get_or_create(type=irtf_type, slug="candidat", name="Candidate RG Document", desc="This document is under consideration in an RG for becoming an IRTF document. A document in this state does not imply any RG consensus and does not imply any precedence or selection. It's simply a way to indicate that somebody has asked for a document to be considered for adoption by an RG.", order=1) +State.objects.get_or_create(type=irtf_type, slug="active", name="Active RG Document", desc="This document has been adopted by the RG and is being actively developed.", order=2) +State.objects.get_or_create(type=irtf_type, slug="parked", name="Parked RG Document", desc="This document has lost its author or editor, is waiting for another document to be written, or cannot currently be worked on by the RG for some other reason.", order=3) +State.objects.get_or_create(type=irtf_type, slug="rg-lc", name="In RG Last Call", desc="The document is in its final review in the RG.", order=4) +State.objects.get_or_create(type=irtf_type, slug="sheph-w", name="Waiting for Document Shepherd", desc="IRTF documents have document shepherds who help RG documents through the process after the RG has finished with the document.", order=5) +State.objects.get_or_create(type=irtf_type, slug="chair-w", name="Waiting for IRTF Chair", desc="The IRTF Chair is meant to be performing some task such as sending a request for IESG Review.", order=6) +State.objects.get_or_create(type=irtf_type, slug="irsg-w", name="Awaiting IRSG Reviews", desc="The document shepherd has taken the document to the IRSG and solicited reviews from one or more IRSG members.", order=7) +State.objects.get_or_create(type=irtf_type, slug="irsgpoll", name="In IRSG Poll", desc="The IRSG is taking a poll on whether or not the document is ready to be published.", order=8) +State.objects.get_or_create(type=irtf_type, slug="iesg-rev", name="In IESG Review", desc="The IRSG has asked the IESG to do a review of the document, as described in RFC5742.", order=9) +State.objects.get_or_create(type=irtf_type, slug="rfc-edit", name="Sent to the RFC Editor", desc="The RG processing of this document is complete and it has been sent to the RFC Editor for publication. The document may be in the RFC Editor's queue, or it may have been published as an RFC; this state doesn't distinguish between different states occurring after the document has left the RG.", order=10) +State.objects.get_or_create(type=irtf_type, slug="pub", name="Published RFC", desc="The document has been published as an RFC.", order=11) +State.objects.get_or_create(type=irtf_type, slug="iesghold", name="Document on Hold Based On IESG Request", desc="The IESG has requested that the document be held pending further review, as specified in RFC 5742, and the IRTF has agreed to such a hold.", order=12) +State.objects.get_or_create(type=irtf_type, slug="dead", name="Dead IRTF Document", desc="This document was an active IRTF document, but for some reason it is no longer being pursued for the IRTF stream. It is possible that the document might be revived later, possibly in another stream.", order=13) # ISE print "importing ISE stream states" -State.objects.get_or_create(type=ise_state_type, slug="receive", name="Submission Received", desc="The draft has been sent to the ISE with a request for publication.", order=1) -State.objects.get_or_create(type=ise_state_type, slug="find-rev", name="Finding Reviewers", desc=" The ISE is finding initial reviewers for the document.", order=2) -State.objects.get_or_create(type=ise_state_type, slug="ise-rev", name="In ISE Review", desc="The ISE is actively working on the document.", order=3) -State.objects.get_or_create(type=ise_state_type, slug="need-res", name="Response to Review Needed", desc=" One or more reviews have been sent to the author, and the ISE is awaiting response.", order=4) -State.objects.get_or_create(type=ise_state_type, slug="iesg-rev", name="In IESG Review", desc="The ISE has asked the IESG to do a review of the document, as described in RFC5742.", order=5) -State.objects.get_or_create(type=ise_state_type, slug="rfc-edit", name="Sent to the RFC Editor", desc="The ISE processing of this document is complete and it has been sent to the RFC Editor for publication. The document may be in the RFC Editor's queue, or it may have been published as an RFC; this state doesn't distinguish between different states occurring after the document has left the ISE.", order=6) -State.objects.get_or_create(type=ise_state_type, slug="pub", name="Published RFC", desc="The document has been published as an RFC.", order=7) -State.objects.get_or_create(type=ise_state_type, slug="dead", name="No Longer In Independent Submission Stream", desc="This document was actively considered in the Independent Submission stream, but the ISE chose not to publish it. It is possible that the document might be revived later. A document in this state may have a comment explaining the reasoning of the ISE (such as if the document was going to move to a different stream).", order=8) -State.objects.get_or_create(type=ise_state_type, slug="iesghold", name="Document on Hold Based On IESG Request", desc="The IESG has requested that the document be held pending further review, as specified in RFC 5742, and the ISE has agreed to such a hold.", order=9) +State.objects.get_or_create(type=ise_type, slug="receive", name="Submission Received", desc="The draft has been sent to the ISE with a request for publication.", order=1) +State.objects.get_or_create(type=ise_type, slug="find-rev", name="Finding Reviewers", desc=" The ISE is finding initial reviewers for the document.", order=2) +State.objects.get_or_create(type=ise_type, slug="ise-rev", name="In ISE Review", desc="The ISE is actively working on the document.", order=3) +State.objects.get_or_create(type=ise_type, slug="need-res", name="Response to Review Needed", desc=" One or more reviews have been sent to the author, and the ISE is awaiting response.", order=4) +State.objects.get_or_create(type=ise_type, slug="iesg-rev", name="In IESG Review", desc="The ISE has asked the IESG to do a review of the document, as described in RFC5742.", order=5) +State.objects.get_or_create(type=ise_type, slug="rfc-edit", name="Sent to the RFC Editor", desc="The ISE processing of this document is complete and it has been sent to the RFC Editor for publication. The document may be in the RFC Editor's queue, or it may have been published as an RFC; this state doesn't distinguish between different states occurring after the document has left the ISE.", order=6) +State.objects.get_or_create(type=ise_type, slug="pub", name="Published RFC", desc="The document has been published as an RFC.", order=7) +State.objects.get_or_create(type=ise_type, slug="dead", name="No Longer In Independent Submission Stream", desc="This document was actively considered in the Independent Submission stream, but the ISE chose not to publish it. It is possible that the document might be revived later. A document in this state may have a comment explaining the reasoning of the ISE (such as if the document was going to move to a different stream).", order=8) +State.objects.get_or_create(type=ise_type, slug="iesghold", name="Document on Hold Based On IESG Request", desc="The IESG has requested that the document be held pending further review, as specified in RFC 5742, and the ISE has agreed to such a hold.", order=9) # now import the next_states; we only go for the default ones, the # WG-specific are handled in the group importer -workflows = [(ietf_state_type, workflows.models.Workflow.objects.get(name="Default WG Workflow")), - (irtf_state_type, workflows.models.Workflow.objects.get(name="IRTF Workflow")), - (ise_state_type, workflows.models.Workflow.objects.get(name="ISE Workflow")), - (iab_state_type, workflows.models.Workflow.objects.get(name="IAB Workflow")), +workflows = [(ietf_type, workflows.models.Workflow.objects.get(name="Default WG Workflow")), + (irtf_type, workflows.models.Workflow.objects.get(name="IRTF Workflow")), + (ise_type, workflows.models.Workflow.objects.get(name="ISE Workflow")), + (iab_type, workflows.models.Workflow.objects.get(name="IAB Workflow")), ] for state_type, workflow in workflows: diff --git a/redesign/name/admin.py b/redesign/name/admin.py index fccd2be08..d2ff40147 100644 --- a/redesign/name/admin.py +++ b/redesign/name/admin.py @@ -10,11 +10,7 @@ admin.site.register(GroupStateName, NameAdmin) admin.site.register(IesgGroupStateName, NameAdmin) admin.site.register(RoleName, NameAdmin) admin.site.register(DocStreamName, NameAdmin) -admin.site.register(DocStateName, NameAdmin) admin.site.register(DocRelationshipName, NameAdmin) -admin.site.register(IesgDocStateName, NameAdmin) -admin.site.register(IanaDocStateName, NameAdmin) -admin.site.register(RfcDocStateName, NameAdmin) admin.site.register(DocTypeName, NameAdmin) admin.site.register(DocTagName, NameAdmin) admin.site.register(StdLevelName, NameAdmin) diff --git a/redesign/name/fixtures/names.xml b/redesign/name/fixtures/names.xml index 84b2b07aa..43aec0224 100644 --- a/redesign/name/fixtures/names.xml +++ b/redesign/name/fixtures/names.xml @@ -78,42 +78,6 @@ 1 0 - - Active - - 1 - 0 - - - Expired - - 1 - 0 - - - RFC - - 1 - 0 - - - Withdrawn by Submitter - - 1 - 0 - - - Replaced - - 1 - 0 - - - Withdrawn by IETF - - 1 - 0 - Legacy @@ -192,6 +156,24 @@ 1 0 + + IANA coordination + RFC-Editor/IANA Registration Coordination + 1 + 0 + + + Holding for references + Holding for normative reference + 1 + 0 + + + Missing references + Awaiting missing normative reference + 1 + 0 + Point Raised - writeup needed IESG discussions on the document have raised some issues that need to be brought to the attention of the authors/WG, but those issues have not been written down yet. (It is common for discussions during a telechat to result in such situations. An AD may raise a possible issue during a telechat and only decide as a result of that discussion whether the issue is worth formally writing up and bringing to the attention of the authors/WG). A document stays in the "Point Raised - Writeup Needed" state until *ALL* IESG comments that have been raised have been documented. @@ -426,108 +408,6 @@ 1 0 - - Publication Requested - A formal request has been made to advance/publish the document, following the procedures in Section 7.5 of RFC 2418. The request could be from a WG chair, from an individual through the RFC Editor, etc. (The Secretariat (iesg-secretary@ietf.org) is copied on these requests to ensure that the request makes it into the ID tracker.) A document in this state has not (yet) been reviewed by an AD nor has any official action been taken on it yet (other than to note that its publication has been requested. - 1 - 10 - - - AD Evaluation - A specific AD (e.g., the Area Advisor for the WG) has begun reviewing the document to verify that it is ready for advancement. The shepherding AD is responsible for doing any necessary review before starting an IETF Last Call or sending the document directly to the IESG as a whole. - 1 - 11 - - - Expert Review - An AD sometimes asks for an external review by an outside party as part of evaluating whether a document is ready for advancement. MIBs, for example, are reviewed by the "MIB doctors". Other types of reviews may also be requested (e.g., security, operations impact, etc.). Documents stay in this state until the review is complete and possibly until the issues raised in the review are addressed. See the "note" field for specific details on the nature of the review. - 1 - 12 - - - Last Call Requested - The AD has requested that the Secretariat start an IETF Last Call, but the the actual Last Call message has not been sent yet. - 1 - 15 - - - In Last Call - The document is currently waiting for IETF Last Call to complete. Last Calls for WG documents typically last 2 weeks, those for individual submissions last 4 weeks. - 1 - 16 - - - Waiting for Writeup - Before a standards-track or BCP document is formally considered by the entire IESG, the AD must write up a protocol action. The protocol action is included in the approval message that the Secretariat sends out when the document is approved for publication as an RFC. - 1 - 18 - - - Waiting for AD Go-Ahead - As a result of the IETF Last Call, comments may need to be responded to and a revision of the ID may be needed as well. The AD is responsible for verifying that all Last Call comments have been adequately addressed and that the (possibly revised) document is in the ID directory and ready for consideration by the IESG as a whole. - 1 - 19 - - - IESG Evaluation - The document is now (finally!) being formally reviewed by the entire IESG. Documents are discussed in email or during a bi-weekly IESG telechat. In this phase, each AD reviews the document and airs any issues they may have. Unresolvable issues are documented as "discuss" comments that can be forwarded to the authors/WG. See the description of substates for additional details about the current state of the IESG discussion. - 1 - 20 - - - IESG Evaluation - Defer - During a telechat, one or more ADs requested an additional 2 weeks to review the document. A defer is designed to be an exception mechanism, and can only be invoked once, the first time the document comes up for discussion during a telechat. - 1 - 21 - - - Approved-announcement to be sent - The IESG has approved the document for publication, but the Secretariat has not yet sent out on official approval message. - 1 - 27 - - - Approved-announcement sent - The IESG has approved the document for publication, and the Secretariat has sent out the official approval message to the RFC editor. - 1 - 30 - - - RFC Ed Queue - The document is in the RFC editor Queue (as confirmed by http://www.rfc-editor.org/queue.html). - 1 - 31 - - - RFC Published - The ID has been published as an RFC. - 1 - 32 - - - DNP-waiting for AD note - Do Not Publish: The IESG recommends against publishing the document, but the writeup explaining its reasoning has not yet been produced. DNPs apply primarily to individual submissions received through the RFC editor. See the "note" field for more details on who has the action item. - 1 - 33 - - - DNP-announcement to be sent - The IESG recommends against publishing the document, the writeup explaining its reasoning has been produced, but the Secretariat has not yet sent out the official "do not publish" recommendation message. - 1 - 34 - - - AD is watching - An AD is aware of the document and has chosen to place the document in a separate state in order to keep a closer eye on it (for whatever reason). Documents in this state are still not being actively tracked in the sense that no formal request has been made to publish or advance the document. The sole difference between this state and "I-D Exists" is that an AD has chosen to put it in a separate state, to make it easier to keep track of (for the AD's own reasons). - 1 - 42 - - - Dead - Document is "dead" and is no longer being tracked. (E.g., it has been replaced by another document with a different name, it has been withdrawn, etc.) - 1 - 99 - Proposed Standard @@ -804,58 +684,64 @@ IAB state - + + IANA state + + + RFC state + + draft active Active 1 - 0 + 1 - + draft expired Expired 1 - 0 + 2 - + draft rfc RFC 1 - 0 + 3 - - draft - auth-rm - Withdrawn by Submitter - 1 - - 0 - - - + draft repl Replaced 1 - 0 + 4 - + + draft + auth-rm + Withdrawn by Submitter + 1 + + 5 + + + draft ietf-rm Withdrawn by IETF 1 - 0 + 6 @@ -865,7 +751,7 @@ 1 A formal request has been made to advance/publish the document, following the procedures in Section 7.5 of RFC 2418. The request could be from a WG chair, from an individual through the RFC Editor, etc. (The Secretariat (iesg-secretary@ietf.org) is copied on these requests to ensure that the request makes it into the ID tracker.) A document in this state has not (yet) been reviewed by an AD nor has any official action been taken on it yet (other than to note that its publication has been requested. 10 - + draft-iesg @@ -874,7 +760,7 @@ 1 A specific AD (e.g., the Area Advisor for the WG) has begun reviewing the document to verify that it is ready for advancement. The shepherding AD is responsible for doing any necessary review before starting an IETF Last Call or sending the document directly to the IESG as a whole. 11 - + draft-iesg @@ -883,7 +769,7 @@ 1 An AD sometimes asks for an external review by an outside party as part of evaluating whether a document is ready for advancement. MIBs, for example, are reviewed by the "MIB doctors". Other types of reviews may also be requested (e.g., security, operations impact, etc.). Documents stay in this state until the review is complete and possibly until the issues raised in the review are addressed. See the "note" field for specific details on the nature of the review. 12 - + draft-iesg @@ -928,7 +814,7 @@ 1 The document is now (finally!) being formally reviewed by the entire IESG. Documents are discussed in email or during a bi-weekly IESG telechat. In this phase, each AD reviews the document and airs any issues they may have. Unresolvable issues are documented as "discuss" comments that can be forwarded to the authors/WG. See the description of substates for additional details about the current state of the IESG discussion. 20 - + draft-iesg @@ -937,7 +823,7 @@ 1 During a telechat, one or more ADs requested an additional 2 weeks to review the document. A defer is designed to be an exception mechanism, and can only be invoked once, the first time the document comes up for discussion during a telechat. 21 - + draft-iesg @@ -946,7 +832,7 @@ 1 The IESG has approved the document for publication, but the Secretariat has not yet sent out on official approval message. 27 - + draft-iesg @@ -955,7 +841,7 @@ 1 The IESG has approved the document for publication, and the Secretariat has sent out the official approval message to the RFC editor. 30 - + draft-iesg @@ -1000,7 +886,7 @@ 1 An AD is aware of the document and has chosen to place the document in a separate state in order to keep a closer eye on it (for whatever reason). Documents in this state are still not being actively tracked in the sense that no formal request has been made to publish or advance the document. The sole difference between this state and "I-D Exists" is that an AD has chosen to put it in a separate state, to make it easier to keep track of (for the AD's own reasons). 42 - + draft-iesg @@ -1009,6 +895,105 @@ 1 Document is "dead" and is no longer being tracked. (E.g., it has been replaced by another document with a different name, it has been withdrawn, etc.) 99 + + + + draft-rfc + edit + EDIT + 1 + Approved by the stream manager (e.g., IESG, IAB, IRSG, ISE), awaiting processing and publishing + 0 + + + + draft-rfc + auth48 + AUTH48 + 1 + Awaiting final author approval + 0 + + + + draft-rfc + auth + AUTH + 1 + Awaiting author action + 0 + + + + draft-rfc + iana-crd + IANA + 1 + RFC-Editor/IANA Registration Coordination + 0 + + + + draft-rfc + iesg + IESG + 1 + Holding for IESG action + 0 + + + + draft-rfc + isr + ISR + 1 + Independent Submission Review by the ISE + 0 + + + + draft-rfc + isr-auth + ISR-AUTH + 1 + Independent Submission awaiting author update, or in discussion between author and ISE + 0 + + + + draft-rfc + ref + REF + 1 + Holding for normative reference + 0 + + + + draft-rfc + rfc-edit + RFC-EDITOR + 1 + Awaiting final RFC Editor review before AUTH48 + 0 + + + + draft-rfc + timeout + TO + 1 + Time-out period during which the IESG reviews document for conflict/concurrence with other IETF working group work + 0 + + + + draft-rfc + missref + MISSREF + 1 + Awaiting missing normative reference + 0 @@ -1165,7 +1150,7 @@ Under normal conditions, it should not be possible for an I-D to be in the "WG Document" state in more than one WG at a time. This said, I-Ds may be transferred from one WG to another with the consent of the WG Chairs and the responsible ADs. 4 - + draft-stream-ietf @@ -1214,7 +1199,7 @@ It is possible for one WGLC to lead into another WGLC for the same document. For example, an I-D that completed a WGLC as an "Informational" document may need another WGLC if a decision is taken to convert the I-D into a Standards Track document. 7 - + draft-stream-ietf @@ -1225,6 +1210,19 @@ A WG Chair may wish to place an I-D that receives a lot of comments during a WGLC into the "Waiting for WG Chair Go-Ahead" state. This state describes an I-D that has undergone a WGLC; however, the Chair is not yet ready to call consensus on the document. + If comments from the WGLC need to be responded to, or a revision to the I-D is needed, the Chair may place an I-D into this state until all of the WGLC comments are adequately addressed and the (possibly revised) document is in the I-D repository. + 8 + + + + draft-stream-ietf + chair-w + Waiting for WG Chair Go-Ahead + 1 + <a href="http://tools.ietf.org/html/rfc6174#section-4.2.8" target="_blank">4.2.8. Waiting for WG Chair Go-Ahead</a> + + A WG Chair may wish to place an I-D that receives a lot of comments during a WGLC into the "Waiting for WG Chair Go-Ahead" state. This state describes an I-D that has undergone a WGLC; however, the Chair is not yet ready to call consensus on the document. + If comments from the WGLC need to be responded to, or a revision to the I-D is needed, the Chair may place an I-D into this state until all of the WGLC comments are adequately addressed and the (possibly revised) document is in the I-D repository. 8 @@ -1240,6 +1238,21 @@ A WG Chair may call consensus on an I-D without a formal WGLC and transition an I-D that was in the "WG Document" state directly into this state. + The name of this state includes the words "Waiting for Writeup" because a good document shepherd writeup takes time to prepare. + 9 + + + + draft-stream-ietf + writeupw + WG Consensus: Waiting for Write-Up + 1 + <a href="http://tools.ietf.org/html/rfc6174#section-4.2.9" target="_blank">4.2.9. WG Consensus: Waiting for Writeup</a> + + A document in the "WG Consensus: Waiting for Writeup" state has essentially completed its development within the working group, and is nearly ready to be sent to the IESG for publication. The last thing to be done is the preparation of a protocol writeup by a Document Shepherd. The IESG requires that a document shepherd writeup be completed before publication of the I-D is requested. The IETF document shepherding process and the role of a WG Document Shepherd is described in RFC 4858 [RFC4858] + + A WG Chair may call consensus on an I-D without a formal WGLC and transition an I-D that was in the "WG Document" state directly into this state. + The name of this state includes the words "Waiting for Writeup" because a good document shepherd writeup takes time to prepare. 9 @@ -1255,7 +1268,7 @@ An I-D in this state may be under review by the IESG, it may have been approved and be in the RFC Editor's queue, or it may have been published as an RFC. Other possibilities exist too. The document may be "Dead" (in the IESG state machine) or in a "Do Not Publish" state. 10 - + draft-stream-irtf diff --git a/redesign/name/models.py b/redesign/name/models.py index f89a01372..39e8ce067 100644 --- a/redesign/name/models.py +++ b/redesign/name/models.py @@ -29,22 +29,9 @@ class RoleName(NameModel): """AD, Chair""" class DocStreamName(NameModel): """IETF, IAB, IRTF, ISE, Legacy""" -class DocStateName(NameModel): - """Active, Expired, RFC, Replaced, Withdrawn""" class DocRelationshipName(NameModel): """Updates, Replaces, Obsoletes, Reviews, ... The relationship is - always recorded in one direction. - """ -class IesgDocStateName(NameModel): - """Pub Request, Ad Eval, Expert Review, Last Call Requested, In - Last Call, Waiting for Writeup, Waiting for AD Go-Ahead, IESG - Evaluation, Deferred, Approved, Announcement Sent, Do Not Publish, - Ad is watching, Dead """ -class IanaDocStateName(NameModel): - """ """ -class RfcDocStateName(NameModel): - """Missref, Edit, RFC-Editor, Auth48, Auth, Published; ISR, - ISR-Auth, ISR-Timeout;""" + always recorded in one direction.""" class DocTypeName(NameModel): """Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email, Review, Issue, Wiki""" @@ -60,7 +47,7 @@ class IntendedStdLevelName(NameModel): class DocReminderTypeName(NameModel): "Stream state" class BallotPositionName(NameModel): - """ Yes, NoObjection, Abstain, Discuss, Recuse """ + """ Yes, No Objection, Abstain, Discuss, Recuse """ class MeetingTypeName(NameModel): """IETF, Interim""" class SessionStatusName(NameModel): @@ -71,31 +58,3 @@ class ConstraintName(NameModel): """Conflict""" class LiaisonStatementPurposeName(NameModel): """For action, For comment, For information, In response, Other""" - - -def get_next_iesg_states(iesg_state): - if not iesg_state: - return () - - next = { - "pub-req": ("ad-eval", "watching", "dead"), - "ad-eval": ("watching", "lc-req", "review-e", "iesg-eva"), - "review-e": ("ad-eval", ), - "lc-req": ("lc", ), - "lc": ("writeupw", "goaheadw"), - "writeupw": ("goaheadw", ), - "goaheadw": ("iesg-eva", ), - "iesg-eva": ("nopubadw", "defer", "ann"), - "defer": ("iesg-eva", ), - "ann": ("approved", ), - "approved": ("rfcqueue", ), - "rfcqueue": ("pub", ), - "pub": ("dead", ), - "nopubadw": ("nopubanw", ), - "nopubanw": ("dead", ), - "watching": ("pub-req", ), - "dead": ("pub-req", ), - } - - return IesgDocStateName.objects.filter(slug__in=next.get(iesg_state.slug, ())) - diff --git a/redesign/name/proxy.py b/redesign/name/proxy.py index bca9861d5..2b8a064fd 100644 --- a/redesign/name/proxy.py +++ b/redesign/name/proxy.py @@ -1,85 +1,6 @@ from redesign.proxy_utils import TranslatingManager from models import * -class IDStatus(DocStateName): - def from_object(self, base): - for f in base._meta.fields: - setattr(self, f.name, getattr(base, f.name)) - return self - - #status_id = models.AutoField(primary_key=True) - - #status = models.CharField(max_length=25, db_column='status_value') - @property - def status(self): - return self.name - - def __unicode__(self): - return super(self.__class__, self).__unicode__() - - class Meta: - proxy = True - -class IDState(IesgDocStateName): - PUBLICATION_REQUESTED = 10 - LAST_CALL_REQUESTED = 15 - IN_LAST_CALL = 16 - WAITING_FOR_WRITEUP = 18 - WAITING_FOR_AD_GO_AHEAD = 19 - IESG_EVALUATION = 20 - IESG_EVALUATION_DEFER = 21 - APPROVED_ANNOUNCEMENT_SENT = 30 - AD_WATCHING = 42 - DEAD = 99 - DO_NOT_PUBLISH_STATES = (33, 34) - - objects = TranslatingManager(dict(pk="order", - document_state_id="order", - document_state_id__in="order__in")) - - def from_object(self, base): - for f in base._meta.fields: - setattr(self, f.name, getattr(base, f.name)) - return self - - #document_state_id = models.AutoField(primary_key=True) - @property - def document_state_id(self): - return self.order - - #state = models.CharField(max_length=50, db_column='document_state_val') - @property - def state(self): - return self.name - - #equiv_group_flag = models.IntegerField(null=True, blank=True) # unused - #description = models.TextField(blank=True, db_column='document_desc') - @property - def description(self): - return self.desc - - @property - def nextstate(self): - # simulate related queryset - from name.models import get_next_iesg_states - return IDState.objects.filter(pk__in=[x.pk for x in get_next_iesg_states(self)]) - - @property - def next_state(self): - # simulate IDNextState - return self - - def __str__(self): - return self.state - - @staticmethod - def choices(): - return [(state.slug, state.name) for state in IDState.objects.all()] - - class Meta: - proxy = True - - class IDSubStateManager(TranslatingManager): def __init__(self, *args): super(IDSubStateManager, self).__init__(*args) diff --git a/redesign/person/models.py b/redesign/person/models.py index c906270b1..e131642b1 100644 --- a/redesign/person/models.py +++ b/redesign/person/models.py @@ -63,7 +63,7 @@ class Person(PersonInfo): def person(self): # little temporary wrapper to help porting to new schema return self - + class PersonHistory(PersonInfo): person = models.ForeignKey(Person, related_name="history_set") user = models.ForeignKey(User, blank=True, null=True) diff --git a/redesign/proxy_utils.py b/redesign/proxy_utils.py index 1a7c701ba..5f3d23ea0 100644 --- a/redesign/proxy_utils.py +++ b/redesign/proxy_utils.py @@ -12,6 +12,9 @@ def proxy_role_email(e): e.person.email = lambda: (e.person.name, e.address) return e +def chunks(l, n): + """Split list l up in chunks of max size n.""" + return (l[i:i+n] for i in range(0, len(l), n)) class TranslatingQuerySet(QuerySet): def translated_args(self, args): @@ -42,10 +45,13 @@ class TranslatingQuerySet(QuerySet): if k in trans: t = trans[k] if callable(t): - t, v = t(v) + ts = t(v) + else: + ts = (t, v) - if t: - res[t] = v + for t, v in chunks(ts, 2): + if t: + res[t] = v else: res[k] = v return res