Port change_state view + helpers + tests to new schema, retaining the old view via settings; adjusted relationship model to use source/target as attribute names
- Legacy-Id: 2808
This commit is contained in:
parent
294740d270
commit
d0f3b5e628
414
ietf/idrfc/fixtures/names.xml
Normal file
414
ietf/idrfc/fixtures/names.xml
Normal file
|
@ -0,0 +1,414 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<django-objects version="1.0">
|
||||
<object pk="yes" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Yes</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="noobj" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">No Objection</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="abstain" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Abstain</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="discuss" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Discuss</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="recuse" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Recuse</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="norecord" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">No record</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="extpty" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">External Party</field>
|
||||
<field type="TextField" name="desc">The document is awaiting review or input from an external party (i.e, someone other than the shepherding AD, the authors, or the WG). See the "note" field for more details on who has the action.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="need-rev" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">Revised ID Needed</field>
|
||||
<field type="TextField" name="desc">An updated ID is needed to address the issues that have been raised.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="iana-crd" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">IANA-coord</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ad-f-up" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">AD Followup</field>
|
||||
<field type="TextField" name="desc">A generic substate indicating that the shepherding AD has the action item to determine appropriate next steps. In particular, the appropriate steps (and the corresponding next state or substate) depend entirely on the nature of the issues that were raised and can only be decided with active involvement of the shepherding AD. Examples include:
|
||||
|
||||
- if another AD raises an issue, the shepherding AD may first iterate with the other AD to get a better understanding of the exact issue. Or, the shepherding AD may attempt to argue that the issue is not serious enough to bring to the attention of the authors/WG.
|
||||
|
||||
- if a documented issue is forwarded to a WG, some further iteration may be needed before it can be determined whether a new revision is needed or whether the WG response to an issue clarifies the issue sufficiently.
|
||||
|
||||
- when a new revision appears, the shepherding AD will first look at the changes to determine whether they believe all outstanding issues have been raised satisfactorily, prior to asking the ADs who raised the original issues to verify the changes.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="point" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">Point Raised - writeup needed</field>
|
||||
<field type="TextField" name="desc">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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="missref" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">MissingRef</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="fasttrac" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">FastTrack</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="rfc-rev" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">Review by RFC Editor</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="via-rfc" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">Via RFC Editor</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="exp-tomb" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">Expired tombstone</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="app-min" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">Approved in minute</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="errata" model="name.docinfotagname">
|
||||
<field type="CharField" name="name">Has errata</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="updates" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">Updates</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="replaces" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">Replaces</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="obs" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">Obsoletes</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="reviews" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">Reviews</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="refs" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">References</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="rfc" model="name.docstatename">
|
||||
<field type="CharField" name="name">RFC</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="expired" model="name.docstatename">
|
||||
<field type="CharField" name="name">Expired</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="repl" model="name.docstatename">
|
||||
<field type="CharField" name="name">Replaced</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="active" model="name.docstatename">
|
||||
<field type="CharField" name="name">Active</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="auth-rm" model="name.docstatename">
|
||||
<field type="CharField" name="name">Withdrawn by Submitter</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ietf-rm" model="name.docstatename">
|
||||
<field type="CharField" name="name">Withdrawn by IETF</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ietf" model="name.docstreamname">
|
||||
<field type="CharField" name="name">IETF</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="indie" model="name.docstreamname">
|
||||
<field type="CharField" name="name">Independent Submission</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="legacy" model="name.docstreamname">
|
||||
<field type="CharField" name="name">Legacy</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="iab" model="name.docstreamname">
|
||||
<field type="CharField" name="name">IAB</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="irtf" model="name.docstreamname">
|
||||
<field type="CharField" name="name">IRTF</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="draft" model="name.doctypename">
|
||||
<field type="CharField" name="name">Draft</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ext" model="name.doctypename">
|
||||
<field type="CharField" name="name">External</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="bof" model="name.groupstatename">
|
||||
<field type="CharField" name="name">BOF</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="proposed" model="name.groupstatename">
|
||||
<field type="CharField" name="name">Proposed</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="active" model="name.groupstatename">
|
||||
<field type="CharField" name="name">Active</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="dormant" model="name.groupstatename">
|
||||
<field type="CharField" name="name">Dormant</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="conclude" model="name.groupstatename">
|
||||
<field type="CharField" name="name">Concluded</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="unknown" model="name.groupstatename">
|
||||
<field type="CharField" name="name">Unknown</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ietf" model="name.grouptypename">
|
||||
<field type="CharField" name="name">IETF</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="area" model="name.grouptypename">
|
||||
<field type="CharField" name="name">Area</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="wg" model="name.grouptypename">
|
||||
<field type="CharField" name="name">WG</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="rg" model="name.grouptypename">
|
||||
<field type="CharField" name="name">RG</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="team" model="name.grouptypename">
|
||||
<field type="CharField" name="name">Team</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="individ" model="name.grouptypename">
|
||||
<field type="CharField" name="name">Individual</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="pub" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">RFC Published</field>
|
||||
<field type="TextField" name="desc">The ID has been published as an RFC.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="dead" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Dead</field>
|
||||
<field type="TextField" name="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.)</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ann" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Approved-announcement sent</field>
|
||||
<field type="TextField" name="desc">The IESG has approved the document for publication, and the Secretariat has sent out the official approval message to the RFC editor.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="watching" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">AD is watching</field>
|
||||
<field type="TextField" name="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).</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="iesg-eva" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">IESG Evaluation</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ad-eval" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">AD Evaluation</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="lc" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">In Last Call</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="pub-req" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Publication Requested</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="rfcqueue" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">RFC Ed Queue</field>
|
||||
<field type="TextField" name="desc">The document is in the RFC editor Queue (as confirmed by http://www.rfc-editor.org/queue.html).</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="defer" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">IESG Evaluation - Defer</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="writeupw" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Waiting for Writeup</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="goaheadw" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Waiting for AD Go-Ahead</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="approved" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Approved-announcement to be sent</field>
|
||||
<field type="TextField" name="desc">The IESG has approved the document for publication, but the Secretariat has not yet sent out on official approval message.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="review-e" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Expert Review</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="nopubadw" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">DNP-waiting for AD note</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="lc-req" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">Last Call requested</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="nopubanw" model="name.iesgdocstatename">
|
||||
<field type="CharField" name="name">DNP-announcement to be sent</field>
|
||||
<field type="TextField" name="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.</field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="bcp" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Best Current Practice</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ds" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Draft Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="exp" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Experimental</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="hist" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Historic</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="inf" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Informational</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ps" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Proposed Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="std" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ad" model="name.rolename">
|
||||
<field type="CharField" name="name">Area Director</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="std" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ds" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Draft Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="ps" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Proposed Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="inf" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Informational</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="exp" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Experimental</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="bcp" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Best Current Practice</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="hist" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Historic</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
<object pk="unkn" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Unknown</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">1</field>
|
||||
</object>
|
||||
</django-objects>
|
40
ietf/idrfc/generate_fixturesREDESIGN.py
Executable file
40
ietf/idrfc/generate_fixturesREDESIGN.py
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# boiler plate
|
||||
import os, sys
|
||||
|
||||
one_dir_up = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../'))
|
||||
|
||||
sys.path.insert(0, one_dir_up)
|
||||
|
||||
from django.core.management import setup_environ
|
||||
import settings
|
||||
setup_environ(settings)
|
||||
|
||||
# script
|
||||
from django.core.serializers import serialize
|
||||
from django.db.models import Q
|
||||
|
||||
def output(name, qs):
|
||||
try:
|
||||
f = open(os.path.join(settings.BASE_DIR, "idrfc/fixtures/%s.xml" % name), 'w')
|
||||
f.write(serialize("xml", qs, indent=4))
|
||||
f.close()
|
||||
except:
|
||||
from django.db import connection
|
||||
from pprint import pprint
|
||||
pprint(connection.queries)
|
||||
raise
|
||||
|
||||
# pick all name models directly out of the module
|
||||
names = []
|
||||
|
||||
import name.models
|
||||
for n in dir(name.models):
|
||||
if n[:1].upper() == n[:1] and n.endswith("Name"):
|
||||
model = getattr(name.models, n)
|
||||
if not model._meta.abstract:
|
||||
names.extend(model.objects.all())
|
||||
|
||||
output("names", names)
|
||||
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.idtracker.models import InternetDraft, DocumentComment, BallotInfo, IESGLogin
|
||||
from ietf.idrfc.mails import *
|
||||
from ietf.idrfc.utils import *
|
||||
from doc.models import Event
|
||||
|
||||
def request_last_call(request, doc):
|
||||
try:
|
||||
|
@ -15,6 +18,26 @@ def request_last_call(request, doc):
|
|||
send_last_call_request(request, doc, ballot)
|
||||
add_document_comment(request, doc, "Last Call was requested")
|
||||
|
||||
def request_last_callREDESIGN(request, doc):
|
||||
if not doc.latest_event(type="changed_ballot_writeup_text"):
|
||||
generate_ballot_writeup(request, doc)
|
||||
if not doc.latest_event(type="changed_ballot_approval_text"):
|
||||
generate_approval_mail(request, doc)
|
||||
if not doc.latest_event(type="changed_last_call_text"):
|
||||
generate_last_call_announcement(request, doc)
|
||||
|
||||
send_last_call_request(request, doc)
|
||||
|
||||
e = Event()
|
||||
e.type = "requested_last_call"
|
||||
e.by = request.user.get_profile().email()
|
||||
e.doc = doc
|
||||
e.desc = "Last call was requested by %s" % e.by.get_name()
|
||||
e.save()
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
request_last_call = request_last_callREDESIGN
|
||||
|
||||
def get_expired_last_calls():
|
||||
return InternetDraft.objects.filter(lc_expiration_date__lte=datetime.date.today(),
|
||||
idinternal__cur_state__document_state_id=IDState.IN_LAST_CALL)
|
||||
|
|
|
@ -9,6 +9,8 @@ from django.conf import settings
|
|||
|
||||
from ietf.utils.mail import send_mail, send_mail_text
|
||||
from ietf.idtracker.models import *
|
||||
from doc.models import Text
|
||||
from person.models import Email
|
||||
|
||||
def email_state_changed(request, doc, text):
|
||||
to = [x.strip() for x in doc.idinternal.state_change_notice_to.replace(';', ',').split(',')]
|
||||
|
@ -18,6 +20,17 @@ def email_state_changed(request, doc, text):
|
|||
dict(text=text,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
||||
|
||||
def email_state_changedREDESIGN(request, doc, text):
|
||||
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
|
||||
send_mail(request, to, None,
|
||||
"ID Tracker State Update Notice: %s" % doc.file_tag(),
|
||||
"idrfc/state_changed_email.txt",
|
||||
dict(text=text,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
email_state_changed = email_state_changedREDESIGN
|
||||
|
||||
def html_to_text(html):
|
||||
return strip_tags(html.replace("<", "<").replace(">", ">").replace("&", "&").replace("<br>", "\n"))
|
||||
|
||||
|
@ -34,6 +47,23 @@ def email_owner(request, doc, owner, changed_by, text, subject=None):
|
|||
doc=doc,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
||||
|
||||
def email_ownerREDESIGN(request, doc, owner, changed_by, text, subject=None):
|
||||
if not owner or not changed_by or owner == changed_by:
|
||||
return
|
||||
|
||||
to = owner.formatted_email()
|
||||
send_mail(request, to,
|
||||
"DraftTracker Mail System <iesg-secretary@ietf.org>",
|
||||
"%s updated by %s" % (doc.file_tag(), changed_by),
|
||||
"idrfc/change_notice.txt",
|
||||
dict(text=html_to_text(text),
|
||||
doc=doc,
|
||||
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
email_owner = email_ownerREDESIGN
|
||||
|
||||
|
||||
def full_intended_status(intended_status):
|
||||
s = str(intended_status)
|
||||
# FIXME: this should perhaps be defined in the db
|
||||
|
@ -54,6 +84,15 @@ def full_intended_status(intended_status):
|
|||
else:
|
||||
return "a %s" % s
|
||||
|
||||
def generate_ballot_writeup(request, doc):
|
||||
e = Text()
|
||||
e.type = "changed_ballot_writeup_text"
|
||||
e.by = request.user.get_profile().email()
|
||||
e.doc = doc
|
||||
e.desc = u"Ballot writeup was generated by %s" % e.by.get_name()
|
||||
e.content = unicode(render_to_string("idrfc/ballot_writeup.txt"))
|
||||
e.save()
|
||||
|
||||
def generate_last_call_announcement(request, doc):
|
||||
status = full_intended_status(doc.intended_status).replace("a ", "").replace("an ", "")
|
||||
|
||||
|
@ -86,6 +125,49 @@ def generate_last_call_announcement(request, doc):
|
|||
)
|
||||
)
|
||||
|
||||
def generate_last_call_announcementREDESIGN(request, doc):
|
||||
doc.full_status = full_intended_status(doc.intended_std_level)
|
||||
status = doc.full_status.replace("a ", "").replace("an ", "")
|
||||
|
||||
expiration_date = date.today() + timedelta(days=14)
|
||||
cc = []
|
||||
if doc.group.type_id == "individ":
|
||||
group = "an individual submitter"
|
||||
expiration_date += timedelta(days=14)
|
||||
else:
|
||||
group = "the %s WG (%s)" % (doc.group.name, doc.group.acronym)
|
||||
if doc.group.list_email:
|
||||
cc.append(doc.group.list_email)
|
||||
|
||||
doc.filled_title = textwrap.fill(doc.title, width=70, subsequent_indent=" " * 3)
|
||||
url = settings.IDTRACKER_BASE_URL + doc.get_absolute_url()
|
||||
|
||||
mail = render_to_string("idrfc/last_call_announcement.txt",
|
||||
dict(doc=doc,
|
||||
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
||||
expiration_date=expiration_date.strftime("%Y-%m-%d"), #.strftime("%B %-d, %Y"),
|
||||
cc=", ".join("<%s>" % e for e in cc),
|
||||
group=group,
|
||||
docs=[doc],
|
||||
urls=[url],
|
||||
status=status,
|
||||
impl_report="Draft" in status or "Full" in status,
|
||||
)
|
||||
)
|
||||
|
||||
from doc.models import Text
|
||||
e = Text()
|
||||
e.type = "changed_last_call_text"
|
||||
e.by = request.user.get_profile().email()
|
||||
e.doc = doc
|
||||
e.desc = u"Last call announcement was generated by %s" % e.by.get_name()
|
||||
e.content = unicode(mail)
|
||||
e.save()
|
||||
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
generate_last_call_announcement = generate_last_call_announcementREDESIGN
|
||||
|
||||
def generate_approval_mail(request, doc):
|
||||
if doc.idinternal.cur_state_id in IDState.DO_NOT_PUBLISH_STATES or doc.idinternal.via_rfc_editor:
|
||||
return generate_approval_mail_rfc_editor(request, doc)
|
||||
|
@ -114,7 +196,7 @@ def generate_approval_mail(request, doc):
|
|||
if len(docs) > 1:
|
||||
made_by = "These documents have been reviewed in the IETF but are not the products of an IETF Working Group."
|
||||
else:
|
||||
made_by = "This document has been reviewed in the IETF but is not the product of an IETF Working Group.";
|
||||
made_by = "This document has been reviewed in the IETF but is not the product of an IETF Working Group."
|
||||
else:
|
||||
if len(docs) > 1:
|
||||
made_by = "These documents are products of the %s." % doc.group.name_with_wg
|
||||
|
@ -159,6 +241,95 @@ 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'):
|
||||
mail = generate_approval_mail_rfc_editor(request, doc)
|
||||
else:
|
||||
mail = generate_approval_mail_approved(request, doc)
|
||||
|
||||
from doc.models import Text
|
||||
e = Text()
|
||||
e.type = "changed_ballot_approval_text"
|
||||
e.by = request.user.get_profile().email()
|
||||
e.doc = doc
|
||||
e.desc = u"Ballot approval text was generated by %s" % e.by.get_name()
|
||||
e.content = unicode(mail)
|
||||
e.save()
|
||||
|
||||
def generate_approval_mail_approved(request, doc):
|
||||
doc.full_status = full_intended_status(doc.intended_std_level.name)
|
||||
status = doc.full_status.replace("a ", "").replace("an ", "")
|
||||
|
||||
if "an " in status:
|
||||
action_type = "Document"
|
||||
else:
|
||||
action_type = "Protocol"
|
||||
|
||||
cc = ["Internet Architecture Board <iab@iab.org>", "RFC Editor <rfc-editor@rfc-editor.org>"]
|
||||
|
||||
# the second check catches some area working groups (like
|
||||
# Transport Area Working Group)
|
||||
if doc.group.type_id != "area" and not doc.group.name.endswith("Working Group"):
|
||||
doc.group.name_with_wg = doc.group.name + " Working Group"
|
||||
if doc.group.list_email:
|
||||
cc.append("%s mailing list <%s>" % (doc.group.acronym, doc.group.list_email))
|
||||
cc.append("%s chair <%s-chairs@tools.ietf.org>" % (doc.group.acronym, doc.group.acronym))
|
||||
else:
|
||||
doc.group.name_with_wg = doc.group.name
|
||||
|
||||
doc.filled_title = textwrap.fill(doc.title, width=70, subsequent_indent=" " * 3)
|
||||
|
||||
if doc.group.type_id == "individ":
|
||||
made_by = "This document has been reviewed in the IETF but is not the product of an IETF Working Group."
|
||||
else:
|
||||
made_by = "This document is the product of the %s." % doc.group.name_with_wg
|
||||
|
||||
director = doc.ad
|
||||
other_director = Email.objects.filter(role__group__role__email=director, role__group__role__name="ad").exclude(pk=director.pk)
|
||||
|
||||
if doc.group.type_id != "individ" and other_director:
|
||||
contacts = "The IESG contact persons are %s and %s." % (director.get_name(), other_director[0].get_name())
|
||||
else:
|
||||
contacts = "The IESG contact person is %s." % director.get_name()
|
||||
|
||||
doc_type = "RFC" if doc.state_id == "rfc" else "Internet Draft"
|
||||
|
||||
return render_to_string("idrfc/approval_mail.txt",
|
||||
dict(doc=doc,
|
||||
docs=[doc],
|
||||
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
||||
cc=",\n ".join(cc),
|
||||
doc_type=doc_type,
|
||||
made_by=made_by,
|
||||
contacts=contacts,
|
||||
status=status,
|
||||
action_type=action_type,
|
||||
)
|
||||
)
|
||||
|
||||
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 in DO_NOT_PUBLISH_IESG_STATES
|
||||
doc_type = "RFC" if doc.state_id == "rfc" else "Internet Draft"
|
||||
|
||||
return render_to_string("idrfc/approval_mail_rfc_editor.txt",
|
||||
dict(doc=doc,
|
||||
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
|
||||
doc_type=doc_type,
|
||||
status=status,
|
||||
full_status=full_status,
|
||||
disapproved=disapproved,
|
||||
)
|
||||
)
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
generate_approval_mail = generate_approval_mailREDESIGN
|
||||
generate_approval_mail_rfc_editor = generate_approval_mail_rfc_editorREDESIGN
|
||||
|
||||
|
||||
def send_last_call_request(request, doc, ballot):
|
||||
to = "iesg-secretary@ietf.org"
|
||||
frm = '"DraftTracker Mail System" <iesg-secretary@ietf.org>'
|
||||
|
@ -170,6 +341,19 @@ def send_last_call_request(request, doc, ballot):
|
|||
dict(docs=docs,
|
||||
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
||||
|
||||
def send_last_call_requestREDESIGN(request, doc):
|
||||
to = "iesg-secretary@ietf.org"
|
||||
frm = '"DraftTracker Mail System" <iesg-secretary@ietf.org>'
|
||||
|
||||
send_mail(request, to, frm,
|
||||
"Last Call: %s" % doc.file_tag(),
|
||||
"idrfc/last_call_request.txt",
|
||||
dict(docs=[doc],
|
||||
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
send_last_call_request = send_last_call_requestREDESIGN
|
||||
|
||||
def email_resurrect_requested(request, doc, by):
|
||||
to = "I-D Administrator <internet-drafts@ietf.org>"
|
||||
frm = u"%s <%s>" % by.person.email()
|
||||
|
|
|
@ -1277,3 +1277,5 @@ class MirrorScriptTestCases(unittest.TestCase,RealDatabaseTest):
|
|||
self.assertEquals(len(refs), 3)
|
||||
print "OK"
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from testsREDESIGN import *
|
||||
|
|
1428
ietf/idrfc/testsREDESIGN.py
Normal file
1428
ietf/idrfc/testsREDESIGN.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -22,6 +22,8 @@ from ietf.idrfc.mails import *
|
|||
from ietf.idrfc.utils import *
|
||||
from ietf.idrfc.lastcall import request_last_call
|
||||
|
||||
from doc.models import Document, Event, save_document_in_history, DocHistory
|
||||
from name.models import IesgDocStateName, get_next_iesg_states
|
||||
|
||||
class ChangeStateForm(forms.Form):
|
||||
state = forms.ModelChoiceField(IDState.objects.all(), empty_label=None, required=True)
|
||||
|
@ -56,7 +58,8 @@ def change_state(request, name):
|
|||
request_last_call(request, doc)
|
||||
|
||||
return render_to_response('idrfc/last_call_requested.html',
|
||||
dict(doc=doc),
|
||||
dict(doc=doc,
|
||||
url=doc.idinternal.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
return HttpResponseRedirect(internal.get_absolute_url())
|
||||
|
@ -77,6 +80,79 @@ def change_state(request, name):
|
|||
next_states=next_states),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class ChangeStateFormREDESIGN(forms.Form):
|
||||
state = forms.ModelChoiceField(IesgDocStateName.objects.all(), empty_label=None, required=True)
|
||||
# FIXME: no tags yet
|
||||
#substate = forms.ModelChoiceField(IDSubState.objects.all(), required=False)
|
||||
|
||||
@group_required('Area_Director','Secretariat')
|
||||
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":
|
||||
raise Http404()
|
||||
|
||||
login = request.user.get_profile().email()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ChangeStateForm(request.POST)
|
||||
if form.is_valid():
|
||||
state = form.cleaned_data['state']
|
||||
if state != doc.iesg_state:
|
||||
save_document_in_history(doc)
|
||||
|
||||
prev_state = doc.iesg_state
|
||||
doc.iesg_state = state
|
||||
|
||||
e = Event()
|
||||
e.type = "changed_document"
|
||||
e.by = login
|
||||
e.doc = doc
|
||||
e.desc = u"State changed to <b>%s</b> from <b>%s</b> by %s" % (
|
||||
doc.iesg_state.name,
|
||||
prev_state.name if prev_state else "None",
|
||||
login.get_name())
|
||||
e.save()
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
email_state_changed(request, doc, strip_tags(e.desc))
|
||||
email_owner(request, doc, doc.ad, login, e.desc)
|
||||
|
||||
if doc.iesg_state_id == "lc-req":
|
||||
request_last_call(request, doc)
|
||||
|
||||
return render_to_response('idrfc/last_call_requested.html',
|
||||
dict(doc=doc,
|
||||
url=doc.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
||||
else:
|
||||
form = ChangeStateForm(initial=dict(state=doc.iesg_state_id))
|
||||
|
||||
next_states = get_next_iesg_states(doc.iesg_state)
|
||||
prev_state = None
|
||||
|
||||
hists = DocHistory.objects.filter(doc=doc).exclude(iesg_state=doc.iesg_state).order_by("-time")[:1]
|
||||
if hists:
|
||||
prev_state = hists[0].iesg_state
|
||||
|
||||
return render_to_response('idrfc/change_stateREDESIGN.html',
|
||||
dict(form=form,
|
||||
doc=doc,
|
||||
prev_state=prev_state,
|
||||
next_states=next_states),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
change_state = change_stateREDESIGN
|
||||
ChangeStateForm = ChangeStateFormREDESIGN
|
||||
|
||||
|
||||
def dehtmlify_textarea_text(s):
|
||||
return s.replace("<br>", "\n").replace("<b>", "").replace("</b>", "").replace(" ", " ")
|
||||
|
||||
|
|
|
@ -409,16 +409,16 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|||
r.obsoleted_by_list = []
|
||||
r.updated_by_list = []
|
||||
|
||||
xed_by = RelatedDocument.objects.filter(doc_alias__name__in=rfc_aliases.values(), relationship__in=("obs", "updates")).select_related('doc_alias__document_id')
|
||||
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[rel.document_id for rel in xed_by]).values_list('document_id', 'name'))
|
||||
xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(), relationship__in=("obs", "updates")).select_related('target__document_id')
|
||||
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name'))
|
||||
for rel in xed_by:
|
||||
r = result_map[rel.doc_alias.document_id]
|
||||
r = result_map[rel.target.document_id]
|
||||
if rel.relationship_id == "obs":
|
||||
attr = "obsoleted_by_list"
|
||||
else:
|
||||
attr = "updated_by_list"
|
||||
|
||||
getattr(r, attr).append(int(rel_rfc_aliases[rel.document_id][3:]))
|
||||
getattr(r, attr).append(int(rel_rfc_aliases[rel.source_id][3:]))
|
||||
|
||||
|
||||
# sort
|
||||
|
|
|
@ -249,11 +249,11 @@ class PersonOrOrgInfo(models.Model):
|
|||
date_created = models.DateField(auto_now_add=True, null=True)
|
||||
created_by = models.CharField(blank=True, null=True, max_length=8)
|
||||
address_type = models.CharField(blank=True, null=True, max_length=4)
|
||||
def save(self):
|
||||
def save(self, **kwargs):
|
||||
self.first_name_key = self.first_name.upper()
|
||||
self.middle_initial_key = self.middle_initial.upper()
|
||||
self.last_name_key = self.last_name.upper()
|
||||
super(PersonOrOrgInfo, self).save()
|
||||
super(PersonOrOrgInfo, self).save(**kwargs)
|
||||
def __str__(self):
|
||||
# For django.VERSION 0.96
|
||||
if self.first_name == '' and self.last_name == '':
|
||||
|
|
|
@ -61,6 +61,11 @@ class IetfUserProfile(models.Model):
|
|||
except:
|
||||
return None
|
||||
|
||||
def email(self):
|
||||
# quick hack to bind new and old schema together for the time being
|
||||
from person.models import Email
|
||||
return Email.objects.get(address=self.person().email()[1])
|
||||
|
||||
def __str__(self):
|
||||
return "IetfUserProfile(%s)" % (self.user,)
|
||||
|
||||
|
|
64
ietf/templates/idrfc/change_stateREDESIGN.html
Normal file
64
ietf/templates/idrfc/change_stateREDESIGN.html
Normal file
|
@ -0,0 +1,64 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Change state of {{ doc }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form.change-state select {
|
||||
width: 22em;
|
||||
}
|
||||
form.change-state .actions {
|
||||
text-align: right;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.next-states,
|
||||
.prev-state {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.next-states form,
|
||||
.prev-state form {
|
||||
display: inline;
|
||||
margin-right: 10px;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Change state of {{ doc }}</h1>
|
||||
|
||||
<p class="helptext">For help on the states, see the <a href="{% url help_states %}">state table</a>.</p>
|
||||
|
||||
<form class="change-state" action="" method="post">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
<tr>
|
||||
<td colspan="2" class="actions">
|
||||
<a href="{{ doc.get_absolute_url }}">Back</a>
|
||||
<input type="submit" value="Save"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
{% if next_states %}
|
||||
<h3>Or jump directly to</h3>
|
||||
|
||||
<div class="next-states">
|
||||
{% for n in next_states %}
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="state" value="{{ n.slug }}" />
|
||||
<input type="submit" value="{{ n.name }}" />
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if prev_state %}
|
||||
<h3>Or revert to previous state</h3>
|
||||
|
||||
<div class="prev-state">
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="state" value="{{ prev_state.slug }}" />
|
||||
<input type="submit" value="Back to {{ prev_state.name }}" />
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -12,6 +12,6 @@ secretariat takes appropriate steps. This may take up to one business
|
|||
day, as it involves a person taking action.</p>
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{ doc.idinternal.get_absolute_url }}">Back</a>
|
||||
<a href="{{ url }}">Back</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -12,7 +12,7 @@ class DocHistoryAdmin(admin.ModelAdmin):
|
|||
list_display = ['doc', 'rev', 'state', 'group', 'pages', 'intended_std_level', 'author_list', 'time']
|
||||
search_fields = ['doc__name']
|
||||
ordering = ['time', 'doc', 'rev']
|
||||
raw_id_fields = ['authors', 'related']
|
||||
raw_id_fields = ['doc', 'authors', 'related', 'group', 'shepherd', 'ad']
|
||||
admin.site.register(DocHistory, DocHistoryAdmin)
|
||||
|
||||
class DocAliasAdmin(admin.ModelAdmin):
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.db import models
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from redesign.group.models import *
|
||||
from redesign.name.models import *
|
||||
from redesign.person.models import Email
|
||||
|
@ -19,17 +21,17 @@ class DocumentInfo(models.Model):
|
|||
tags = models.ManyToManyField(DocInfoTagName, 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
|
||||
wg_state = models.ForeignKey(WgDocStateName, blank=True, null=True) # Not/Candidate/Active/Parked/LastCall/WriteUp/Submitted/Dead
|
||||
iesg_state = models.ForeignKey(IesgDocStateName, blank=True, null=True) #
|
||||
iana_state = models.ForeignKey(IanaDocStateName, blank=True, null=True)
|
||||
rfc_state = models.ForeignKey(RfcDocStateName, blank=True, null=True)
|
||||
wg_state = models.ForeignKey(WgDocStateName, verbose_name="WG state", blank=True, null=True) # Not/Candidate/Active/Parked/LastCall/WriteUp/Submitted/Dead
|
||||
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(max_length=16)
|
||||
rev = models.CharField(verbose_name="revision", max_length=16)
|
||||
pages = models.IntegerField(blank=True, null=True)
|
||||
intended_std_level = models.ForeignKey(IntendedStdLevelName, blank=True, null=True)
|
||||
std_level = models.ForeignKey(StdLevelName, blank=True, null=True)
|
||||
ad = models.ForeignKey(Email, related_name='ad_%(class)s_set', blank=True, null=True)
|
||||
ad = models.ForeignKey(Email, verbose_name="area director", related_name='ad_%(class)s_set', blank=True, null=True)
|
||||
shepherd = models.ForeignKey(Email, related_name='shepherd_%(class)s_set', blank=True, null=True)
|
||||
notify = models.CharField(max_length=255, blank=True)
|
||||
external_url = models.URLField(blank=True) # Should be set for documents with type 'External'.
|
||||
|
@ -50,11 +52,11 @@ class DocumentInfo(models.Model):
|
|||
return e[0] if e else None
|
||||
|
||||
class RelatedDocument(models.Model):
|
||||
document = models.ForeignKey('Document') # source
|
||||
doc_alias = models.ForeignKey('DocAlias') # target
|
||||
source = models.ForeignKey('Document')
|
||||
target = models.ForeignKey('DocAlias')
|
||||
relationship = models.ForeignKey(DocRelationshipName)
|
||||
def __unicode__(self):
|
||||
return u"%s %s %s" % (self.document.name, self.relationship.name.lower(), self.doc_alias.name)
|
||||
return u"%s %s %s" % (self.source.name, self.relationship.name.lower(), self.target.name)
|
||||
|
||||
class DocumentAuthor(models.Model):
|
||||
document = models.ForeignKey('Document')
|
||||
|
@ -62,7 +64,7 @@ class DocumentAuthor(models.Model):
|
|||
order = models.IntegerField()
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s (%s)" % (self.document.name, self.email.get_name(), self.order)
|
||||
return u"%s %s (%s)" % (self.document.name, self.author.get_name(), self.order)
|
||||
|
||||
class Meta:
|
||||
ordering = ["document", "order"]
|
||||
|
@ -71,55 +73,28 @@ class Document(DocumentInfo):
|
|||
name = models.CharField(max_length=255, primary_key=True) # immutable
|
||||
related = models.ManyToManyField('DocAlias', through=RelatedDocument, blank=True, related_name="reversely_related_document_set")
|
||||
authors = models.ManyToManyField(Email, through=DocumentAuthor, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
def values(self):
|
||||
try:
|
||||
fields = dict([(field.name, getattr(self, field.name))
|
||||
for field in self._meta.fields
|
||||
if field is not self._meta.pk])
|
||||
except:
|
||||
for field in self._meta.fields:
|
||||
print "* %24s"%field.name,
|
||||
print getattr(self, field.name)
|
||||
raise
|
||||
many2many = dict([(field.name, getattr(self, field.name).all())
|
||||
for field in self._meta.many_to_many ])
|
||||
return fields, many2many
|
||||
|
||||
def save_with_history(self, force_insert=False, force_update=False):
|
||||
fields, many2many = self.values()
|
||||
fields["doc"] = self
|
||||
try:
|
||||
snap = DocHistory.objects.get(**dict((k,v) for k,v in fields.items() if k != 'time'))
|
||||
# FIXME: what if there are two with the same set of values
|
||||
# at different points in time?
|
||||
if snap.time > fields["time"]:
|
||||
snap.time = fields["time"]
|
||||
snap.save()
|
||||
except DocHistory.DoesNotExist:
|
||||
snap = DocHistory(**fields)
|
||||
snap.save()
|
||||
for m in many2many:
|
||||
# FIXME: check that this works with related/authors
|
||||
#print "m2m:", m, many2many[m]
|
||||
rel = getattr(snap, m)
|
||||
for item in many2many[m]:
|
||||
rel.add(item)
|
||||
except DocHistory.MultipleObjectsReturned:
|
||||
list = DocHistory.objects.filter(**dict((k,v) for k,v in fields.items() if k != 'time'))
|
||||
list.delete()
|
||||
snap = DocHistory(**fields)
|
||||
snap.save()
|
||||
print "Deleted list:", snap
|
||||
super(Document, self).save(force_insert, force_update)
|
||||
|
||||
def get_absolute_url(self):
|
||||
name = self.name
|
||||
if self.state == "rfc":
|
||||
aliases = self.docalias_set.filter(name__startswith="rfc")
|
||||
if aliases:
|
||||
name = aliases[0].name
|
||||
return urlreverse('doc_view', kwargs={ 'name': name })
|
||||
|
||||
def file_tag(self):
|
||||
# FIXME: compensate for tombstones?
|
||||
return u"<%s-%s.txt>" % (self.name, self.rev)
|
||||
|
||||
class RelatedDocHistory(models.Model):
|
||||
document = models.ForeignKey('DocHistory') # source
|
||||
doc_alias = models.ForeignKey('DocAlias', related_name="reversely_related_document_history_set") # target
|
||||
source = models.ForeignKey('DocHistory')
|
||||
target = models.ForeignKey('DocAlias', related_name="reversely_related_document_history_set")
|
||||
relationship = models.ForeignKey(DocRelationshipName)
|
||||
def __unicode__(self):
|
||||
return u"%s %s %s" % (self.document.doc.name, self.relationship.name.lower(), self.doc_alias.name)
|
||||
return u"%s %s %s" % (self.source.doc.name, self.relationship.name.lower(), self.target.name)
|
||||
|
||||
class DocHistoryAuthor(models.Model):
|
||||
document = models.ForeignKey('DocHistory')
|
||||
|
@ -127,18 +102,58 @@ class DocHistoryAuthor(models.Model):
|
|||
order = models.IntegerField()
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s %s (%s)" % (self.document.doc.name, self.email.get_name(), self.order)
|
||||
return u"%s %s (%s)" % (self.document.doc.name, self.author.get_name(), self.order)
|
||||
|
||||
class Meta:
|
||||
ordering = ["document", "order"]
|
||||
|
||||
|
||||
class DocHistory(DocumentInfo):
|
||||
doc = models.ForeignKey(Document) # ID of the Document this relates to
|
||||
# Django won't let us define these in the base class, so we have
|
||||
# to repeat them
|
||||
related = models.ManyToManyField('DocAlias', through=RelatedDocHistory, blank=True)
|
||||
authors = models.ManyToManyField(Email, through=DocHistoryAuthor, blank=True)
|
||||
def __unicode__(self):
|
||||
return unicode(self.doc.name)
|
||||
|
||||
def save_document_in_history(doc):
|
||||
def get_model_fields_as_dict(obj):
|
||||
return dict((field.name, getattr(obj, field.name))
|
||||
for field in obj._meta.fields
|
||||
if field is not obj._meta.pk)
|
||||
|
||||
# copy fields
|
||||
fields = get_model_fields_as_dict(doc)
|
||||
fields["doc"] = doc
|
||||
|
||||
dochist = DocHistory(**fields)
|
||||
dochist.save()
|
||||
|
||||
# copy many to many
|
||||
for field in doc._meta.many_to_many:
|
||||
if not field.rel.through:
|
||||
# just add the attributes
|
||||
rel = getattr(dochist, field.name)
|
||||
for item in getattr(doc, field.name).all():
|
||||
rel.add(item)
|
||||
|
||||
# copy remaining tricky many to many
|
||||
def transfer_fields(obj, HistModel):
|
||||
mfields = get_model_fields_as_dict(item)
|
||||
# map doc -> dochist
|
||||
for k, v in mfields.iteritems():
|
||||
if v == doc:
|
||||
mfields[k] = dochist
|
||||
HistModel.objects.create(**mfields)
|
||||
|
||||
for item in RelatedDocument.objects.filter(source=doc):
|
||||
transfer_fields(item, RelatedDocHistory)
|
||||
|
||||
for item in DocumentAuthor.objects.filter(document=doc):
|
||||
transfer_fields(item, DocHistoryAuthor)
|
||||
|
||||
return dochist
|
||||
|
||||
class DocAlias(models.Model):
|
||||
"""This is used for documents that may appear under multiple names,
|
||||
and in particular for RFCs, which for continuity still keep the
|
||||
|
@ -194,8 +209,10 @@ EVENT_TYPES = [
|
|||
|
||||
# IESG events
|
||||
("started_iesg_process", "Started IESG process on document"),
|
||||
|
||||
("sent_ballot_announcement", "Sent ballot announcement"),
|
||||
("changed_ballot_position", "Changed ballot position"),
|
||||
|
||||
("changed_ballot_approval_text", "Changed ballot approval text"),
|
||||
("changed_ballot_writeup_text", "Changed ballot writeup text"),
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ class InternetDraft(Document):
|
|||
#replaced_by = models.ForeignKey('self', db_column='replaced_by', blank=True, null=True, related_name='replaces_set')
|
||||
@property
|
||||
def replaced_by(self):
|
||||
r = InternetDraft.objects.filter(relateddocument__doc_alias__document=self, relateddocument__relationship="replaces")
|
||||
r = InternetDraft.objects.filter(relateddocument__target__document=self, relateddocument__relationship="replaces")
|
||||
return r[0] if r else None
|
||||
|
||||
#replaces = FKAsOneToOne('replaces', reverse=True)
|
||||
|
@ -156,7 +156,7 @@ class InternetDraft(Document):
|
|||
|
||||
@property
|
||||
def replaces_set(self):
|
||||
return InternetDraft.objects.filter(docalias__relateddocument__document=self, docalias__relateddocument__relationship="replaces")
|
||||
return InternetDraft.objects.filter(docalias__relateddocument__source=self, docalias__relateddocument__relationship="replaces")
|
||||
|
||||
#review_by_rfc_editor = models.BooleanField()
|
||||
@property
|
||||
|
@ -631,25 +631,25 @@ class InternetDraft(Document):
|
|||
#updates = models.CharField(max_length=200,blank=True,null=True)
|
||||
@property
|
||||
def updates(self):
|
||||
return ",".join("RFC%s" % n for n in sorted(d.rfc_number for d in InternetDraft.objects.filter(docalias__relateddocument__document=self, docalias__relateddocument__relationship="updates")))
|
||||
return ",".join("RFC%s" % n for n in sorted(d.rfc_number for d in InternetDraft.objects.filter(docalias__relateddocument__source=self, docalias__relateddocument__relationship="updates")))
|
||||
|
||||
#updated_by = models.CharField(max_length=200,blank=True,null=True)
|
||||
@property
|
||||
def updated_by(self):
|
||||
if not hasattr(self, "updated_by_list"):
|
||||
self.updated_by_list = [d.rfc_number for d in InternetDraft.objects.filter(relateddocument__doc_alias__document=self, relateddocument__relationship="updates")]
|
||||
self.updated_by_list = [d.rfc_number for d in InternetDraft.objects.filter(relateddocument__target__document=self, relateddocument__relationship="updates")]
|
||||
return ",".join("RFC%s" % n for n in sorted(self.updated_by_list))
|
||||
|
||||
#obsoletes = models.CharField(max_length=200,blank=True,null=True)
|
||||
@property
|
||||
def obsoletes(self):
|
||||
return ",".join("RFC%s" % n for n in sorted(d.rfc_number for d in InternetDraft.objects.filter(docalias__relateddocument__document=self, docalias__relateddocument__relationship="obs")))
|
||||
return ",".join("RFC%s" % n for n in sorted(d.rfc_number for d in InternetDraft.objects.filter(docalias__relateddocument__source=self, docalias__relateddocument__relationship="obs")))
|
||||
|
||||
#obsoleted_by = models.CharField(max_length=200,blank=True,null=True)
|
||||
@property
|
||||
def obsoleted_by(self):
|
||||
if not hasattr(self, "obsoleted_by_list"):
|
||||
self.obsoleted_by_list = [d.rfc_number for d in InternetDraft.objects.filter(relateddocument__doc_alias__document=self, relateddocument__relationship="obs")]
|
||||
self.obsoleted_by_list = [d.rfc_number for d in InternetDraft.objects.filter(relateddocument__target__document=self, relateddocument__relationship="obs")]
|
||||
return ",".join("RFC%s" % n for n in sorted(self.obsoleted_by_list))
|
||||
|
||||
#also = models.CharField(max_length=50,blank=True,null=True)
|
||||
|
|
|
@ -49,5 +49,5 @@ class Role(models.Model):
|
|||
email = models.ForeignKey(Email)
|
||||
auth = models.CharField(max_length=255, blank=True)
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
return u"%s is %s in %s" % (self.email.get_name(), self.name.name, self.grop.acronym)
|
||||
|
||||
|
|
|
@ -890,7 +890,7 @@ for index, o in enumerate(all_drafts.iterator()):
|
|||
# replacements
|
||||
if o.replaced_by:
|
||||
replacement, _ = Document.objects.get_or_create(name=o.replaced_by.filename, defaults=dict(time=datetime.datetime(1970, 1, 1, 0, 0, 0)))
|
||||
RelatedDocument.objects.get_or_create(document=replacement, doc_alias=d_alias, relationship=relationship_replaces)
|
||||
RelatedDocument.objects.get_or_create(source=replacement, target=d_alias, relationship=relationship_replaces)
|
||||
|
||||
# the RFC-related attributes are imported when we handle the RFCs below
|
||||
|
||||
|
@ -987,9 +987,9 @@ for index, o in enumerate(all_rfcs.iterator()):
|
|||
other_number = int(other_rfc.replace("RFC", ""))
|
||||
other, other_alias = get_or_create_rfc_document(other_number)
|
||||
if reverse:
|
||||
RelatedDocument.objects.get_or_create(document=other, doc_alias=d_alias, relationship=rel_type)
|
||||
RelatedDocument.objects.get_or_create(source=other, target=d_alias, relationship=rel_type)
|
||||
else:
|
||||
RelatedDocument.objects.get_or_create(document=d, doc_alias=other_alias, relationship=rel_type)
|
||||
RelatedDocument.objects.get_or_create(source=d, target=other_alias, relationship=rel_type)
|
||||
|
||||
def parse_relation_list(s):
|
||||
if not s:
|
||||
|
|
|
@ -55,3 +55,31 @@ class IntendedStdLevelName(NameModel):
|
|||
Practice, Historic, ..."""
|
||||
class BallotPositionName(NameModel):
|
||||
""" Yes, NoObjection, Abstain, Discuss, Recuse """
|
||||
|
||||
|
||||
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, ()))
|
||||
|
||||
|
|
|
@ -65,3 +65,10 @@ class Email(models.Model):
|
|||
|
||||
def get_name(self):
|
||||
return self.person.name if self.person else self.address
|
||||
|
||||
def formatted_email(self):
|
||||
if self.person and self.person.name:
|
||||
return u"%s <%s>" % (self.person.name, self.address)
|
||||
else:
|
||||
return self.address
|
||||
|
||||
|
|
Loading…
Reference in a new issue