Merged in branch/iola/shimfree@6083. This cleans up and moves relevant code from idrfc/ to doc/. There should now only be a bit of old wrapper code left in idrfc; that will go away when the remaining models which use it are cleaned up.

- Legacy-Id: 6117
This commit is contained in:
Henrik Levkowetz 2013-09-09 17:45:36 +00:00
commit 2a2389d17f
143 changed files with 999 additions and 4900 deletions

View file

@ -9,7 +9,7 @@ management.setup_environ(settings)
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_USER)
from ietf.idrfc.expire import *
from ietf.doc.expire import *
if not in_draft_expire_freeze():
for doc in get_expired_drafts():

View file

@ -9,7 +9,7 @@ management.setup_environ(settings)
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_USER)
from ietf.idrfc.lastcall import *
from ietf.doc.lastcall import *
drafts = get_expired_last_calls()
for doc in drafts:

View file

@ -6,7 +6,7 @@ from ietf import settings
from django.core import management
management.setup_environ(settings)
from ietf.idrfc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft
from ietf.doc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft
# notify about documents that expire within the next 2 weeks

View file

@ -64,7 +64,7 @@ while urls:
print "was fetching", url
sys.exit(1)
except:
print "FAIL", url
print 500, "%.3fs" % (datetime.datetime.now() - timestamp).total_seconds(), url, "FAIL (from %s)" % referrer
print "============="
print traceback.format_exc()
print "============="
@ -82,9 +82,15 @@ while urls:
ctype = ctype[:ctype.index(";")]
if ctype == "text/html":
for u in extract_html_urls(r.content):
if u not in visited and u not in urls:
urls[u] = url
try:
for u in extract_html_urls(r.content):
if u not in visited and u not in urls:
urls[u] = url
except:
print "error extracting HTML urls from", url
print "============="
print traceback.format_exc()
print "============="
else:
tags.append(u"FAIL (from %s)" % referrer)

View file

@ -4,13 +4,13 @@ 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, itertools
import datetime, os, shutil, glob, re
from ietf.utils.mail import send_mail, send_mail_subj
from ietf.idrfc.utils import log_state_changed
from ietf.doc.models import Document, DocEvent, State, save_document_in_history, IESG_SUBSTATE_TAGS
from ietf.person.models import Person, Email
from ietf.meeting.models import Meeting
from ietf.doc.utils import log_state_changed
def expirable_draft(draft):
"""Return whether draft is in an expirable state or not. This is
@ -82,7 +82,7 @@ def send_expire_warning_for_draft(doc):
if to or cc:
send_mail(request, to, frm,
u"Expiration impending: %s" % doc.file_tag(),
"idrfc/expire_warning_email.txt",
"doc/draft/expire_warning_email.txt",
dict(doc=doc,
state=state,
expiration=expiration
@ -101,7 +101,7 @@ def send_expire_notice_for_draft(doc):
send_mail(request, to,
"I-D Expiring System <ietf-secretariat-reply@ietf.org>",
u"I-D was expired %s" % doc.file_tag(),
"idrfc/id_expired_email.txt",
"doc/draft/id_expired_email.txt",
dict(doc=doc,
state=state,
))
@ -128,14 +128,14 @@ def expire_draft(doc):
save_document_in_history(doc)
if doc.latest_event(type='started_iesg_process'):
dead_state = State.objects.get(used=True, type="draft-iesg", slug="dead")
prev = doc.get_state("draft-iesg")
prev_state = doc.friendly_state()
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
prev_tag = prev_tag[0] if prev_tag else None
if prev != dead_state:
if doc.get_state("draft-iesg") != dead_state:
doc.set_state(dead_state)
if prev_tag:
doc.tags.remove(prev_tag)
log_state_changed(None, doc, system, prev, prev_tag)
log_state_changed(None, doc, system, doc.friendly_state(), prev_state)
e = DocEvent(doc=doc, by=system)
e.type = "expired_document"

View file

@ -12,7 +12,7 @@ from django.utils.text import truncate_words
from ietf.doc.models import *
from ietf.doc.utils import augment_events_with_revision
from ietf.idtracker.templatetags.ietf_filters import format_textarea
from ietf.doc.templatetags.ietf_filters import format_textarea
class DocumentChanges(Feed):
feed_type = Atom1Feed

View file

@ -3,26 +3,13 @@
import datetime
from django.conf import settings
from django.db.models import Q
from ietf.idtracker.models import InternetDraft, DocumentComment, BallotInfo
from ietf.idrfc.mails import *
from ietf.idrfc.utils import *
from ietf.doc.models import *
from ietf.person.models import Person
import debug
from ietf.doc.utils import log_state_changed
from ietf.doc.mails import *
def request_last_call(request, doc):
try:
ballot = doc.idinternal.ballot
except BallotInfo.DoesNotExist:
ballot = generate_ballot(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"):
@ -39,14 +26,7 @@ def request_last_callREDESIGN(request, doc):
e.desc = "Last call was requested"
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)
def get_expired_last_callsREDESIGN():
today = datetime.date.today()
for d in Document.objects.filter(Q(states__type="draft-iesg", states__slug="lc")
| Q(states__type="statchg", states__slug="in-lc")):
@ -55,24 +35,6 @@ def get_expired_last_callsREDESIGN():
yield d
def expire_last_call(doc):
state = IDState.WAITING_FOR_WRITEUP
try:
ballot = doc.idinternal.ballot
if ballot.ballot_writeup and "Relevant content can frequently be found in the abstract" not in ballot.ballot_writeup:
state = IDState.WAITING_FOR_AD_GO_AHEAD
except BallotInfo.DoesNotExist:
pass
doc.idinternal.change_state(IDState.objects.get(document_state_id=state), None)
doc.idinternal.event_date = datetime.date.today()
doc.idinternal.save()
log_state_changed(None, doc, by="system", email_watch_list=False)
email_last_call_expired(doc)
def expire_last_callREDESIGN(doc):
if doc.type_id == 'draft':
state = State.objects.get(used=True, type="draft-iesg", slug="writeupw")
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
@ -87,8 +49,9 @@ def expire_last_callREDESIGN(doc):
else:
raise ValueError("Unexpected document type to expire_last_call(): %s" % doc.type)
save_document_in_history(doc)
prev_state = doc.friendly_state()
save_document_in_history(doc)
doc.set_state(state)
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
@ -96,14 +59,9 @@ def expire_last_callREDESIGN(doc):
if prev_tag:
doc.tags.remove(prev_tag)
e = log_state_changed(None, doc, Person.objects.get(name="(System)"), prev, prev_tag)
e = log_state_changed(None, doc, Person.objects.get(name="(System)"), doc.friendly_state(), prev_state)
doc.time = e.time
doc.save()
email_last_call_expired(doc)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
get_expired_last_calls = get_expired_last_callsREDESIGN
expire_last_call = expire_last_callREDESIGN

View file

@ -1,7 +1,6 @@
# generation of mails
import textwrap
from datetime import datetime, date, time, timedelta
import textwrap, datetime
from django.template.loader import render_to_string
from django.utils.html import strip_tags
@ -9,23 +8,12 @@ from django.conf import settings
from django.core.urlresolvers import reverse as urlreverse
from ietf.utils.mail import send_mail, send_mail_text
from ietf.idtracker.models import *
from ietf.ipr.search import iprs_from_docs, related_docs
#from ietf.doc.models import *
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias, ConsensusDocEvent
from ietf.person.models import Person
from ietf.group.models import Group
from ietf.group.models import Group, Role
def email_state_changed(request, doc, text):
to = [x.strip() for x in doc.idinternal.state_change_notice_to.replace(';', ',').split(',')]
if to:
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.idinternal.get_absolute_url()))
def email_state_changedREDESIGN(request, doc, text):
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
if not to:
return
@ -33,41 +21,37 @@ def email_state_changedREDESIGN(request, doc, text):
text = strip_tags(text)
send_mail(request, to, None,
"ID Tracker State Update Notice: %s" % doc.file_tag(),
"idrfc/state_changed_email.txt",
"doc/mail/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 email_stream_changed(request, doc, old_stream, new_stream, text=""):
"""Email the change text to the notify group and to the stream chairs"""
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
from ietf.group.models import Role as RedesignRole
# These use comprehension to deal with conditions when there might be more than one chair listed for a stream
if old_stream:
to.extend([x.person.formatted_email() for x in RedesignRole.objects.filter(group__acronym=old_stream.slug,name='chair')])
to.extend([x.person.formatted_email() for x in Role.objects.filter(group__acronym=old_stream.slug,name='chair')])
if new_stream:
to.extend([x.person.formatted_email() for x in RedesignRole.objects.filter(group__acronym=new_stream.slug,name='chair')])
to.extend([x.person.formatted_email() for x in Role.objects.filter(group__acronym=new_stream.slug,name='chair')])
if not to:
return
if not text:
text = u"Stream changed to <b>%s</b> from %s"% (new_stream,old_stream)
text = u"Stream changed to <b>%s</b> from %s" % (new_stream, old_stream)
text = strip_tags(text)
send_mail(request, to, None,
"ID Tracker Stream Change Notice: %s" % doc.file_tag(),
"idrfc/stream_changed_email.txt",
"doc/mail/stream_changed_email.txt",
dict(text=text,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
def email_pulled_from_rfc_queue(request, doc, comment, prev_state, next_state):
send_mail(request, ["IANA <iana@iana.org>", "RFC Editor <rfc-editor@rfc-editor.org>"], None,
"%s changed state from %s to %s" % (doc.name, prev_state.name, next_state.name),
"idrfc/pulled_from_rfc_queue_email.txt",
"doc/mail/pulled_from_rfc_queue_email.txt",
dict(doc=doc,
prev_state=prev_state,
next_state=next_state,
@ -86,20 +70,7 @@ def email_authors(request, doc, subject, text):
def html_to_text(html):
return strip_tags(html.replace("&lt;", "<").replace("&gt;", ">").replace("&amp;", "&").replace("<br>", "\n"))
def email_owner(request, doc, owner, changed_by, text, subject=None):
if not owner or not changed_by or owner == changed_by:
return
to = u"%s <%s>" % owner.person.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.idinternal.get_absolute_url()))
def email_adREDESIGN(request, doc, ad, changed_by, text, subject=None):
def email_ad(request, doc, ad, changed_by, text, subject=None):
if not ad or not changed_by or ad == changed_by:
return
@ -107,14 +78,11 @@ def email_adREDESIGN(request, doc, ad, changed_by, text, subject=None):
send_mail(request, to,
"DraftTracker Mail System <iesg-secretary@ietf.org>",
"%s updated by %s" % (doc.file_tag(), changed_by.plain_name()),
"idrfc/change_notice.txt",
"doc/mail/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_adREDESIGN
def generate_ballot_writeup(request, doc):
e = doc.latest_event(type="iana_review")
@ -125,21 +93,17 @@ def generate_ballot_writeup(request, doc):
e.by = request.user.get_profile()
e.doc = doc
e.desc = u"Ballot writeup was generated"
e.text = unicode(render_to_string("idrfc/ballot_writeup.txt", {'iana': iana}))
e.text = unicode(render_to_string("doc/mail/ballot_writeup.txt", {'iana': iana}))
e.save()
return e
def generate_last_call_announcement(request, doc):
pass
def generate_last_call_announcementREDESIGN(request, doc):
expiration_date = date.today() + timedelta(days=14)
expiration_date = datetime.date.today() + datetime.timedelta(days=14)
cc = []
if doc.group.type_id in ("individ", "area"):
group = "an individual submitter"
expiration_date += timedelta(days=14)
expiration_date += datetime.timedelta(days=14)
else:
group = "the %s WG (%s)" % (doc.group.name, doc.group.acronym)
if doc.group.list_email:
@ -154,7 +118,7 @@ def generate_last_call_announcementREDESIGN(request, doc):
else:
ipr_links = None
mail = render_to_string("idrfc/last_call_announcement.txt",
mail = render_to_string("doc/mail/last_call_announcement.txt",
dict(doc=doc,
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url() + "ballot/",
expiration_date=expiration_date.strftime("%Y-%m-%d"), #.strftime("%B %-d, %Y"),
@ -177,18 +141,9 @@ def generate_last_call_announcementREDESIGN(request, doc):
return e
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
generate_last_call_announcement = generate_last_call_announcementREDESIGN
def generate_approval_mail(request, doc):
pass
def generate_approval_mail_rfc_editor(request, doc):
pass
DO_NOT_PUBLISH_IESG_STATES = ("nopubadw", "nopubanw")
def generate_approval_mailREDESIGN(request, doc):
def generate_approval_mail(request, doc):
if doc.get_state_slug("draft-iesg") in DO_NOT_PUBLISH_IESG_STATES or doc.stream_id in ('ise','irtf'):
mail = generate_approval_mail_rfc_editor(request, doc)
else:
@ -241,7 +196,7 @@ def generate_approval_mail_approved(request, doc):
doc_type = "RFC" if doc.get_state_slug() == "rfc" else "Internet Draft"
return render_to_string("idrfc/approval_mail.txt",
return render_to_string("doc/mail/approval_mail.txt",
dict(doc=doc,
docs=[doc],
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
@ -253,7 +208,7 @@ def generate_approval_mail_approved(request, doc):
)
)
def generate_approval_mail_rfc_editorREDESIGN(request, doc):
def generate_approval_mail_rfc_editor(request, doc):
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"
@ -272,7 +227,7 @@ def generate_approval_mail_rfc_editorREDESIGN(request, doc):
# include IRSG
to.append('"Internet Research Steering Group" <irsg@irtf.org>')
return render_to_string("idrfc/approval_mail_rfc_editor.txt",
return render_to_string("doc/mail/approval_mail_rfc_editor.txt",
dict(doc=doc,
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
doc_type=doc_type,
@ -281,10 +236,6 @@ def generate_approval_mail_rfc_editorREDESIGN(request, doc):
)
)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
generate_approval_mail = generate_approval_mailREDESIGN
generate_approval_mail_rfc_editor = generate_approval_mail_rfc_editorREDESIGN
def generate_publication_request(request, doc):
group_description = ""
if doc.group and doc.group.acronym != "none":
@ -300,7 +251,7 @@ def generate_publication_request(request, doc):
approving_body = str(doc.stream)
consensus_body = approving_body
return render_to_string("idrfc/publication_request.txt",
return render_to_string("doc/mail/publication_request.txt",
dict(doc=doc,
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
group_description=group_description,
@ -310,42 +261,18 @@ def generate_publication_request(request, doc):
)
)
def send_last_call_request(request, doc, ballot):
to = "iesg-secretary@ietf.org"
frm = '"DraftTracker Mail System" <iesg-secretary@ietf.org>'
docs = [d.document() for d in doc.idinternal.ballot_set()]
send_mail(request, to, frm,
"Last Call: %s" % doc.file_tag(),
"idrfc/last_call_request.txt",
dict(docs=docs,
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
def send_last_call_requestREDESIGN(request, doc):
def send_last_call_request(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",
"doc/mail/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()
send_mail(request, to, frm,
"I-D Resurrection Request",
"idrfc/resurrect_request_email.txt",
dict(doc=doc,
by=frm,
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
def email_resurrect_requestedREDESIGN(request, doc, by):
to = "I-D Administrator <internet-drafts@ietf.org>"
if by.role_set.filter(name="secr", group__acronym="secretariat"):
e = by.role_email("secr", group="secretariat")
@ -355,25 +282,12 @@ def email_resurrect_requestedREDESIGN(request, doc, by):
send_mail(request, to, e.formatted_email(),
"I-D Resurrection Request",
"idrfc/resurrect_request_email.txt",
"doc/mail/resurrect_request_email.txt",
dict(doc=doc,
by=frm,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
email_resurrect_requested = email_resurrect_requestedREDESIGN
def email_resurrection_completed(request, doc):
to = u"%s <%s>" % doc.idinternal.resurrect_requested_by.person.email()
frm = "I-D Administrator <internet-drafts-reply@ietf.org>"
send_mail(request, to, frm,
"I-D Resurrection Completed - %s" % doc.file_tag(),
"idrfc/resurrect_completed_email.txt",
dict(doc=doc,
by=frm,
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
def email_resurrection_completedREDESIGN(request, doc, requester):
def email_resurrection_completed(request, doc, requester):
if requester.role_set.filter(name="secr", group__acronym="secretariat"):
e = requester.role_email("secr", group="secretariat")
else:
@ -383,28 +297,22 @@ def email_resurrection_completedREDESIGN(request, doc, requester):
frm = "I-D Administrator <internet-drafts-reply@ietf.org>"
send_mail(request, to, frm,
"I-D Resurrection Completed - %s" % doc.file_tag(),
"idrfc/resurrect_completed_email.txt",
"doc/mail/resurrect_completed_email.txt",
dict(doc=doc,
by=frm,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
email_resurrection_completed = email_resurrection_completedREDESIGN
def email_ballot_deferred(request, doc, by, telechat_date):
to = "iesg@ietf.org"
frm = "DraftTracker Mail System <iesg-secretary@ietf.org>"
send_mail(request, to, frm,
"IESG Deferred Ballot notification: %s" % doc.file_tag(),
"idrfc/ballot_deferred_email.txt",
"doc/mail/ballot_deferred_email.txt",
dict(doc=doc,
by=by,
telechat_date=telechat_date))
def generate_issue_ballot_mail(request, doc):
pass
def generate_issue_ballot_mailREDESIGN(request, doc, ballot):
def generate_issue_ballot_mail(request, doc, ballot):
active_ads = Person.objects.filter(role__name="ad", role__group__state="active").distinct()
positions = BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ballot=ballot).order_by("-time", '-id').select_related('ad')
@ -456,7 +364,7 @@ def generate_issue_ballot_mailREDESIGN(request, doc, ballot):
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
ballot_writeup = e.text if e else ""
return render_to_string("idrfc/issue_ballot_mailREDESIGN.txt",
return render_to_string("doc/mail/issue_ballot_mail.txt",
dict(doc=doc,
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
active_ad_positions=active_ad_positions,
@ -468,9 +376,6 @@ def generate_issue_ballot_mailREDESIGN(request, doc, ballot):
)
)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
generate_issue_ballot_mail = generate_issue_ballot_mailREDESIGN
def email_iana(request, doc, to, msg):
# fix up message and send it with extra info on doc in headers
import email
@ -494,19 +399,6 @@ def extra_automation_headers(doc):
return extra
def email_last_call_expired(doc):
text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.idinternal.cur_state.state
send_mail(None,
"iesg@ietf.org",
"DraftTracker Mail System <iesg-secretary@ietf.org>",
"Last Call Expired: %s" % doc.file_tag(),
"idrfc/change_notice.txt",
dict(text=text,
doc=doc,
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()),
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.get_state("draft-iesg").name
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
@ -516,12 +408,8 @@ def email_last_call_expiredREDESIGN(doc):
to,
"DraftTracker Mail System <iesg-secretary@ietf.org>",
"Last Call Expired: %s" % doc.file_tag(),
"idrfc/change_notice.txt",
"doc/mail/change_notice.txt",
dict(text=text,
doc=doc,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc="iesg-secretary@ietf.org")
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
email_last_call_expired = email_last_call_expiredREDESIGN

View file

@ -355,7 +355,6 @@ class Document(DocumentInfo):
iesg_state = self.get_state("draft-iesg")
iesg_state_summary = None
if iesg_state:
# This knowledge about which tags are reportable IESG substate tags is duplicated in idrfc
iesg_substate = self.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
# There really shouldn't be more than one tag in iesg_substate, but this will do something sort-of-sensible if there is
iesg_state_summary = iesg_state.name

View file

@ -84,7 +84,7 @@ def render_ballot_icon(user, doc):
edit_position_url = ""
if has_role(user, "Area Director"):
edit_position_url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
edit_position_url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
title = "IESG positions (click to show more%s)" % (", right-click to edit position" if edit_position_url else "")

View file

@ -1,7 +1,6 @@
from django import template
from django.core.cache import cache
from django.template import loader
from ietf.idtracker.models import Area
register = template.Library()

View file

@ -33,7 +33,8 @@
from django import template
from django.core.cache import cache
from django.template import loader
from ietf.idtracker.models import Area
from ietf.group.models import Group
register = template.Library()
@ -42,26 +43,27 @@ area_short_names = {
'rai':'RAI'
}
def get_short_name(area):
if area.area_acronym.acronym in area_short_names:
return area_short_names[area.area_acronym.acronym]
else:
area_name = area.area_acronym.name
if area_name.endswith(" Area"):
area_name = area_name[:-5]
return area_name
class WgMenuNode(template.Node):
def __init__(self):
pass
def render(self, context):
x = cache.get('idrfc_wgmenu')
x = cache.get('base_left_wgmenu')
if x:
return x
areas = [{'area':x, 'short_name':get_short_name(x)} for x in Area.active_areas()]
x = loader.render_to_string('base_wgmenu.html', {'areas':areas})
cache.set('idrfc_wgmenu', x, 30*60)
return x
areas = Group.objects.filter(type="area", state="active").order_by('acronym')
groups = Group.objects.filter(type="wg", state="active", parent__in=areas).order_by("acronym")
for a in areas:
a.short_area_name = area_short_names.get(a.acronym) or a.name
if a.short_area_name.endswith(" Area"):
a.short_area_name = a.short_area_name[:-len(" Area")]
a.active_groups = [g for g in groups if g.parent_id == a.id]
areas = [a for a in areas if a.active_groups]
res = loader.render_to_string('base_wgmenu.html', {'areas':areas})
cache.set('base_left_wgmenu', x, 30*60)
return res
def do_wg_menu(parser, token):
return WgMenuNode()

View file

@ -17,7 +17,10 @@ from ietf.meeting.models import Meeting, MeetingTypeName
from ietf.iesg.models import TelechatDate
# extra tests
from ietf.doc.tests_draft import *
from ietf.doc.tests_ballot import *
from ietf.doc.tests_conflict_review import *
from ietf.doc.tests_status_change import *
class SearchTestCase(django.test.TestCase):
@ -243,3 +246,49 @@ class DocTestCase(django.test.TestCase):
r = self.client.get(urlreverse("ietf.doc.views_doc.document_json", kwargs=dict(name=doc.name)))
self.assertEqual(r.status_code, 200)
class AddCommentTestCase(django.test.TestCase):
fixtures = ['names']
def test_add_comment(self):
draft = make_test_data()
url = urlreverse('doc_add_comment', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form textarea[name=comment]')), 1)
# request resurrect
events_before = draft.docevent_set.count()
mailbox_before = len(outbox)
r = self.client.post(url, dict(comment="This is a test."))
self.assertEquals(r.status_code, 302)
self.assertEquals(draft.docevent_set.count(), events_before + 1)
self.assertEquals("This is a test.", draft.latest_event().desc)
self.assertEquals("added_comment", draft.latest_event().type)
self.assertEquals(len(outbox), mailbox_before + 1)
self.assertTrue("updated" in outbox[-1]['Subject'])
self.assertTrue(draft.name in outbox[-1]['Subject'])
# Make sure we can also do it as IANA
self.client.login(remote_user="iana")
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form textarea[name=comment]')), 1)
class TemplateTagTest(unittest.TestCase):
def test_template_tags(self):
import doctest
from ietf.doc.templatetags import ietf_filters
failures, tests = doctest.testmod(ietf_filters)
self.assertEqual(failures, 0)

495
ietf/doc/tests_ballot.py Normal file
View file

@ -0,0 +1,495 @@
import unittest
import StringIO
import os, shutil
from datetime import date, timedelta, time
import django.test
from django.core.urlresolvers import reverse as urlreverse
from django.conf import settings
from pyquery import PyQuery
import debug
from ietf.doc.models import *
from ietf.name.models import *
from ietf.group.models import *
from ietf.person.models import *
from ietf.meeting.models import Meeting, MeetingTypeName
from ietf.iesg.models import TelechatDate
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.utils.test_data import make_test_data
from ietf.utils.mail import outbox
class EditPositionTestCase(django.test.TestCase):
fixtures = ['names']
def test_edit_position(self):
draft = make_test_data()
url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=draft.name,
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
login_testing_unauthorized(self, "ad", url)
ad = Person.objects.get(name="Aread Irector")
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name=position]')) > 0)
self.assertEquals(len(q('form textarea[name=comment]')), 1)
# vote
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="discuss",
discuss=" This is a discussion test. \n ",
comment=" This is a test. \n "))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "discuss")
self.assertTrue(" This is a discussion test." in pos.discuss)
self.assertTrue(pos.discuss_time != None)
self.assertTrue(" This is a test." in pos.comment)
self.assertTrue(pos.comment_time != None)
self.assertTrue("New position" in pos.desc)
self.assertEquals(draft.docevent_set.count(), events_before + 3)
# recast vote
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="noobj"))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "noobj")
self.assertEquals(draft.docevent_set.count(), events_before + 1)
self.assertTrue("Position for" in pos.desc)
# clear vote
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="norecord"))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "norecord")
self.assertEquals(draft.docevent_set.count(), events_before + 1)
self.assertTrue("Position for" in pos.desc)
# change comment
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="norecord", comment="New comment."))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "norecord")
self.assertEquals(draft.docevent_set.count(), events_before + 2)
self.assertTrue("Ballot comment text updated" in pos.desc)
def test_edit_position_as_secretary(self):
draft = make_test_data()
url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=draft.name,
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
ad = Person.objects.get(name="Aread Irector")
url += "?ad=%s" % ad.pk
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name=position]')) > 0)
# vote on behalf of AD
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="discuss", discuss="Test discuss text"))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "discuss")
self.assertEquals(pos.discuss, "Test discuss text")
self.assertTrue("New position" in pos.desc)
self.assertTrue("by Sec" in pos.desc)
def test_cannot_edit_position_as_pre_ad(self):
draft = make_test_data()
url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=draft.name,
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
# transform to pre-ad
ad_role = Role.objects.filter(name="ad")[0]
ad_role.name_id = "pre-ad"
ad_role.save()
# we can see
login_testing_unauthorized(self, ad_role.person.user.username, url)
# but not touch
r = self.client.post(url, dict(position="discuss", discuss="Test discuss text"))
self.assertEquals(r.status_code, 403)
def test_send_ballot_comment(self):
draft = make_test_data()
draft.notify = "somebody@example.com"
draft.save()
ad = Person.objects.get(name="Aread Irector")
ballot = draft.latest_event(BallotDocEvent, type="created_ballot")
BallotPositionDocEvent.objects.create(
doc=draft, type="changed_ballot_position",
by=ad, ad=ad, ballot=ballot, pos=BallotPositionName.objects.get(slug="discuss"),
discuss="This draft seems to be lacking a clearer title?",
discuss_time=datetime.datetime.now(),
comment="Test!",
comment_time=datetime.datetime.now())
url = urlreverse('doc_send_ballot_comment', kwargs=dict(name=draft.name,
ballot_id=ballot.pk))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name="cc"]')) > 0)
# send
mailbox_before = len(outbox)
r = self.client.post(url, dict(cc="test@example.com", cc_state_change="1"))
self.assertEquals(r.status_code, 302)
self.assertEquals(len(outbox), mailbox_before + 1)
m = outbox[-1]
self.assertTrue("COMMENT" in m['Subject'])
self.assertTrue("DISCUSS" in m['Subject'])
self.assertTrue(draft.name in m['Subject'])
self.assertTrue("clearer title" in str(m))
self.assertTrue("Test!" in str(m))
class DeferBallotTestCase(django.test.TestCase):
fixtures = ['names']
def test_defer_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva"))
url = urlreverse('doc_defer_ballot', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
# defer
mailbox_before = len(outbox)
r = self.client.post(url, dict())
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertEquals(draft.get_state_slug("draft-iesg"), "defer")
self.assertEquals(len(outbox), mailbox_before + 2)
self.assertTrue("State Update" in outbox[-2]['Subject'])
self.assertTrue("Deferred" in outbox[-1]['Subject'])
self.assertTrue(draft.file_tag() in outbox[-1]['Subject'])
def test_undefer_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="defer"))
url = urlreverse('doc_undefer_ballot', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
# undefer
r = self.client.post(url, dict())
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertEquals(draft.get_state_slug("draft-iesg"), "iesg-eva")
class BallotWriteupsTestCase(django.test.TestCase):
fixtures = ['names']
def test_edit_last_call_text(self):
draft = make_test_data()
url = urlreverse('doc_ballot_lastcall', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('textarea[name=last_call_text]')), 1)
self.assertEquals(len(q('input[type=submit][value*="Save Last Call"]')), 1)
# we're secretariat, so we got The Link
self.assertEquals(len(q('a:contains("Make Last Call")')), 1)
# subject error
r = self.client.post(url, dict(
last_call_text="Subject: test\r\nhello\r\n\r\n",
save_last_call_text="1"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('ul.errorlist')) > 0)
# save
r = self.client.post(url, dict(
last_call_text="This is a simple test.",
save_last_call_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_last_call_text").text)
# test regenerate
r = self.client.post(url, dict(
last_call_text="This is a simple test.",
regenerate_last_call_text="1"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
draft = Document.objects.get(name=draft.name)
self.assertTrue("Subject: Last Call" in draft.latest_event(WriteupDocEvent, type="changed_last_call_text").text)
def test_request_last_call(self):
draft = make_test_data()
url = urlreverse('doc_ballot_lastcall', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# give us an announcement to send
r = self.client.post(url, dict(regenerate_last_call_text="1"))
self.assertEquals(r.status_code, 200)
mailbox_before = len(outbox)
# send
r = self.client.post(url, dict(
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.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'])
def test_edit_ballot_writeup(self):
draft = make_test_data()
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# add a IANA review note
draft.set_state(State.objects.get(used=True, type="draft-iana-review", slug="not-ok"))
DocEvent.objects.create(type="iana_review",
doc=draft,
by=Person.objects.get(user__username="iana"),
desc="IANA does not approve of this document, it does not make sense.",
)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('textarea[name=ballot_writeup]')), 1)
self.assertEquals(len(q('input[type=submit][value*="Save Ballot Writeup"]')), 1)
self.assertTrue("IANA does not" in r.content)
# save
r = self.client.post(url, dict(
ballot_writeup="This is a simple test.",
save_ballot_writeup="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text").text)
def test_issue_ballot(self):
draft = make_test_data()
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
ballot = draft.latest_event(BallotDocEvent, type="created_ballot")
def create_pos(num, vote, comment="", discuss=""):
ad = Person.objects.get(name="Ad No%s" % num)
e = BallotPositionDocEvent()
e.doc = draft
e.ballot = ballot
e.by = ad
e.ad = ad
e.pos = BallotPositionName.objects.get(slug=vote)
e.type = "changed_ballot_position"
e.comment = comment
if e.comment:
e.comment_time = datetime.datetime.now()
e.discuss = discuss
if e.discuss:
e.discuss_time = datetime.datetime.now()
e.save()
# active
create_pos(1, "yes", discuss="discuss1 " * 20)
create_pos(2, "noobj", comment="comment2 " * 20)
create_pos(3, "discuss", discuss="discuss3 " * 20, comment="comment3 " * 20)
create_pos(4, "abstain")
create_pos(5, "recuse")
# inactive
create_pos(9, "yes")
mailbox_before = len(outbox)
r = self.client.post(url, dict(
ballot_writeup="This is a test.",
issue_ballot="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue(draft.latest_event(type="sent_ballot_announcement"))
self.assertEquals(len(outbox), mailbox_before + 2)
issue_email = outbox[-2]
self.assertTrue("Evaluation:" in issue_email['Subject'])
self.assertTrue("comment1" not in str(issue_email))
self.assertTrue("comment2" in str(issue_email))
self.assertTrue("comment3" in str(issue_email))
self.assertTrue("discuss3" in str(issue_email))
self.assertTrue("This is a test" in str(issue_email))
self.assertTrue("The IESG has approved" in str(issue_email))
def test_edit_approval_text(self):
draft = make_test_data()
url = urlreverse('doc_ballot_approvaltext', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('textarea[name=approval_text]')), 1)
self.assertEquals(len(q('input[type=submit][value*="Save Approval"]')), 1)
# save
r = self.client.post(url, dict(
approval_text="This is a simple test.",
save_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
# test regenerate
r = self.client.post(url, dict(regenerate_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("Subject: Protocol Action" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
# test regenerate when it's a disapprove
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="nopubadw"))
r = self.client.post(url, dict(regenerate_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("NOT be published" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
# test regenerate when it's a conflict review
draft.group = Group.objects.get(type="individ")
draft.stream_id = "irtf"
draft.save()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva"))
r = self.client.post(url, dict(regenerate_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("Subject: Results of IETF-conflict review" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
class ApproveBallotTestCase(django.test.TestCase):
fixtures = ['names']
def test_approve_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, 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)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue("send out the announcement" in q('.actions input[type=submit]')[0].get('value').lower())
self.assertEquals(len(q('.announcement pre:contains("Subject: Protocol Action")')), 1)
# approve
mailbox_before = len(outbox)
r = self.client.post(url, dict(skiprfceditorpost="1"))
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
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
self.assertTrue("Protocol Action" in outbox[-1]['Subject'])
self.assertTrue(not outbox[-1]['CC'])
self.assertTrue("Protocol Action" in draft.message_set.order_by("-time")[0].subject)
def test_disapprove_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="nopubadw"))
url = urlreverse('doc_approve_ballot', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# disapprove (the Martians aren't going to be happy)
mailbox_before = len(outbox)
r = self.client.post(url, dict())
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
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]))
class MakeLastCallTestCase(django.test.TestCase):
fixtures = ['names']
def test_make_last_call(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="lc-req"))
url = urlreverse('doc_make_last_call', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('input[name=last_call_sent_date]')), 1)
# make last call
mailbox_before = len(outbox)
expire_date = q('input[name=last_call_expiration_date]')[0].get("value")
r = self.client.post(url,
dict(last_call_sent_date=q('input[name=last_call_sent_date]')[0].get("value"),
last_call_expiration_date=expire_date
))
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
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)
self.assertTrue("Last Call" in outbox[-4]['Subject'])
# the IANA copy
self.assertTrue("Last Call" in outbox[-3]['Subject'])
self.assertTrue("Last Call" in draft.message_set.order_by("-time")[0].subject)

View file

@ -1,35 +1,3 @@
# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# * Neither the name of the Nokia Corporation and/or its
# subsidiary(-ies) nor the names of its contributors may be used
# to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import unittest
import StringIO
import os, shutil
@ -48,15 +16,10 @@ from ietf.group.models import *
from ietf.person.models import *
from ietf.meeting.models import Meeting, MeetingTypeName
from ietf.iesg.models import TelechatDate
from ietf.utils.test_utils import SimpleUrlTestCase, RealDatabaseTest, login_testing_unauthorized
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.utils.test_data import make_test_data
from ietf.utils.mail import outbox
class IdRfcUrlTestCase(SimpleUrlTestCase):
def testUrls(self):
#self.doTestUrls(__file__)
self.doTestUrls(os.path.join(os.path.dirname(os.path.abspath(__file__)), "testurlREDESIGN.list"))
class ChangeStateTestCase(django.test.TestCase):
fixtures = ['names']
@ -443,556 +406,7 @@ class ResurrectTestCase(django.test.TestCase):
self.assertEquals(draft.get_state_slug(), "active")
self.assertTrue(draft.expires >= datetime.datetime.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE - 1))
self.assertEquals(len(outbox), mailbox_before + 1)
class AddCommentTestCase(django.test.TestCase):
fixtures = ['names']
def test_add_comment(self):
draft = make_test_data()
url = urlreverse('doc_add_comment', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form textarea[name=comment]')), 1)
# request resurrect
events_before = draft.docevent_set.count()
mailbox_before = len(outbox)
r = self.client.post(url, dict(comment="This is a test."))
self.assertEquals(r.status_code, 302)
self.assertEquals(draft.docevent_set.count(), events_before + 1)
self.assertEquals("This is a test.", draft.latest_event().desc)
self.assertEquals("added_comment", draft.latest_event().type)
self.assertEquals(len(outbox), mailbox_before + 1)
self.assertTrue("updated" in outbox[-1]['Subject'])
self.assertTrue(draft.name in outbox[-1]['Subject'])
# Make sure we can also do it as IANA
self.client.login(remote_user="iana")
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form textarea[name=comment]')), 1)
class EditPositionTestCase(django.test.TestCase):
fixtures = ['names']
def test_edit_position(self):
draft = make_test_data()
url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=draft.name,
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
login_testing_unauthorized(self, "ad", url)
ad = Person.objects.get(name="Aread Irector")
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name=position]')) > 0)
self.assertEquals(len(q('form textarea[name=comment]')), 1)
# vote
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="discuss",
discuss=" This is a discussion test. \n ",
comment=" This is a test. \n "))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "discuss")
self.assertTrue(" This is a discussion test." in pos.discuss)
self.assertTrue(pos.discuss_time != None)
self.assertTrue(" This is a test." in pos.comment)
self.assertTrue(pos.comment_time != None)
self.assertTrue("New position" in pos.desc)
self.assertEquals(draft.docevent_set.count(), events_before + 3)
# recast vote
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="noobj"))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "noobj")
self.assertEquals(draft.docevent_set.count(), events_before + 1)
self.assertTrue("Position for" in pos.desc)
# clear vote
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="norecord"))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "norecord")
self.assertEquals(draft.docevent_set.count(), events_before + 1)
self.assertTrue("Position for" in pos.desc)
# change comment
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="norecord", comment="New comment."))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "norecord")
self.assertEquals(draft.docevent_set.count(), events_before + 2)
self.assertTrue("Ballot comment text updated" in pos.desc)
def test_edit_position_as_secretary(self):
draft = make_test_data()
url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=draft.name,
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
ad = Person.objects.get(name="Aread Irector")
url += "?ad=%s" % ad.pk
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name=position]')) > 0)
# vote on behalf of AD
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="discuss", discuss="Test discuss text"))
self.assertEquals(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, ad=ad)
self.assertEquals(pos.pos.slug, "discuss")
self.assertEquals(pos.discuss, "Test discuss text")
self.assertTrue("New position" in pos.desc)
self.assertTrue("by Sec" in pos.desc)
def test_cannot_edit_position_as_pre_ad(self):
draft = make_test_data()
url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=draft.name,
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
# transform to pre-ad
ad_role = Role.objects.filter(name="ad")[0]
ad_role.name_id = "pre-ad"
ad_role.save()
# we can see
login_testing_unauthorized(self, ad_role.person.user.username, url)
# but not touch
r = self.client.post(url, dict(position="discuss", discuss="Test discuss text"))
self.assertEquals(r.status_code, 403)
def test_send_ballot_comment(self):
draft = make_test_data()
draft.notify = "somebody@example.com"
draft.save()
ad = Person.objects.get(name="Aread Irector")
ballot = draft.latest_event(BallotDocEvent, type="created_ballot")
BallotPositionDocEvent.objects.create(
doc=draft, type="changed_ballot_position",
by=ad, ad=ad, ballot=ballot, pos=BallotPositionName.objects.get(slug="discuss"),
discuss="This draft seems to be lacking a clearer title?",
discuss_time=datetime.datetime.now(),
comment="Test!",
comment_time=datetime.datetime.now())
url = urlreverse('doc_send_ballot_comment', kwargs=dict(name=draft.name,
ballot_id=ballot.pk))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name="cc"]')) > 0)
# send
mailbox_before = len(outbox)
r = self.client.post(url, dict(cc="test@example.com", cc_state_change="1"))
self.assertEquals(r.status_code, 302)
self.assertEquals(len(outbox), mailbox_before + 1)
m = outbox[-1]
self.assertTrue("COMMENT" in m['Subject'])
self.assertTrue("DISCUSS" in m['Subject'])
self.assertTrue(draft.name in m['Subject'])
self.assertTrue("clearer title" in str(m))
self.assertTrue("Test!" in str(m))
class DeferBallotTestCase(django.test.TestCase):
fixtures = ['names']
def test_defer_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva"))
url = urlreverse('doc_defer_ballot', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
# defer
mailbox_before = len(outbox)
r = self.client.post(url, dict())
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertEquals(draft.get_state_slug("draft-iesg"), "defer")
self.assertEquals(len(outbox), mailbox_before + 2)
self.assertTrue("State Update" in outbox[-2]['Subject'])
self.assertTrue("Deferred" in outbox[-1]['Subject'])
self.assertTrue(draft.file_tag() in outbox[-1]['Subject'])
def test_undefer_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="defer"))
url = urlreverse('doc_undefer_ballot', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
# undefer
r = self.client.post(url, dict())
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertEquals(draft.get_state_slug("draft-iesg"), "iesg-eva")
class BallotWriteupsTestCase(django.test.TestCase):
fixtures = ['names']
def test_edit_last_call_text(self):
draft = make_test_data()
url = urlreverse('doc_ballot_lastcall', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('textarea[name=last_call_text]')), 1)
self.assertEquals(len(q('input[type=submit][value*="Save Last Call"]')), 1)
# we're secretariat, so we got The Link
self.assertEquals(len(q('a:contains("Make Last Call")')), 1)
# subject error
r = self.client.post(url, dict(
last_call_text="Subject: test\r\nhello\r\n\r\n",
save_last_call_text="1"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('ul.errorlist')) > 0)
# save
r = self.client.post(url, dict(
last_call_text="This is a simple test.",
save_last_call_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_last_call_text").text)
# test regenerate
r = self.client.post(url, dict(
last_call_text="This is a simple test.",
regenerate_last_call_text="1"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
draft = Document.objects.get(name=draft.name)
self.assertTrue("Subject: Last Call" in draft.latest_event(WriteupDocEvent, type="changed_last_call_text").text)
def test_request_last_call(self):
draft = make_test_data()
url = urlreverse('doc_ballot_lastcall', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# give us an announcement to send
r = self.client.post(url, dict(regenerate_last_call_text="1"))
self.assertEquals(r.status_code, 200)
mailbox_before = len(outbox)
# send
r = self.client.post(url, dict(
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.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'])
def test_edit_ballot_writeup(self):
draft = make_test_data()
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# add a IANA review note
draft.set_state(State.objects.get(used=True, type="draft-iana-review", slug="not-ok"))
DocEvent.objects.create(type="iana_review",
doc=draft,
by=Person.objects.get(user__username="iana"),
desc="IANA does not approve of this document, it does not make sense.",
)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('textarea[name=ballot_writeup]')), 1)
self.assertEquals(len(q('input[type=submit][value*="Save Ballot Writeup"]')), 1)
self.assertTrue("IANA does not" in r.content)
# save
r = self.client.post(url, dict(
ballot_writeup="This is a simple test.",
save_ballot_writeup="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text").text)
def test_issue_ballot(self):
draft = make_test_data()
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
ballot = draft.latest_event(BallotDocEvent, type="created_ballot")
def create_pos(num, vote, comment="", discuss=""):
ad = Person.objects.get(name="Ad No%s" % num)
e = BallotPositionDocEvent()
e.doc = draft
e.ballot = ballot
e.by = ad
e.ad = ad
e.pos = BallotPositionName.objects.get(slug=vote)
e.type = "changed_ballot_position"
e.comment = comment
if e.comment:
e.comment_time = datetime.datetime.now()
e.discuss = discuss
if e.discuss:
e.discuss_time = datetime.datetime.now()
e.save()
# active
create_pos(1, "yes", discuss="discuss1 " * 20)
create_pos(2, "noobj", comment="comment2 " * 20)
create_pos(3, "discuss", discuss="discuss3 " * 20, comment="comment3 " * 20)
create_pos(4, "abstain")
create_pos(5, "recuse")
# inactive
create_pos(9, "yes")
mailbox_before = len(outbox)
r = self.client.post(url, dict(
ballot_writeup="This is a test.",
issue_ballot="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue(draft.latest_event(type="sent_ballot_announcement"))
self.assertEquals(len(outbox), mailbox_before + 2)
issue_email = outbox[-2]
self.assertTrue("Evaluation:" in issue_email['Subject'])
self.assertTrue("comment1" not in str(issue_email))
self.assertTrue("comment2" in str(issue_email))
self.assertTrue("comment3" in str(issue_email))
self.assertTrue("discuss3" in str(issue_email))
self.assertTrue("This is a test" in str(issue_email))
self.assertTrue("The IESG has approved" in str(issue_email))
def test_edit_approval_text(self):
draft = make_test_data()
url = urlreverse('doc_ballot_approvaltext', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('textarea[name=approval_text]')), 1)
self.assertEquals(len(q('input[type=submit][value*="Save Approval"]')), 1)
# save
r = self.client.post(url, dict(
approval_text="This is a simple test.",
save_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
# test regenerate
r = self.client.post(url, dict(regenerate_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("Subject: Protocol Action" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
# test regenerate when it's a disapprove
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="nopubadw"))
r = self.client.post(url, dict(regenerate_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("NOT be published" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
# test regenerate when it's a conflict review
draft.group = Group.objects.get(type="individ")
draft.stream_id = "irtf"
draft.save()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva"))
r = self.client.post(url, dict(regenerate_approval_text="1"))
self.assertEquals(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue("Subject: Results of IETF-conflict review" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
class ApproveBallotTestCase(django.test.TestCase):
fixtures = ['names']
def test_approve_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, 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)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue("send out the announcement" in q('.actions input[type=submit]')[0].get('value').lower())
self.assertEquals(len(q('.announcement pre:contains("Subject: Protocol Action")')), 1)
# approve
mailbox_before = len(outbox)
r = self.client.post(url, dict(skiprfceditorpost="1"))
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
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
self.assertTrue("Protocol Action" in outbox[-1]['Subject'])
self.assertTrue(not outbox[-1]['CC'])
self.assertTrue("Protocol Action" in draft.message_set.order_by("-time")[0].subject)
def test_disapprove_ballot(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="nopubadw"))
url = urlreverse('doc_approve_ballot', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# disapprove (the Martians aren't going to be happy)
mailbox_before = len(outbox)
r = self.client.post(url, dict())
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
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]))
class MakeLastCallTestCase(django.test.TestCase):
fixtures = ['names']
def test_make_last_call(self):
draft = make_test_data()
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="lc-req"))
url = urlreverse('doc_make_last_call', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('input[name=last_call_sent_date]')), 1)
# make last call
mailbox_before = len(outbox)
expire_date = q('input[name=last_call_expiration_date]')[0].get("value")
r = self.client.post(url,
dict(last_call_sent_date=q('input[name=last_call_sent_date]')[0].get("value"),
last_call_expiration_date=expire_date
))
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
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)
self.assertTrue("Last Call" in outbox[-4]['Subject'])
# the IANA copy
self.assertTrue("Last Call" in outbox[-3]['Subject'])
self.assertTrue("Last Call" in draft.message_set.order_by("-time")[0].subject)
class RequestPublicationTestCase(django.test.TestCase):
fixtures = ['names']
def test_request_publication(self):
draft = make_test_data()
draft.stream = StreamName.objects.get(slug="iab")
draft.group = Group.objects.get(acronym="iab")
draft.intended_std_level = IntendedStdLevelName.objects.get(slug="inf")
draft.save()
draft.set_state(State.objects.get(used=True, type="draft-stream-iab", slug="approved"))
url = urlreverse('doc_request_publication', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "iabchair", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
subject = q('input#id_subject')[0].get("value")
self.assertTrue("Document Action" in subject)
body = q('.request-publication #id_body').text()
self.assertTrue("Informational" in body)
self.assertTrue("IAB" in body)
# approve
mailbox_before = len(outbox)
r = self.client.post(url, dict(subject=subject, body=body, skiprfceditorpost="1"))
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertEquals(draft.get_state_slug("draft-stream-iab"), "rfc-edit")
self.assertEquals(len(outbox), mailbox_before + 2)
self.assertTrue("Document Action" in outbox[-2]['Subject'])
self.assertTrue("Document Action" in draft.message_set.order_by("-time")[0].subject)
# the IANA copy
self.assertTrue("Document Action" in outbox[-1]['Subject'])
self.assertTrue(not outbox[-1]['CC'])
class ExpireIDsTestCase(django.test.TestCase):
fixtures = ['names']
@ -1019,7 +433,7 @@ class ExpireIDsTestCase(django.test.TestCase):
f.close()
def test_in_draft_expire_freeze(self):
from ietf.idrfc.expire import in_draft_expire_freeze
from ietf.doc.expire import in_draft_expire_freeze
Meeting.objects.create(number="123",
type=MeetingTypeName.objects.get(slug="ietf"),
@ -1034,7 +448,7 @@ class ExpireIDsTestCase(django.test.TestCase):
self.assertTrue(not in_draft_expire_freeze(datetime.datetime.combine(ietf_monday, time(0, 0, 0))))
def test_warn_expirable_drafts(self):
from ietf.idrfc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft
from ietf.doc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft
draft = make_test_data()
@ -1057,7 +471,7 @@ class ExpireIDsTestCase(django.test.TestCase):
self.assertTrue("wgchairman@ietf.org" in str(outbox[-1]))
def test_expire_drafts(self):
from ietf.idrfc.expire import get_expired_drafts, send_expire_notice_for_draft, expire_draft
from ietf.doc.expire import get_expired_drafts, send_expire_notice_for_draft, expire_draft
draft = make_test_data()
@ -1102,7 +516,7 @@ class ExpireIDsTestCase(django.test.TestCase):
def test_clean_up_draft_files(self):
draft = make_test_data()
from ietf.idrfc.expire import clean_up_draft_files
from ietf.doc.expire import clean_up_draft_files
# put unknown file
unknown = "draft-i-am-unknown-01.txt"
@ -1180,7 +594,7 @@ class ExpireLastCallTestCase(django.test.TestCase):
fixtures = ['names']
def test_expire_last_call(self):
from ietf.idrfc.lastcall import get_expired_last_calls, expire_last_call
from ietf.doc.lastcall import get_expired_last_calls, expire_last_call
# check that non-expirable drafts aren't expired
@ -1430,7 +844,6 @@ class IndividualInfoFormsTestCase(django.test.TestCase):
# direct edit
r = self.client.post(url,dict(content='here is a new writeup',submit_response="1"))
print r.content
self.assertEquals(r.status_code,302)
self.doc = Document.objects.get(name=self.docname)
self.assertTrue(self.doc.latest_event(WriteupDocEvent,type="changed_protocol_writeup").text.startswith('here is a new writeup'))
@ -1454,3 +867,41 @@ class IndividualInfoFormsTestCase(django.test.TestCase):
self.docname='draft-ietf-mars-test'
self.doc = Document.objects.get(name=self.docname)
class RequestPublicationTestCase(django.test.TestCase):
fixtures = ['names']
def test_request_publication(self):
draft = make_test_data()
draft.stream = StreamName.objects.get(slug="iab")
draft.group = Group.objects.get(acronym="iab")
draft.intended_std_level = IntendedStdLevelName.objects.get(slug="inf")
draft.save()
draft.set_state(State.objects.get(used=True, type="draft-stream-iab", slug="approved"))
url = urlreverse('doc_request_publication', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "iabchair", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
subject = q('input#id_subject')[0].get("value")
self.assertTrue("Document Action" in subject)
body = q('.request-publication #id_body').text()
self.assertTrue("Informational" in body)
self.assertTrue("IAB" in body)
# approve
mailbox_before = len(outbox)
r = self.client.post(url, dict(subject=subject, body=body, skiprfceditorpost="1"))
self.assertEquals(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertEquals(draft.get_state_slug("draft-stream-iab"), "rfc-edit")
self.assertEquals(len(outbox), mailbox_before + 2)
self.assertTrue("Document Action" in outbox[-2]['Subject'])
self.assertTrue("Document Action" in draft.message_set.order_by("-time")[0].subject)
# the IANA copy
self.assertTrue("Document Action" in outbox[-1]['Subject'])
self.assertTrue(not outbox[-1]['CC'])

View file

@ -31,8 +31,8 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from django.conf.urls.defaults import patterns, url, include
from ietf.idrfc import views_search, views_edit, views_ballot, views
from ietf.doc.models import State
from ietf.doc import views_search, views_draft, views_ballot
from ietf.doc import views_status_change
from ietf.doc import views_doc
@ -65,23 +65,23 @@ urlpatterns = patterns('',
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballotpopup/(?P<ballot_id>[0-9]+)/$', views_doc.ballot_popup),
#(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot.json$', views_doc.ballot_json), # legacy view
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='doc_change_state'), # IESG state
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/(?P<state_type>iana-action|iana-review)/$', views_edit.change_iana_state, name='doc_change_iana_state'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/info/$', views_edit.edit_info, name='doc_edit_info'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestresurrect/$', views_edit.request_resurrect, name='doc_request_resurrect'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/resurrect/$', views_edit.resurrect, name='doc_resurrect'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/addcomment/$', views_edit.add_comment, name='doc_add_comment'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', views_draft.change_state, name='doc_change_state'), # IESG state
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/(?P<state_type>iana-action|iana-review)/$', views_draft.change_iana_state, name='doc_change_iana_state'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/info/$', views_draft.edit_info, name='doc_edit_info'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestresurrect/$', views_draft.request_resurrect, name='doc_request_resurrect'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/resurrect/$', views_draft.resurrect, name='doc_resurrect'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/addcomment/$', views_doc.add_comment, name='doc_add_comment'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/stream/$', views_edit.change_stream, name='doc_change_stream'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/notify/$', views_edit.edit_notices, name='doc_change_notify'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/status/$', views_edit.change_intention, name='doc_change_intended_status'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/telechat/$', views_edit.telechat_date, name='doc_change_telechat_date'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/iesgnote/$', views_edit.edit_iesg_note, name='doc_change_iesg_note'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ad/$', views_edit.edit_ad, name='doc_change_ad'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/consensus/$', views_edit.edit_consensus, name='doc_edit_consensus'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/shepherd/$', views_edit.edit_shepherd, name='doc_edit_shepherd'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/shepherdwriteup/$', views_edit.edit_shepherd_writeup, name='doc_edit_shepherd_writeup'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestpublication/$', views_edit.request_publication, name='doc_request_publication'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/stream/$', views_draft.change_stream, name='doc_change_stream'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/notify/$', views_draft.edit_notices, name='doc_change_notify'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/status/$', views_draft.change_intention, name='doc_change_intended_status'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/telechat/$', views_draft.telechat_date, name='doc_change_telechat_date'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/iesgnote/$', views_draft.edit_iesg_note, name='doc_change_iesg_note'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ad/$', views_draft.edit_ad, name='doc_change_ad'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/consensus/$', views_draft.edit_consensus, name='doc_edit_consensus'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/shepherd/$', views_draft.edit_shepherd, name='doc_edit_shepherd'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/shepherdwriteup/$', views_draft.edit_shepherd_writeup, name='doc_edit_shepherd_writeup'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/requestpublication/$', views_draft.request_publication, name='doc_request_publication'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/clearballot/$', views_ballot.clear_ballot, name='doc_clear_ballot'),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/deferballot/$', views_ballot.defer_ballot, name='doc_defer_ballot'),
@ -98,10 +98,3 @@ urlpatterns = patterns('',
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
)
urlpatterns += patterns('django.views.generic.simple',
url(r'^help/state/charter/$', 'direct_to_template', { 'template': 'doc/states.html', 'extra_context': { 'states': State.objects.filter(used=True, type="charter"),'title':"Charter" } }, name='help_charter_states'),
url(r'^help/state/conflict-review/$', 'direct_to_template', { 'template': 'doc/states.html', 'extra_context': { 'states': State.objects.filter(used=True, type="conflrev").order_by("order"),'title':"Conflict Review" } }, name='help_conflict_review_states'),
url(r'^help/state/status-change/$', 'direct_to_template', { 'template': 'doc/states.html', 'extra_context': { 'states': State.objects.filter(type="statchg").order_by("order"),'title':"RFC Status Change" } }, name='help_status_change_states'),
)

View file

@ -3,9 +3,7 @@ import math
from django.conf import settings
# Should this move from idrfc to doc?
from ietf.idrfc import markup_txt
from ietf.utils import markup_txt
from ietf.doc.models import *
def get_state_types(doc):
@ -241,3 +239,54 @@ def nice_consensus(consensus):
False: "No"
}
return mapping[consensus]
def update_telechat(request, doc, by, new_telechat_date, new_returning_item=None):
from ietf.doc.models import TelechatDocEvent
on_agenda = bool(new_telechat_date)
prev = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
prev_returning = bool(prev and prev.returning_item)
prev_telechat = prev.telechat_date if prev else None
prev_agenda = bool(prev_telechat)
returning_item_changed = bool(new_returning_item != None and new_returning_item != prev_returning)
if new_returning_item == None:
returning = prev_returning
else:
returning = new_returning_item
if returning == prev_returning and new_telechat_date == prev_telechat:
# fully updated, nothing to do
return
# auto-update returning item
if (not returning_item_changed and on_agenda and prev_agenda
and new_telechat_date != prev_telechat):
returning = True
e = TelechatDocEvent()
e.type = "scheduled_for_telechat"
e.by = by
e.doc = doc
e.returning_item = returning
e.telechat_date = new_telechat_date
if on_agenda != prev_agenda:
if on_agenda:
e.desc = "Placed on agenda for telechat - %s" % (new_telechat_date)
else:
e.desc = "Removed from agenda for telechat"
elif on_agenda and new_telechat_date != prev_telechat:
e.desc = "Telechat date has been changed to <b>%s</b> from <b>%s</b>" % (
new_telechat_date, prev_telechat)
else:
# we didn't reschedule but flipped returning item bit - let's
# just explain that
if returning:
e.desc = "Set telechat returning item indication"
else:
e.desc = "Removed telechat returning item indication"
e.save()

View file

@ -1,8 +1,8 @@
# ballot management (voting, commenting, writeups, ...) for Area
# Directors and Secretariat
import re, os
from datetime import datetime, date, time, timedelta
import re, os, datetime
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
from django.shortcuts import render_to_response, get_object_or_404
from django.core.urlresolvers import reverse as urlreverse
@ -16,16 +16,12 @@ from django.conf import settings
import debug
from ietf.utils.mail import send_mail_text, send_mail_preformatted
from ietf.ietfauth.decorators import group_required, role_required
from ietf.idtracker.templatetags.ietf_filters import in_group
from ietf.ietfauth.decorators import has_role, role_required
from ietf.idtracker.models import *
from ietf.iesg.models import *
from ietf.iesg.models import TelechatDate
from ietf.ipr.models import IprDetail
from ietf.ipr.search import iprs_from_docs
from ietf.idrfc.mails import *
from ietf.idrfc.utils import *
from ietf.idrfc.lastcall import request_last_call
from ietf.doc.mails import *
from ietf.doc.lastcall import request_last_call
from ietf.doc.utils import *
from ietf.doc.models import *
@ -34,9 +30,6 @@ from ietf.name.models import BallotPositionName
from ietf.message.utils import infer_message
from ietf.person.models import Person
from ietf.doc.utils import log_state_changed as docutil_log_state_changed
from ietf.idrfc.utils import log_state_changed as idrfcutil_log_state_changed
BALLOT_CHOICES = (("yes", "Yes"),
("noobj", "No Objection"),
("discuss", "Discuss"),
@ -54,20 +47,20 @@ def do_undefer_ballot(request, doc):
logging, and the Document object.
'''
login = request.user.get_profile()
telechat_date = TelechatDates.objects.all()[0].date1
telechat_date = TelechatDate.objects.active().order_by("date")[0].date
save_document_in_history(doc)
prev_state = doc.friendly_state()
if doc.type_id == 'draft':
doc.set_state(State.objects.get(used=True, type="draft-iesg", slug='iesg-eva'))
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
prev_tag = prev_tag[0] if prev_tag else None
if prev_tag:
doc.tags.remove(prev_tag)
elif doc.type_id == 'conflrev':
doc.set_state(State.objects.get(used=True, type='conflrev',slug='iesgeval'))
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
doc.time = e.time
doc.save()
@ -96,15 +89,8 @@ def get_ballot_info(ballot, area_director):
return (pos, discuss, comment)
class EditPositionForm(forms.Form):
pass
# -------------------------------------------------
@group_required('Area_Director','Secretariat')
def edit_position(request, name):
pass
class EditPositionFormREDESIGN(forms.Form):
class EditPositionForm(forms.Form):
position = forms.ModelChoiceField(queryset=BallotPositionName.objects.all(), widget=forms.RadioSelect, initial="norecord", required=True)
discuss = forms.CharField(required=False, widget=forms.Textarea)
comment = forms.CharField(required=False, widget=forms.Textarea)
@ -123,7 +109,7 @@ class EditPositionFormREDESIGN(forms.Form):
return entered_discuss
@role_required('Area Director','Secretariat')
def edit_positionREDESIGN(request, name, ballot_id):
def edit_position(request, name, ballot_id):
"""Vote and edit discuss and comment on document as Area Director."""
doc = get_object_or_404(Document, docalias__name=name)
ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc)
@ -244,7 +230,7 @@ def edit_positionREDESIGN(request, name, ballot_id):
ballot_deferred = doc.active_defer_event()
return render_to_response('idrfc/edit_positionREDESIGN.html',
return render_to_response('doc/ballot/edit_position.html',
dict(doc=doc,
form=form,
ad=ad,
@ -257,85 +243,9 @@ def edit_positionREDESIGN(request, name, ballot_id):
),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
edit_position = edit_positionREDESIGN
EditPositionForm = EditPositionFormREDESIGN
@group_required('Area_Director','Secretariat')
def send_ballot_comment(request, name):
"""Email Internet Draft ballot discuss/comment for area director."""
doc = get_object_or_404(InternetDraft, filename=name)
if not doc.idinternal:
raise Http404()
ad = login = IESGLogin.objects.get(login_name=request.user.username)
return_to_url = request.GET.get('return_to_url')
if not return_to_url:
return_to_url = doc.idinternal.get_absolute_url()
if 'HTTP_REFERER' in request.META:
back_url = request.META['HTTP_REFERER']
else:
back_url = doc.idinternal.get_absolute_url()
# if we're in the Secretariat, we can select an AD to act as stand-in for
if not in_group(request.user, "Area_Director"):
ad_username = request.GET.get('ad')
if not ad_username:
raise Http404()
ad = get_object_or_404(IESGLogin, login_name=ad_username)
pos, discuss, comment = get_ballot_info(doc.idinternal.ballot, ad)
subj = []
d = ""
if pos and pos.discuss == 1 and discuss and discuss.text:
d = discuss.text
subj.append("DISCUSS")
c = ""
if comment and comment.text:
c = comment.text
subj.append("COMMENT")
ad_name = str(ad)
ad_name_genitive = ad_name + "'" if ad_name.endswith('s') else ad_name + "'s"
subject = "%s %s on %s" % (ad_name_genitive, pos.name() if pos else "No Position" , doc.filename + '-' + doc.revision_display())
if subj:
subject += ": (with "+" and ".join(subj)+")"
body = render_to_string("idrfc/ballot_comment_mail.txt",
dict(discuss=d, comment=c, ad=ad, doc=doc, pos=pos, settings=settings))
frm = u"%s <%s>" % ad.person.email()
to = "The IESG <iesg@ietf.org>"
if request.method == 'POST':
cc = [x.strip() for x in request.POST.get("cc", "").split(',') if x.strip()]
if request.POST.get("cc_state_change") and doc.idinternal.state_change_notice_to:
cc.extend(doc.idinternal.state_change_notice_to.split(','))
send_mail_text(request, to, frm, subject, body, cc=", ".join(cc))
return HttpResponseRedirect(return_to_url)
return render_to_response('idrfc/send_ballot_comment.html',
dict(doc=doc,
subject=subject,
body=body,
frm=frm,
to=to,
ad=ad,
can_send=d or c,
back_url=back_url,
),
context_instance=RequestContext(request))
@role_required('Area Director','Secretariat')
def send_ballot_commentREDESIGN(request, name, ballot_id):
def send_ballot_comment(request, name, ballot_id):
"""Email document ballot position discuss/comment for Area Director."""
doc = get_object_or_404(Document, docalias__name=name)
ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc)
@ -379,7 +289,7 @@ def send_ballot_commentREDESIGN(request, name, ballot_id):
if subj:
subject += ": (with %s)" % " and ".join(subj)
body = render_to_string("idrfc/ballot_comment_mail.txt",
body = render_to_string("doc/ballot/ballot_comment_mail.txt",
dict(discuss=d,
comment=c,
ad=ad.plain_name(),
@ -395,11 +305,11 @@ def send_ballot_commentREDESIGN(request, name, ballot_id):
if request.POST.get("cc_state_change") and doc.notify:
cc.extend(doc.notify.split(','))
send_mail_text(request, to, frm, subject, body, cc=", ".join(cc))
send_mail_text(request, to, frm, subject, body, cc=u", ".join(cc))
return HttpResponseRedirect(return_to_url)
return render_to_response('idrfc/send_ballot_commentREDESIGN.html',
return render_to_response('doc/ballot/send_ballot_comment.html',
dict(doc=doc,
subject=subject,
body=body,
@ -411,10 +321,7 @@ def send_ballot_commentREDESIGN(request, name, ballot_id):
),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
send_ballot_comment = send_ballot_commentREDESIGN
@group_required('Secretariat')
@role_required('Secretariat')
def clear_ballot(request, name):
"""Clear all positions and discusses on every open ballot for a document."""
doc = get_object_or_404(Document, name=name)
@ -427,17 +334,13 @@ def clear_ballot(request, name):
do_undefer_ballot(request,doc)
return HttpResponseRedirect(urlreverse("doc_view", kwargs=dict(name=doc.name)))
return render_to_response('idrfc/clear_ballot.html',
return render_to_response('doc/ballot/clear_ballot.html',
dict(doc=doc,
back_url=doc.get_absolute_url()),
context_instance=RequestContext(request))
@group_required('Area_Director','Secretariat')
@role_required('Area Director','Secretariat')
def defer_ballot(request, name):
pass
@group_required('Area_Director','Secretariat')
def defer_ballotREDESIGN(request, name):
"""Signal post-pone of ballot, notifying relevant parties."""
doc = get_object_or_404(Document, docalias__name=name)
if doc.type_id not in ('draft','conflrev'):
@ -446,7 +349,7 @@ def defer_ballotREDESIGN(request, name):
raise Http404()
login = request.user.get_profile()
telechat_date = TelechatDates.objects.all()[0].date2
telechat_date = TelechatDate.objects.active().order_by("date")[1].date
if request.method == 'POST':
save_document_in_history(doc)
@ -461,7 +364,7 @@ def defer_ballotREDESIGN(request, name):
elif doc.type_id == 'conflrev':
doc.set_state(State.objects.get(used=True, type='conflrev', slug='defer'))
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
doc.time = e.time
doc.save()
@ -473,21 +376,14 @@ def defer_ballotREDESIGN(request, name):
return HttpResponseRedirect(doc.get_absolute_url())
return render_to_response('idrfc/defer_ballot.html',
return render_to_response('doc/ballot/defer_ballot.html',
dict(doc=doc,
telechat_date=telechat_date,
back_url=doc.get_absolute_url()),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
defer_ballot = defer_ballotREDESIGN
@group_required('Area_Director','Secretariat')
@role_required('Area Director','Secretariat')
def undefer_ballot(request, name):
pass
@group_required('Area_Director','Secretariat')
def undefer_ballotREDESIGN(request, name):
"""undo deferral of ballot ballot."""
doc = get_object_or_404(Document, docalias__name=name)
if doc.type_id not in ('draft','conflrev'):
@ -495,109 +391,19 @@ def undefer_ballotREDESIGN(request, name):
if doc.type_id == 'draft' and not doc.get_state("draft-iesg"):
raise Http404()
telechat_date = TelechatDates.objects.all()[0].date1
telechat_date = TelechatDate.objects.active().order_by("date")[0].date
if request.method == 'POST':
do_undefer_ballot(request,doc)
return HttpResponseRedirect(doc.get_absolute_url())
return render_to_response('idrfc/undefer_ballot.html',
return render_to_response('doc/ballot/undefer_ballot.html',
dict(doc=doc,
telechat_date=telechat_date,
back_url=doc.get_absolute_url()),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
undefer_ballot = undefer_ballotREDESIGN
class LastCallTextForm(forms.ModelForm):
def clean_last_call_text(self):
lines = self.cleaned_data["last_call_text"].split("\r\n")
for l, next in zip(lines, lines[1:]):
if l.startswith('Subject:') and next.strip():
raise forms.ValidationError("Subject line appears to have a line break, please make sure there is no line breaks in the subject line and that it is followed by an empty line.")
return self.cleaned_data["last_call_text"].replace("\r", "")
class Meta:
model = BallotInfo
fields = ["last_call_text"]
class BallotWriteupForm(forms.ModelForm):
class Meta:
model = BallotInfo
fields = ["ballot_writeup"]
def clean_ballot_writeup(self):
return self.cleaned_data["ballot_writeup"].replace("\r", "")
@group_required('Area_Director','Secretariat')
def lastcalltext(request, name):
"""Editing of the last call text"""
doc = get_object_or_404(InternetDraft, filename=name)
if not doc.idinternal:
raise Http404()
login = IESGLogin.objects.get(login_name=request.user.username)
try:
ballot = doc.idinternal.ballot
except BallotInfo.DoesNotExist:
ballot = generate_ballot(request, doc)
last_call_form = LastCallTextForm(instance=ballot)
if request.method == 'POST':
if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST:
last_call_form = LastCallTextForm(request.POST, instance=ballot)
if last_call_form.is_valid():
ballot.last_call_text = last_call_form.cleaned_data["last_call_text"]
add_document_comment(request, doc, "Last Call text changed")
ballot.save()
if "send_last_call_request" in request.POST:
doc.idinternal.change_state(IDState.objects.get(document_state_id=IDState.LAST_CALL_REQUESTED), None)
change = idrfcutil_log_state_changed(request, doc, login)
email_owner(request, doc, doc.idinternal.job_owner, login, change)
request_last_call(request, doc)
doc.idinternal.event_date = date.today()
doc.idinternal.save()
return render_to_response('idrfc/last_call_requested.html',
dict(doc=doc),
context_instance=RequestContext(request))
if "regenerate_last_call_text" in request.POST:
ballot.last_call_text = generate_last_call_announcement(request, doc)
ballot.save()
# make sure form has the updated text
last_call_form = LastCallTextForm(instance=ballot)
doc.idinternal.event_date = date.today()
doc.idinternal.save()
can_request_last_call = doc.idinternal.cur_state_id < 27
can_make_last_call = doc.idinternal.cur_state_id < 20
can_announce = doc.idinternal.cur_state_id > 19
docs_with_invalid_status = [d.document().file_tag() for d in doc.idinternal.ballot_set() if "None" in d.document().intended_status.intended_status or "Request" in d.document().intended_status.intended_status]
need_intended_status = ", ".join(docs_with_invalid_status)
return render_to_response('idrfc/ballot_lastcalltext.html',
dict(doc=doc,
back_url=doc.idinternal.get_absolute_url(),
ballot=ballot,
last_call_form=last_call_form,
can_request_last_call=can_request_last_call,
can_make_last_call=can_make_last_call,
need_intended_status=need_intended_status,
),
context_instance=RequestContext(request))
class LastCallTextFormREDESIGN(forms.Form):
class LastCallTextForm(forms.Form):
last_call_text = forms.CharField(widget=forms.Textarea, required=True)
def clean_last_call_text(self):
@ -608,8 +414,9 @@ class LastCallTextFormREDESIGN(forms.Form):
return self.cleaned_data["last_call_text"].replace("\r", "")
@group_required('Area_Director','Secretariat')
def lastcalltextREDESIGN(request, name):
@role_required('Area Director','Secretariat')
def lastcalltext(request, name):
"""Editing of the last call text"""
doc = get_object_or_404(Document, docalias__name=name)
if not doc.get_state("draft-iesg"):
@ -639,7 +446,7 @@ def lastcalltextREDESIGN(request, name):
if "send_last_call_request" in request.POST:
save_document_in_history(doc)
prev = doc.get_state("draft-iesg")
prev_state = doc.friendly_state()
doc.set_state(State.objects.get(used=True, type="draft-iesg", slug='lc-req'))
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
@ -647,17 +454,17 @@ def lastcalltextREDESIGN(request, name):
if prev_tag:
doc.tags.remove(prev_tag)
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
doc.time = e.time
doc.save()
email_state_changed(request, doc, e.desc)
email_owner(request, doc, doc.ad, login, e.desc)
email_ad(request, doc, doc.ad, login, e.desc)
request_last_call(request, doc)
return render_to_response('idrfc/last_call_requested.html',
return render_to_response('doc/draft/last_call_requested.html',
dict(doc=doc),
context_instance=RequestContext(request))
@ -677,7 +484,7 @@ def lastcalltextREDESIGN(request, name):
if not doc.intended_std_level:
need_intended_status = doc.file_tag()
return render_to_response('idrfc/ballot_lastcalltext.html',
return render_to_response('doc/ballot/lastcalltext.html',
dict(doc=doc,
back_url=doc.get_absolute_url(),
last_call_form=form,
@ -687,95 +494,14 @@ def lastcalltextREDESIGN(request, name):
),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
LastCallTextForm = LastCallTextFormREDESIGN
lastcalltext = lastcalltextREDESIGN
@group_required('Area_Director','Secretariat')
def ballot_writeupnotes(request, name):
"""Editing of ballot write-up and notes"""
doc = get_object_or_404(InternetDraft, filename=name)
if not doc.idinternal:
raise Http404()
login = IESGLogin.objects.get(login_name=request.user.username)
try:
ballot = doc.idinternal.ballot
except BallotInfo.DoesNotExist:
ballot = generate_ballot(request, doc)
ballot_writeup_form = BallotWriteupForm(instance=ballot)
if request.method == 'POST':
if "save_ballot_writeup" in request.POST:
ballot_writeup_form = BallotWriteupForm(request.POST, instance=ballot)
if ballot_writeup_form.is_valid():
ballot.ballot_writeup = ballot_writeup_form.cleaned_data["ballot_writeup"]
add_document_comment(request, doc, "Ballot writeup text changed")
ballot.save()
if "issue_ballot" in request.POST:
ballot_writeup_form = BallotWriteupForm(request.POST, instance=ballot)
approval_text_form = ApprovalTextForm(request.POST, instance=ballot)
if ballot_writeup_form.is_valid() and approval_text_form.is_valid():
ballot.ballot_writeup = ballot_writeup_form.cleaned_data["ballot_writeup"]
ballot.approval_text = approval_text_form.cleaned_data["approval_text"]
ballot.active = True
ballot.ballot_issued = True
ballot.save()
if not Position.objects.filter(ballot=ballot, ad=login):
pos = Position()
pos.ballot = ballot
pos.ad = login
pos.yes = 1
pos.noobj = pos.abstain = pos.approve = pos.discuss = pos.recuse = 0
pos.save()
msg = generate_issue_ballot_mail(request, doc)
send_mail_preformatted(request, msg)
# email_iana(request, doc, 'drafts-eval@icann.org', msg)
doc.b_sent_date = date.today()
doc.save()
add_document_comment(request, doc, "Ballot has been issued")
doc.idinternal.event_date = date.today()
doc.idinternal.save()
return render_to_response('idrfc/ballot_issued.html',
dict(doc=doc,
back_url=doc.idinternal.get_absolute_url()),
context_instance=RequestContext(request))
doc.idinternal.event_date = date.today()
doc.idinternal.save()
docs_with_invalid_status = [d.document().file_tag() for d in doc.idinternal.ballot_set() if "None" in d.document().intended_status.intended_status or "Request" in d.document().intended_status.intended_status]
need_intended_status = ", ".join(docs_with_invalid_status)
return render_to_response('idrfc/ballot_writeupnotes.html',
dict(doc=doc,
ballot=ballot,
ballot_writeup_form=ballot_writeup_form,
need_intended_status=need_intended_status,
),
context_instance=RequestContext(request))
class BallotWriteupFormREDESIGN(forms.Form):
class BallotWriteupForm(forms.Form):
ballot_writeup = forms.CharField(widget=forms.Textarea, required=True)
def clean_ballot_writeup(self):
return self.cleaned_data["ballot_writeup"].replace("\r", "")
@group_required('Area_Director','Secretariat')
def ballot_writeupnotesREDESIGN(request, name):
@role_required('Area Director','Secretariat')
def ballot_writeupnotes(request, name):
"""Editing of ballot write-up and notes"""
doc = get_object_or_404(Document, docalias__name=name)
@ -828,7 +554,7 @@ def ballot_writeupnotesREDESIGN(request, name):
e.desc = "Ballot has been issued"
e.save()
return render_to_response('idrfc/ballot_issued.html',
return render_to_response('doc/ballot/ballot_issued.html',
dict(doc=doc,
back_url=doc.get_absolute_url()),
context_instance=RequestContext(request))
@ -838,7 +564,7 @@ def ballot_writeupnotesREDESIGN(request, name):
if not doc.intended_std_level:
need_intended_status = doc.file_tag()
return render_to_response('idrfc/ballot_writeupnotesREDESIGN.html',
return render_to_response('doc/ballot/writeupnotes.html',
dict(doc=doc,
back_url=doc.get_absolute_url(),
ballot_issued=bool(doc.latest_event(type="sent_ballot_announcement")),
@ -847,19 +573,13 @@ def ballot_writeupnotesREDESIGN(request, name):
),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
BallotWriteupForm = BallotWriteupFormREDESIGN
ballot_writeupnotes = ballot_writeupnotesREDESIGN
class ApprovalTextForm(forms.Form):
approval_text = forms.CharField(widget=forms.Textarea, required=True)
def clean_approval_text(self):
return self.cleaned_data["approval_text"].replace("\r", "")
@group_required('Area_Director','Secretariat')
@role_required('Area Director','Secretariat')
def ballot_approvaltext(request, name):
"""Editing of approval text"""
doc = get_object_or_404(Document, docalias__name=name)
@ -898,7 +618,7 @@ def ballot_approvaltext(request, name):
if not doc.intended_std_level:
need_intended_status = doc.file_tag()
return render_to_response('idrfc/ballot_approvaltext.html',
return render_to_response('doc/ballot/approvaltext.html',
dict(doc=doc,
back_url=doc.get_absolute_url(),
approval_text_form=form,
@ -907,80 +627,8 @@ def ballot_approvaltext(request, name):
),
context_instance=RequestContext(request))
@group_required('Secretariat')
@role_required('Secretariat')
def approve_ballot(request, name):
"""Approve ballot, sending out announcement, changing state."""
doc = get_object_or_404(InternetDraft, filename=name)
if not doc.idinternal:
raise Http404()
login = IESGLogin.objects.get(login_name=request.user.username)
ballot = doc.idinternal.ballot
if "To: RFC Editor" in ballot.approval_text:
action = "to_rfc_editor"
elif "NOT be published" in ballot.approval_text:
action = "do_not_publish"
else:
action = "to_announcement_list"
announcement = ballot.approval_text + "\n\n" + ballot.ballot_writeup
if request.method == 'POST':
for i in doc.idinternal.ballot_set():
if action == "do_not_publish":
new_state = IDState.DEAD
else:
new_state = IDState.APPROVED_ANNOUNCEMENT_SENT
i.change_state(IDState.objects.get(document_state_id=new_state), None)
if action == "do_not_publish":
i.dnp = True
i.dnp_date = date.today()
i.noproblem = False
if action == "to_rfc_editor":
i.noproblem = True
i.event_date = date.today()
i.save()
i.document().b_approve_date = date.today()
i.document().save()
if action == "do_not_publish":
comment = "Do Not Publish note has been sent to RFC Editor"
else:
comment = "IESG has approved"
comment += " and state has been changed to %s" % i.cur_state.state
add_document_comment(request, i.document(), comment)
email_owner(request, i.document(), i.job_owner, login, comment)
email_state_changed(request, i.document(), strip_tags(comment))
send_mail_preformatted(request, announcement)
ballot.an_sent = True
ballot.an_sent_date = date.today()
ballot.an_sent_by = login
ballot.save()
if action == "to_announcement_list":
email_iana(request, doc, "drafts-approval@icann.org", announcement)
return HttpResponseRedirect(doc.idinternal.get_absolute_url())
return render_to_response('idrfc/approve_ballot.html',
dict(doc=doc,
action=action,
announcement=announcement),
context_instance=RequestContext(request))
@group_required('Secretariat')
def approve_ballotREDESIGN(request, name):
"""Approve ballot, sending out announcement, changing state."""
doc = get_object_or_404(Document, docalias__name=name)
if not doc.get_state("draft-iesg"):
@ -1017,13 +665,14 @@ def approve_ballotREDESIGN(request, name):
else:
new_state = State.objects.get(used=True, type="draft-iesg", slug="ann")
prev_friendly_state = doc.friendly_state()
prev_state = doc.get_state("draft-iesg")
if new_state.slug == "ann" and new_state.slug != prev_state.slug and not request.REQUEST.get("skiprfceditorpost"):
# start by notifying the RFC Editor
import ietf.sync.rfceditor
response, error = ietf.sync.rfceditor.post_approved_draft(settings.RFC_EDITOR_SYNC_NOTIFICATION_URL, doc.name)
if error:
return render_to_response('doc/rfceditor_post_approved_draft_failed.html',
return render_to_response('doc/draft/rfceditor_post_approved_draft_failed.html',
dict(name=doc.name,
response=response,
error=error),
@ -1053,13 +702,13 @@ def approve_ballotREDESIGN(request, name):
change_description = e.desc + " and state has been changed to %s" % doc.get_state("draft-iesg").name
e = idrfcutil_log_state_changed(request, doc, login, prev_state, prev_tag)
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_friendly_state)
doc.time = e.time
doc.save()
email_state_changed(request, doc, change_description)
email_owner(request, doc, doc.ad, login, change_description)
email_ad(request, doc, doc.ad, login, change_description)
# send announcement
@ -1076,21 +725,18 @@ def approve_ballotREDESIGN(request, name):
return HttpResponseRedirect(doc.get_absolute_url())
return render_to_response('idrfc/approve_ballot.html',
return render_to_response('doc/ballot/approve_ballot.html',
dict(doc=doc,
action=action,
announcement=announcement),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
approve_ballot = approve_ballotREDESIGN
class MakeLastCallForm(forms.Form):
last_call_sent_date = forms.DateField(required=True)
last_call_expiration_date = forms.DateField(required=True)
@group_required('Secretariat')
@role_required('Secretariat')
def make_last_call(request, name):
"""Make last call for Internet Draft, sending out announcement."""
doc = get_object_or_404(Document, docalias__name=name)
@ -1121,31 +767,28 @@ def make_last_call(request, name):
save_document_in_history(doc)
prev_state = doc.get_state("draft-iesg")
if doc.type.slug == 'draft':
prev = doc.get_state("draft-iesg")
doc.set_state(State.objects.get(used=True, type="draft-iesg", slug='lc'))
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
prev_tag = prev_tag[0] if prev_tag else None
if prev_tag:
doc.tags.remove(prev_tag)
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
change_description = "Last call has been made for %s and state has been changed to %s" % (doc.name, doc.get_state("draft-iesg").name)
elif doc.type.slug == 'statchg':
prev = doc.friendly_state()
doc.set_state(State.objects.get(used=True, type="statchg", slug='in-lc'))
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev)
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
change_description = "Last call has been made for %s and state has been changed to %s" % (doc.name, doc.friendly_state())
doc.time = e.time
doc.save()
email_state_changed(request, doc, change_description)
email_owner(request, doc, doc.ad, login, change_description)
email_ad(request, doc, doc.ad, login, change_description)
e = LastCallDocEvent(doc=doc, by=login)
e.type = "sent_last_call"
@ -1168,18 +811,18 @@ def make_last_call(request, name):
return HttpResponseRedirect(doc.get_absolute_url())
else:
initial = {}
initial["last_call_sent_date"] = date.today()
initial["last_call_sent_date"] = datetime.date.today()
if doc.type.slug == 'draft':
# This logic is repeated in the code that edits last call text - why?
expire_days = 14
if doc.group.type_id in ("individ", "area"):
expire_days = 28
templ = 'idrfc/make_last_callREDESIGN.html'
templ = 'doc/draft/make_last_call.html'
else:
expire_days=28
templ = 'doc/status_change/make_last_call.html'
initial["last_call_expiration_date"] = date.today() + timedelta(days=expire_days)
initial["last_call_expiration_date"] = datetime.date.today() + datetime.timedelta(days=expire_days)
form = MakeLastCallForm(initial=initial)

View file

@ -8,16 +8,14 @@ from django.template import RequestContext
from django.template.loader import render_to_string
from django.conf import settings
from ietf.idrfc.utils import update_telechat
from ietf.doc.utils import log_state_changed
from ietf.doc.utils import log_state_changed, update_telechat
from ietf.doc.models import save_document_in_history
from ietf.doc.utils import create_ballot_if_not_open, close_open_ballots, get_document_content
from ietf.ietfauth.decorators import has_role, role_required
from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.utils.mail import send_mail_preformatted
from ietf.idrfc.mails import email_iana
from ietf.doc.mails import email_iana
from ietf.doc.models import State, Document, DocHistory, DocAlias
from ietf.doc.models import DocEvent, NewRevisionDocEvent, WriteupDocEvent, TelechatDocEvent, BallotDocEvent, BallotPositionDocEvent
@ -89,7 +87,7 @@ def change_state(request, name, option=None):
dict(form=form,
doc=review,
login=login,
help_url=reverse('help_conflict_review_states'),
help_url=reverse('state_help', kwargs=dict(type="conflict-review")),
),
context_instance=RequestContext(request))

View file

@ -42,6 +42,7 @@ from django.utils.decorators import decorator_from_middleware
from django.middleware.gzip import GZipMiddleware
from django.core.urlresolvers import reverse as urlreverse, NoReverseMatch
from django.conf import settings
from django import forms
from ietf.doc.models import *
from ietf.doc.utils import *
@ -50,6 +51,7 @@ from ietf.ietfauth.utils import *
from ietf.doc.views_status_change import RELATION_SLUGS as status_change_relationships
from ietf.wgcharter.utils import historic_milestones_for_charter
from ietf.ipr.models import IprDocAlias
from ietf.doc.mails import email_ad
def render_document_top(request, doc, tab, name):
tabs = []
@ -455,7 +457,7 @@ def document_main(request, name, rev=None):
else:
sorted_relations=None
return render_to_response("idrfc/document_status_change.html",
return render_to_response("doc/document_status_change.html",
dict(doc=doc,
top=top,
content=content,
@ -773,3 +775,35 @@ def ballot_json(request, name):
response.write(json.dumps(ballot.dict(), indent=2))
return response
class AddCommentForm(forms.Form):
comment = forms.CharField(required=True, widget=forms.Textarea)
@role_required('Area Director', 'Secretariat', 'IANA', 'RFC Editor')
def add_comment(request, name):
"""Add comment to history of document."""
doc = get_object_or_404(Document, docalias__name=name)
login = request.user.get_profile()
if request.method == 'POST':
form = AddCommentForm(request.POST)
if form.is_valid():
c = form.cleaned_data['comment']
e = DocEvent(doc=doc, by=login)
e.type = "added_comment"
e.desc = c
e.save()
if doc.type_id == "draft":
email_ad(request, doc, doc.ad, login,
"A new comment added by %s" % login.name)
return HttpResponseRedirect(urlreverse("doc_history", kwargs=dict(name=doc.name)))
else:
form = AddCommentForm()
return render_to_response('doc/add_comment.html',
dict(doc=doc,
form=form),
context_instance=RequestContext(request))

View file

@ -1,8 +1,7 @@
# changing state and metadata and commenting on Internet Drafts for
# Area Directors and Secretariat
# changing state and metadata on Internet Drafts
import re, os, datetime
import re, os
from datetime import datetime, date, time, timedelta
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
from django.shortcuts import render_to_response, get_object_or_404
from django.core.urlresolvers import reverse as urlreverse
@ -16,14 +15,11 @@ from django.forms.util import ErrorList
from django.contrib.auth.decorators import login_required
from ietf.utils.mail import send_mail_text, send_mail_message
from ietf.ietfauth.decorators import group_required, has_role, role_required
from ietf.ietfauth.utils import user_is_person
from ietf.idtracker.templatetags.ietf_filters import in_group
from ietf.idtracker.models import *
from ietf.iesg.models import *
from ietf.idrfc.mails import *
from ietf.idrfc.utils import *
from ietf.idrfc.lastcall import request_last_call
from ietf.ietfauth.decorators import role_required
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_person
from ietf.iesg.models import TelechatDate
from ietf.doc.mails import *
from ietf.doc.lastcall import request_last_call
from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.person.forms import EmailsField
from ietf.group.models import Group
@ -38,16 +34,8 @@ from ietf.doc.utils import *
from ietf.name.models import IntendedStdLevelName, DocTagName, StreamName
from ietf.person.models import Person, Email
from ietf.message.models import Message
from ietf.idrfc.utils import log_state_changed
class ChangeStateForm(forms.Form):
pass
@group_required('Area_Director','Secretariat')
def change_state(request, name):
pass
class ChangeStateFormREDESIGN(forms.Form):
state = forms.ModelChoiceField(State.objects.filter(used=True, type="draft-iesg"), empty_label=None, required=True)
substate = forms.ModelChoiceField(DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS), required=False)
comment = forms.CharField(widget=forms.Textarea, required=False)
@ -62,15 +50,15 @@ class ChangeStateFormREDESIGN(forms.Form):
# tag handling is a bit awkward since the UI still works
# as if IESG tags are a substate
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
prev_tag = prev_tag[0] if prev_tag else None
if state == prev and tag == prev_tag:
self._errors['comment'] = ErrorList([u'State not changed. Comments entered will be lost with no state change. Please go back and use the Add Comment feature on the history tab to add comments without changing state.'])
return retclean
@group_required('Area_Director','Secretariat')
def change_stateREDESIGN(request, name):
@role_required('Area Director','Secretariat')
def change_state(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)
@ -85,6 +73,7 @@ def change_stateREDESIGN(request, name):
if form.is_valid():
next_state = form.cleaned_data['state']
prev_state = doc.get_state("draft-iesg")
prev_friendly_state = doc.friendly_state()
tag = form.cleaned_data['substate']
comment = form.cleaned_data['comment'].strip()
@ -105,7 +94,7 @@ def change_stateREDESIGN(request, name):
if tag:
doc.tags.add(tag)
e = log_state_changed(request, doc, login, prev_state, prev_tag)
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_friendly_state)
if comment:
c = DocEvent(type="added_comment")
@ -120,7 +109,7 @@ def change_stateREDESIGN(request, name):
doc.save()
email_state_changed(request, doc, e.desc)
email_owner(request, doc, doc.ad, login, e.desc)
email_ad(request, doc, doc.ad, login, e.desc)
if prev_state and prev_state.slug in ("ann", "rfcqueue") and next_state.slug not in ("rfcqueue", "pub"):
@ -133,7 +122,7 @@ def change_stateREDESIGN(request, name):
if next_state.slug == "lc-req":
request_last_call(request, doc)
return render_to_response('idrfc/last_call_requested.html',
return render_to_response('doc/draft/last_call_requested.html',
dict(doc=doc,
url=doc.get_absolute_url()),
context_instance=RequestContext(request))
@ -161,7 +150,7 @@ def change_stateREDESIGN(request, name):
to_iesg_eval = State.objects.get(used=True, type="draft-iesg", slug="iesg-eva")
next_states = next_states.exclude(slug="iesg-eva")
return render_to_response('idrfc/change_stateREDESIGN.html',
return render_to_response('doc/draft/change_state.html',
dict(form=form,
doc=doc,
state=state,
@ -170,10 +159,6 @@ def change_stateREDESIGN(request, name):
to_iesg_eval=to_iesg_eval),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
change_state = change_stateREDESIGN
ChangeStateForm = ChangeStateFormREDESIGN
class ChangeIanaStateForm(forms.Form):
state = forms.ModelChoiceField(State.objects.all(), required=False)
@ -213,7 +198,7 @@ def change_iana_state(request, name, state_type):
else:
form = ChangeIanaStateForm(state_type, initial=dict(state=prev_state.pk if prev_state else None))
return render_to_response('idrfc/change_iana_state.html',
return render_to_response('doc/draft/change_iana_state.html',
dict(form=form,
doc=doc),
context_instance=RequestContext(request))
@ -277,7 +262,7 @@ def change_stream(request, name):
stream = doc.stream
form = ChangeStreamForm(initial=dict(stream=stream))
return render_to_response('idrfc/change_stream.html',
return render_to_response('doc/draft/change_stream.html',
dict(form=form,
doc=doc,
),
@ -327,7 +312,7 @@ def change_intention(request, name):
doc.time = e.time
doc.save()
email_owner(request, doc, doc.ad, login, email_desc)
email_ad(request, doc, doc.ad, login, email_desc)
return HttpResponseRedirect(doc.get_absolute_url())
@ -335,45 +320,13 @@ def change_intention(request, name):
intended_std_level = doc.intended_std_level
form = ChangeIntentionForm(initial=dict(intended_std_level=intended_std_level))
return render_to_response('idrfc/change_intended_status.html',
return render_to_response('doc/draft/change_intended_status.html',
dict(form=form,
doc=doc,
),
context_instance=RequestContext(request))
def dehtmlify_textarea_text(s):
return s.replace("<br>", "\n").replace("<b>", "").replace("</b>", "").replace(" ", " ")
class EditInfoForm(forms.Form):
pass
def get_initial_state_change_notice(doc):
# set change state notice to something sensible
receivers = []
if doc.group_id == Acronym.INDIVIDUAL_SUBMITTER:
for a in doc.authors.all():
# maybe it would be more appropriate to use a.email() ?
e = a.person.email()[1]
if e:
receivers.append(e)
else:
receivers.append("%s-chairs@%s" % (doc.group.acronym, settings.TOOLS_SERVER))
for editor in doc.group.ietfwg.wgeditor_set.all():
e = editor.person.email()[1]
if e:
receivers.append(e)
receivers.append("%s@%s" % (doc.filename, settings.TOOLS_SERVER))
return ", ".join(receivers)
def get_new_ballot_id():
return IDInternal.objects.aggregate(Max('ballot'))['ballot__max'] + 1
@group_required('Area_Director','Secretariat')
def edit_info(request, name):
pass
class EditInfoFormREDESIGN(forms.Form):
intended_std_level = forms.ModelChoiceField(IntendedStdLevelName.objects.filter(used=True), empty_label="(None)", required=True, label="Intended RFC status")
area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active"), empty_label="(None - individual submission)", required=False, label="Assigned to area")
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'), label="Responsible AD", empty_label="(None)", required=True)
@ -421,8 +374,8 @@ def get_initial_notify(doc):
receivers.append("%s@%s" % (doc.name, settings.TOOLS_SERVER))
return ", ".join(receivers)
@group_required('Area_Director','Secretariat')
def edit_infoREDESIGN(request, name):
@role_required('Area Director','Secretariat')
def edit_info(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)
@ -530,7 +483,7 @@ def edit_infoREDESIGN(request, name):
doc.time = datetime.datetime.now()
if changes and not new_document:
email_owner(request, doc, orig_ad, login, "\n".join(changes))
email_ad(request, doc, orig_ad, login, "\n".join(changes))
doc.save()
return HttpResponseRedirect(doc.get_absolute_url())
@ -552,7 +505,7 @@ def edit_infoREDESIGN(request, name):
if doc.group.type_id not in ("individ", "area"):
form.standard_fields = [x for x in form.standard_fields if x.name != "area"]
return render_to_response('idrfc/edit_infoREDESIGN.html',
return render_to_response('doc/draft/edit_info.html',
dict(doc=doc,
form=form,
user=request.user,
@ -560,37 +513,8 @@ def edit_infoREDESIGN(request, name):
ballot_issued=doc.latest_event(type="sent_ballot_announcement")),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
EditInfoForm = EditInfoFormREDESIGN
edit_info = edit_infoREDESIGN
@group_required('Area_Director','Secretariat')
@role_required('Area Director','Secretariat')
def request_resurrect(request, name):
"""Request resurrect of expired Internet Draft."""
doc = get_object_or_404(InternetDraft, filename=name)
if doc.status.status != "Expired":
raise Http404()
if not doc.idinternal:
doc.idinternal = IDInternal(draft=doc, rfc_flag=type(doc) == Rfc)
login = IESGLogin.objects.get(login_name=request.user.username)
if request.method == 'POST':
email_resurrect_requested(request, doc, login)
add_document_comment(request, doc, "Resurrection was requested")
doc.idinternal.resurrect_requested_by = login
doc.idinternal.save()
return HttpResponseRedirect(doc.idinternal.get_absolute_url())
return render_to_response('idrfc/request_resurrect.html',
dict(doc=doc,
back_url=doc.idinternal.get_absolute_url()),
context_instance=RequestContext(request))
@group_required('Area_Director','Secretariat')
def request_resurrectREDESIGN(request, name):
"""Request resurrect of expired Internet Draft."""
doc = get_object_or_404(Document, docalias__name=name)
if doc.get_state_slug() != "expired":
@ -608,44 +532,13 @@ def request_resurrectREDESIGN(request, name):
return HttpResponseRedirect(doc.get_absolute_url())
return render_to_response('idrfc/request_resurrect.html',
return render_to_response('doc/draft/request_resurrect.html',
dict(doc=doc,
back_url=doc.get_absolute_url()),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
request_resurrect = request_resurrectREDESIGN
@group_required('Secretariat')
@role_required('Secretariat')
def resurrect(request, name):
"""Resurrect expired Internet Draft."""
doc = get_object_or_404(InternetDraft, filename=name)
if doc.status.status != "Expired":
raise Http404()
if not doc.idinternal:
doc.idinternal = IDInternal(draft=doc, rfc_flag=type(doc) == Rfc)
login = IESGLogin.objects.get(login_name=request.user.username)
if request.method == 'POST':
if doc.idinternal.resurrect_requested_by:
email_resurrection_completed(request, doc)
add_document_comment(request, doc, "Resurrection was completed")
doc.idinternal.resurrect_requested_by = None
doc.idinternal.event_date = date.today()
doc.idinternal.save()
doc.status = IDStatus.objects.get(status="Active")
doc.save()
return HttpResponseRedirect(doc.idinternal.get_absolute_url())
return render_to_response('idrfc/resurrect.html',
dict(doc=doc,
back_url=doc.idinternal.get_absolute_url()),
context_instance=RequestContext(request))
@group_required('Secretariat')
def resurrectREDESIGN(request, name):
"""Resurrect expired Internet Draft."""
doc = get_object_or_404(Document, docalias__name=name)
if doc.get_state_slug() != "expired":
@ -671,81 +564,16 @@ def resurrectREDESIGN(request, name):
doc.save()
return HttpResponseRedirect(doc.get_absolute_url())
return render_to_response('idrfc/resurrect.html',
return render_to_response('doc/draft/resurrect.html',
dict(doc=doc,
back_url=doc.get_absolute_url()),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
resurrect = resurrectREDESIGN
class AddCommentForm(forms.Form):
comment = forms.CharField(required=True, widget=forms.Textarea)
@group_required('Area_Director','Secretariat', 'IANA')
def add_comment(request, name):
"""Add comment to Internet Draft."""
doc = get_object_or_404(InternetDraft, filename=name)
if not doc.idinternal:
raise Http404()
login = IESGLogin.objects.get(login_name=request.user.username)
if request.method == 'POST':
form = AddCommentForm(request.POST)
if form.is_valid():
c = form.cleaned_data['comment']
add_document_comment(request, doc, c)
email_owner(request, doc, doc.idinternal.job_owner, login,
"A new comment added by %s" % login)
return HttpResponseRedirect(doc.idinternal.get_absolute_url())
else:
form = AddCommentForm()
return render_to_response('idrfc/add_comment.html',
dict(doc=doc,
form=form,
back_url=doc.idinternal.get_absolute_url()),
context_instance=RequestContext(request))
@group_required('Area_Director', 'Secretariat', 'IANA', 'RFC Editor')
def add_commentREDESIGN(request, name):
"""Add comment to history of document."""
doc = get_object_or_404(Document, docalias__name=name)
login = request.user.get_profile()
if request.method == 'POST':
form = AddCommentForm(request.POST)
if form.is_valid():
c = form.cleaned_data['comment']
e = DocEvent(doc=doc, by=login)
e.type = "added_comment"
e.desc = c
e.save()
if doc.type_id == "draft":
email_owner(request, doc, doc.ad, login,
"A new comment added by %s" % login.name)
return HttpResponseRedirect(urlreverse("doc_history", kwargs=dict(name=doc.name)))
else:
form = AddCommentForm()
return render_to_response('idrfc/add_comment.html',
dict(doc=doc,
form=form),
context_instance=RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
add_comment = add_commentREDESIGN
class NotifyForm(forms.Form):
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False)
@group_required('Area_Director','Secretariat')
@role_required('Area Director', 'Secretariat')
def edit_notices(request, name):
"""Change the set of email addresses document change notificaitions go to."""
@ -781,7 +609,7 @@ def edit_notices(request, name):
init = { "notify" : doc.notify }
form = NotifyForm(initial=init)
return render_to_response('idrfc/change_notify.html',
return render_to_response('doc/draft/change_notify.html',
{'form': form,
'doc': doc,
},
@ -802,7 +630,7 @@ class TelechatForm(forms.Form):
self.fields['telechat_date'].choices = [("", "(not on agenda)")] + [(d, d.strftime("%Y-%m-%d")) for d in dates]
@group_required("Area Director", "Secretariat")
@role_required("Area Director", "Secretariat")
def telechat_date(request, name):
doc = get_object_or_404(Document, type="draft", name=name)
login = request.user.get_profile()
@ -822,7 +650,7 @@ def telechat_date(request, name):
else:
form = TelechatForm(initial=initial)
return render_to_response('idrfc/edit_telechat_date.html',
return render_to_response('doc/edit_telechat_date.html',
dict(doc=doc,
form=form,
user=request.user,
@ -838,7 +666,7 @@ class IESGNoteForm(forms.Form):
# that has caused a lot of pain in the past.
return self.cleaned_data['note'].replace('\r', '').strip()
@group_required("Area Director", "Secretariat")
@role_required("Area Director", "Secretariat")
def edit_iesg_note(request, name):
doc = get_object_or_404(Document, type="draft", name=name)
login = request.user.get_profile()
@ -871,7 +699,7 @@ def edit_iesg_note(request, name):
else:
form = IESGNoteForm(initial=initial)
return render_to_response('idrfc/edit_iesg_note.html',
return render_to_response('doc/draft/edit_iesg_note.html',
dict(doc=doc,
form=form,
),
@ -941,7 +769,7 @@ def edit_shepherd_writeup(request, name):
)
form = ShepherdWriteupUploadForm(initial=init)
return render_to_response('idrfc/change_shepherd_writeup.html',
return render_to_response('doc/draft/change_shepherd_writeup.html',
{'form': form,
'doc' : doc,
},
@ -992,7 +820,7 @@ def edit_shepherd(request, name):
init = { "shepherd": current_shepherd}
form = ShepherdForm(initial=init)
return render_to_response('idrfc/change_shepherd.html',
return render_to_response('doc/change_shepherd.html',
{'form': form,
'doc': doc,
},
@ -1011,7 +839,7 @@ class AdForm(forms.Form):
if ad_pk and ad_pk not in [pk for pk, name in choices]:
self.fields['ad'].choices = list(choices) + [("", "-------"), (ad_pk, Person.objects.get(pk=ad_pk).plain_name())]
@group_required("Area Director", "Secretariat")
@role_required("Area Director", "Secretariat")
def edit_ad(request, name):
"""Change the shepherding Area Director for this draft."""
@ -1035,7 +863,7 @@ def edit_ad(request, name):
init = { "ad" : doc.ad_id }
form = AdForm(initial=init)
return render_to_response('idrfc/change_ad.html',
return render_to_response('doc/draft/change_ad.html',
{'form': form,
'doc': doc,
},
@ -1073,7 +901,7 @@ def edit_consensus(request, name):
else:
form = ConsensusForm(initial=dict(consensus=nice_consensus(prev_consensus).replace("Unknown", "")))
return render_to_response('idrfc/change_consensus.html',
return render_to_response('doc/draft/change_consensus.html',
{'form': form,
'doc': doc,
},
@ -1107,7 +935,7 @@ def request_publication(request, name):
import ietf.sync.rfceditor
response, error = ietf.sync.rfceditor.post_approved_draft(settings.RFC_EDITOR_SYNC_NOTIFICATION_URL, doc.name)
if error:
return render_to_response('doc/rfceditor_post_approved_draft_failed.html',
return render_to_response('doc/draft/rfceditor_post_approved_draft_failed.html',
dict(name=doc.name,
response=response,
error=error),
@ -1147,7 +975,7 @@ def request_publication(request, name):
else:
action = "Document Action"
from ietf.idrfc.templatetags.mail_filters import std_level_prompt
from ietf.doc.templatetags.mail_filters import std_level_prompt
subject = "%s: '%s' to %s (%s-%s.txt)" % (action, doc.title, std_level_prompt(doc), doc.name, doc.rev)
@ -1156,7 +984,7 @@ def request_publication(request, name):
form = PublicationForm(initial=dict(subject=subject,
body=body))
return render_to_response('idrfc/request_publication.html',
return render_to_response('doc/draft/request_publication.html',
dict(form=form,
doc=doc,
message=m,

View file

@ -10,7 +10,8 @@ def state_help(request, type):
"draft-rfceditor": ("draft-rfceditor", "RFC Editor States For Internet-Drafts"),
"draft-iana-action": ("draft-iana-action", "IANA Action States For Internet-Drafts"),
"charter": ("charter", "Charter States"),
"conflict-review": ("conflrev", "Conflict Review States")
"conflict-review": ("conflrev", "Conflict Review States"),
"status-change": ("statchg", "RFC Status Change States"),
}.get(type, (None, None))
state_type = get_object_or_404(StateType, slug=slug)

View file

@ -38,13 +38,12 @@ from django.db.models import Q
from django.template import RequestContext
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
from ietf.idrfc.expire import expirable_draft
from ietf.doc.expire import expirable_draft
from ietf.utils import normalize_draftname
from ietf.doc.models import *
from ietf.person.models import *
from ietf.group.models import *
from ietf.ipr.models import IprDocAlias
from ietf.ipr.search import related_docs
from ietf.idindex.index import active_drafts_index_by_group
class SearchForm(forms.Form):
@ -152,7 +151,7 @@ def fill_in_search_attributes(docs):
ipr_docaliases = IprDocAlias.objects.filter(doc_alias__document__in=doc_ids).select_related('doc_alias')
for a in ipr_docaliases:
docs_dict[a.doc_alias.document_id].iprs.append(a)
rel_docs_dict = dict((d.pk, d) for d in rel_docs)
rel_doc_ids = rel_docs_dict.keys()
@ -389,10 +388,14 @@ def search(request):
results = []
meta = { 'by': None, 'advanced': False, 'searching': False }
return render_to_response('doc/search.html',
return render_to_response('doc/search/search.html',
{'form':form, 'docs':results, 'meta':meta, 'show_add_to_list': True },
context_instance=RequestContext(request))
def frontpage(request):
form = SearchForm()
return render_to_response('doc/frontpage.html', {'form':form}, context_instance=RequestContext(request))
def ad_dashboard_group(doc):
if doc.type.slug=='draft':

View file

@ -8,8 +8,7 @@ from django.template import RequestContext
from django.template.loader import render_to_string
from django.conf import settings
from ietf.idrfc.utils import update_telechat
from ietf.doc.utils import log_state_changed
from ietf.doc.utils import log_state_changed, update_telechat
from ietf.doc.models import save_document_in_history
from ietf.doc.utils import create_ballot_if_not_open, close_open_ballots, get_document_content
@ -24,9 +23,8 @@ from ietf.group.models import Group
from ietf.name.models import DocRelationshipName, StdLevelName
from ietf.doc.forms import TelechatForm, AdForm, NotifyForm
from ietf.idrfc.views_ballot import LastCallTextForm
from ietf.idrfc.lastcall import request_last_call
from ietf.doc.views_ballot import LastCallTextForm
from ietf.doc.lastcall import request_last_call
class ChangeStateForm(forms.Form):
new_state = forms.ModelChoiceField(State.objects.filter(type="statchg", used=True), label="Status Change Evaluation State", empty_label=None, required=True)
@ -95,7 +93,7 @@ def change_state(request, name, option=None):
dict(form=form,
doc=status_change,
login=login,
help_url=reverse('help_status_change_states')
help_url=reverse('state_help', kwargs=dict(type="status-change")),
),
context_instance=RequestContext(request))
@ -702,7 +700,7 @@ def last_call(request, name):
request_last_call(request, status_change)
return render_to_response('idrfc/last_call_requested.html',
return render_to_response('doc/draft/last_call_requested.html',
dict(doc=status_change,
url = status_change.get_absolute_url(),
),

View file

@ -8,7 +8,7 @@ import pytz
from django.conf import settings
from django.template.loader import render_to_string
from ietf.idtracker.templatetags.ietf_filters import clean_whitespace
from ietf.doc.templatetags.ietf_filters import clean_whitespace
from ietf.doc.models import *
def all_id_txt():

View file

@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="3175" model="idtracker.ballotinfo">
<field type="BooleanField" name="active">1</field>
<field type="BooleanField" name="an_sent">0</field>
<field type="DateField" name="an_sent_date"><None></None></field>
<field to="idtracker.iesglogin" name="an_sent_by" rel="ManyToOneRel"><None></None></field>
<field type="BooleanField" name="defer">0</field>
<field to="idtracker.iesglogin" name="defer_by" rel="ManyToOneRel">111</field>
<field type="DateField" name="defer_date">2009-10-06</field>
<field type="TextField" name="approval_text">From: The IESG &lt;iesg-secretary@ietf.org&gt;
To: IETF-Announce &lt;ietf-announce@ietf.org&gt;
Cc: Internet Architecture Board &lt;iab@iab.org&gt;,
RFC Editor &lt;rfc-editor@rfc-editor.org&gt;,
mipshop mailing list &lt;mipshop@ietf.org&gt;,
mipshop chair &lt;mipshop-chairs@tools.ietf.org&gt;
Subject: Protocol Action: 'Fast Handovers for Proxy Mobile IPv6' to
Proposed Standard
The IESG has approved the following document:
- 'Fast Handovers for Proxy Mobile IPv6 '
&lt;draft-ietf-mipshop-pfmipv6-09.txt&gt; as a Proposed Standard
This document is the product of the Mobility for IP: Performance,
Signaling and Handoff Optimization Working Group.
The IESG contact persons are Jari Arkko and Ralph Droms.
A URL of this Internet-Draft is:
http://www.ietf.org/internet-drafts/draft-ietf-mipshop-pfmipv6-09.txt</field>
<field type="TextField" name="last_call_text">To: IETF-Announce &lt;ietf-announce@ietf.org&gt;
From: The IESG &lt;iesg-secretary@ietf.org&gt;
Reply-to: ietf@ietf.org
CC: &lt;mipshop@ietf.org&gt;
Subject: Last Call: draft-ietf-mipshop-pfmipv6 (Fast Handovers for Proxy Mobile IPv6) to Proposed Standard
The IESG has received a request from the Mobility for IP: Performance,
Signaling and Handoff Optimization WG (mipshop) to consider the following document:
- 'Fast Handovers for Proxy Mobile IPv6 '
&lt;draft-ietf-mipshop-pfmipv6-09.txt&gt; as a Proposed Standard
The IESG plans to make a decision in the next few weeks, and solicits
final comments on this action. Please send substantive comments to the
ietf@ietf.org mailing lists by 2009-09-22. Exceptionally,
comments may be sent to iesg@ietf.org instead. In either case, please
retain the beginning of the Subject line to allow automated sorting.
The file can be obtained via
http://www.ietf.org/internet-drafts/draft-ietf-mipshop-pfmipv6-09.txt
IESG discussion can be tracked via
https://datatracker.ietf.org/public/pidtracker.cgi?command=view_id&amp;dTag=17914&amp;rfc_flag=0</field>
<field type="TextField" name="ballot_writeup">Technical Summary
The document describes a mechanism to provide fast handovers when
Proxy Mobile IPv6 is used as the mobility management protocol. It
also describes a mechanism to transfer context between two MAGs
to assist in the handover. The mobile node is not involved in any
Signaling for the fast handovers to work.
Working Group Summary
This is a product of the MIPSHOP WG.
Document Quality
There are no known implementations of the specification. It is likely
to be implemented by some vendors, since this document is required
for fast handovers in 3GPP2 eHPRD network.
Personnel
Document shepherd: Vijay Devarapalli
Responsible AD: Jari Arkko
RFC Editor Note
(Insert RFC Editor Note here or remove section)
IRTF Note
(Insert IRTF Note here or remove section)
IESG Note
(Insert IESG Note here or remove section)
IANA Note
(Insert IANA Note here or remove section)</field>
<field type="IntegerField" name="ballot_issued">1</field>
</object>
</django-objects>

File diff suppressed because it is too large Load diff

View file

@ -1,264 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="17914" model="idtracker.internetdraft">
<field type="CharField" name="title">Fast Handovers for Proxy Mobile IPv6</field>
<field type="CharField" name="id_document_key">FAST HANDOVERS FOR PROXY MOBILE IPV6</field>
<field to="idtracker.acronym" name="group" rel="ManyToOneRel">1598</field>
<field type="CharField" name="filename">draft-ietf-mipshop-pfmipv6</field>
<field type="CharField" name="revision">13</field>
<field type="DateField" name="revision_date">2010-04-11</field>
<field type="CharField" name="file_type">.txt</field>
<field type="IntegerField" name="txt_page_count">41</field>
<field type="CharField" name="local_path"><None></None></field>
<field type="DateField" name="start_date">2008-10-27</field>
<field type="DateField" name="expiration_date"><None></None></field>
<field type="TextField" name="abstract">Mobile IPv6 (MIPv6) [RFC3775] provides a mobile node with IP mobility
when it performs a handover from one MAG to another and fast
handovers for Mobile IPv6 (FMIPv6) [RFC5568] are specified to enhance
the handover performance in terms of latency and packet loss. While
MIPv6 (and FMIPv6 as well) requires the participation of the mobile
node in the mobility-related signaling, Proxy Mobile IPv6 (PMIPv6)
[RFC5213] provides IP mobility to mobile nodes that either have or do
not have MIPv6 functionality without such involvement. Nevertheless,
the basic performance of PMIPv6 in terms of handover latency and
packet loss is considered not any different from that of MIPv6.
When the fast handover is considered in such an environment, several
modifications are needed to FMIPv6 to adapt to the network-based
mobility management. This document specifies the usage of Fast
Mobile IPv6 (FMIPv6) when Proxy Mobile IPv6 is used as the mobility
management protocol. Necessary extensions are specified for FMIPv6
to support the scenario when the mobile node does not have IP
mobility functionality and hence is not involved with either MIPv6 or
FMIPv6 operations.</field>
<field type="DateField" name="dunn_sent_date"><None></None></field>
<field type="DateField" name="extension_date"><None></None></field>
<field to="idtracker.idstatus" name="status" rel="ManyToOneRel">1</field>
<field to="idtracker.idintendedstatus" name="intended_status" rel="ManyToOneRel">6</field>
<field type="DateField" name="lc_sent_date">2009-09-08</field>
<field type="CharField" name="lc_changes"><None></None></field>
<field type="DateField" name="lc_expiration_date">2009-09-22</field>
<field type="DateField" name="b_sent_date"><None></None></field>
<field type="DateField" name="b_discussion_date"><None></None></field>
<field type="DateField" name="b_approve_date"><None></None></field>
<field type="DateField" name="wgreturn_date"><None></None></field>
<field type="IntegerField" name="rfc_number"><None></None></field>
<field type="TextField" name="comments"><None></None></field>
<field type="DateField" name="last_modified_date">2010-04-11</field>
<field to="idtracker.internetdraft" name="replaced_by" rel="ManyToOneRel"><None></None></field>
<field type="BooleanField" name="review_by_rfc_editor">0</field>
<field type="BooleanField" name="expired_tombstone">0</field>
</object>
<object pk="17914" model="idtracker.idinternal">
<field type="IntegerField" name="rfc_flag">0</field>
<field to="idtracker.ballotinfo" name="ballot" rel="ManyToOneRel">3175</field>
<field type="IntegerField" name="primary_flag">1</field>
<field type="IntegerField" name="group_flag">0</field>
<field type="CharField" name="token_name">Jari Arkko</field>
<field type="CharField" name="token_email">jari.arkko@piuha.net</field>
<field type="TextField" name="note">On the May 6th agenda to solicit one additional vote (Discusses cleared)&lt;br&gt;Vijay Devarapalli (vijay@wichorus.com) is the document shepherd.</field>
<field type="DateField" name="status_date"><None></None></field>
<field type="CharField" name="email_display">Jari Arkko</field>
<field type="IntegerField" name="agenda">1</field>
<field to="idtracker.idstate" name="cur_state" rel="ManyToOneRel">11</field>
<field to="idtracker.idstate" name="prev_state" rel="ManyToOneRel">10</field>
<field type="CharField" name="assigned_to"></field>
<field to="idtracker.iesglogin" name="mark_by" rel="ManyToOneRel">100</field>
<field to="idtracker.iesglogin" name="job_owner" rel="ManyToOneRel">49</field>
<field type="DateField" name="event_date">2010-05-17</field>
<field to="idtracker.area" name="area_acronym" rel="ManyToOneRel">1052</field>
<field to="idtracker.idsubstate" name="cur_sub_state" rel="ManyToOneRel"><None></None></field>
<field to="idtracker.idsubstate" name="prev_sub_state" rel="ManyToOneRel"><None></None></field>
<field type="IntegerField" name="returning_item">0</field>
<field type="DateField" name="telechat_date">2010-05-20</field>
<field type="IntegerField" name="via_rfc_editor">0</field>
<field type="CharField" name="state_change_notice_to">mipshop-chairs@tools.ietf.org, draft-ietf-mipshop-pfmipv6@tools.ietf.org</field>
<field type="IntegerField" name="dnp">0</field>
<field type="DateField" name="dnp_date"><None></None></field>
<field type="IntegerField" name="noproblem">0</field>
<field to="idtracker.iesglogin" name="resurrect_requested_by" rel="ManyToOneRel"><None></None></field>
<field type="IntegerField" name="approved_in_minute">1</field>
</object>
<object pk="1598" model="idtracker.acronym">
<field type="CharField" name="acronym">mipshop</field>
<field type="CharField" name="name">Mobility for IP: Performance, Signaling and Handoff Optimization</field>
<field type="CharField" name="name_key">MOBILITY FOR</field>
</object>
<object pk="1598" model="idtracker.ietfwg">
<field to="idtracker.wgtype" name="group_type" rel="ManyToOneRel">1</field>
<field type="DateField" name="proposed_date">2003-06-10</field>
<field type="DateField" name="start_date">2003-10-20</field>
<field type="DateField" name="dormant_date"><None></None></field>
<field type="DateField" name="concluded_date"><None></None></field>
<field to="idtracker.wgstatus" name="status" rel="ManyToOneRel">1</field>
<field to="idtracker.areadirector" name="area_director" rel="ManyToOneRel">126</field>
<field type="CharField" name="meeting_scheduled">NO</field>
<field type="CharField" name="email_address">mipshop@ietf.org</field>
<field type="CharField" name="email_subscribe">mipshop-request@ietf.org</field>
<field type="CharField" name="email_keyword">subscribe</field>
<field type="CharField" name="email_archive">http://www.ietf.org/mail-archive/web/mipshop/index.html</field>
<field type="TextField" name="comments">1st meeting at the 57th IETF in Vienna, Austria</field>
<field type="DateField" name="last_modified_date">2009-05-22</field>
<field type="CharField" name="meeting_scheduled_old">NO</field>
</object>
<object pk="10910" model="idtracker.areagroup">
<field to="idtracker.area" name="area" rel="ManyToOneRel">1052</field>
<field to="idtracker.ietfwg" name="group" rel="ManyToOneRel">1598</field>
</object>
<object pk="1052" model="idtracker.area">
<field type="DateField" name="start_date">1983-09-06</field>
<field type="DateField" name="concluded_date"><None></None></field>
<field to="idtracker.areastatus" name="status" rel="ManyToOneRel">1</field>
<field type="TextField" name="comments"></field>
<field type="DateField" name="last_modified_date">2003-09-26</field>
<field type="TextField" name="extra_email_addresses"><None></None></field>
</object>
<object pk="1052" model="idtracker.acronym">
<field type="CharField" name="acronym">int</field>
<field type="CharField" name="name">Internet Area</field>
<field type="CharField" name="name_key">INTERNET AREA</field>
</object>
<object pk="12676" model="idtracker.internetdraft">
<field type="CharField" name="title">Using IPsec between Mobile and Correspondent IPv6 Nodes</field>
<field type="CharField" name="id_document_key">USING IPSEC BETWEEN MOBILE AND CORRESPONDENT IPV6 NODES</field>
<field to="idtracker.acronym" name="group" rel="ManyToOneRel">1597</field>
<field type="CharField" name="filename">draft-ietf-mip6-cn-ipsec</field>
<field type="CharField" name="revision">09</field>
<field type="DateField" name="revision_date">2008-08-25</field>
<field type="CharField" name="file_type">.txt</field>
<field type="IntegerField" name="txt_page_count">11</field>
<field type="CharField" name="local_path"></field>
<field type="DateField" name="start_date">2005-01-11</field>
<field type="DateField" name="expiration_date">2010-04-27</field>
<field type="TextField" name="abstract">Mobile IPv6 uses IPsec to protect signaling between the Mobile Node
and the Home Agent. This document defines how IPsec can be used
between the Mobile Node and Correspondent Nodes for Home Address
Option validation and protection of mobility signaling for Route
Optimization. The configuration details for IPsec and IKE are also
provided.</field>
<field type="DateField" name="dunn_sent_date">2010-04-26</field>
<field type="DateField" name="extension_date"><None></None></field>
<field to="idtracker.idstatus" name="status" rel="ManyToOneRel">2</field>
<field to="idtracker.idintendedstatus" name="intended_status" rel="ManyToOneRel">6</field>
<field type="DateField" name="lc_sent_date">2007-08-17</field>
<field type="CharField" name="lc_changes">NO</field>
<field type="DateField" name="lc_expiration_date">2007-08-31</field>
<field type="DateField" name="b_sent_date"><None></None></field>
<field type="DateField" name="b_discussion_date"><None></None></field>
<field type="DateField" name="b_approve_date"><None></None></field>
<field type="DateField" name="wgreturn_date"><None></None></field>
<field type="IntegerField" name="rfc_number">0</field>
<field type="TextField" name="comments"></field>
<field type="DateField" name="last_modified_date">2010-04-27</field>
<field to="idtracker.internetdraft" name="replaced_by" rel="ManyToOneRel"><None></None></field>
<field type="BooleanField" name="review_by_rfc_editor">0</field>
<field type="BooleanField" name="expired_tombstone">0</field>
</object>
<object pk="12676" model="idtracker.idinternal">
<field type="IntegerField" name="rfc_flag">0</field>
<field to="idtracker.ballotinfo" name="ballot" rel="ManyToOneRel">2157</field>
<field type="IntegerField" name="primary_flag">1</field>
<field type="IntegerField" name="group_flag">0</field>
<field type="CharField" name="token_name">Jari Arkko</field>
<field type="CharField" name="token_email">jari.arkko@piuha.net</field>
<field type="TextField" name="note">AD Sponsored submission. There is no Document Shepherd.</field>
<field type="DateField" name="status_date"><None></None></field>
<field type="CharField" name="email_display">Jari Arkko</field>
<field type="IntegerField" name="agenda">0</field>
<field to="idtracker.idstate" name="cur_state" rel="ManyToOneRel">99</field>
<field to="idtracker.idstate" name="prev_state" rel="ManyToOneRel">20</field>
<field type="CharField" name="assigned_to"></field>
<field to="idtracker.iesglogin" name="mark_by" rel="ManyToOneRel">49</field>
<field to="idtracker.iesglogin" name="job_owner" rel="ManyToOneRel">49</field>
<field type="DateField" name="event_date">2010-04-26</field>
<field to="idtracker.area" name="area_acronym" rel="ManyToOneRel">1052</field>
<field to="idtracker.idsubstate" name="cur_sub_state" rel="ManyToOneRel"><None></None></field>
<field to="idtracker.idsubstate" name="prev_sub_state" rel="ManyToOneRel">5</field>
<field type="IntegerField" name="returning_item">0</field>
<field type="DateField" name="telechat_date">2007-09-06</field>
<field type="IntegerField" name="via_rfc_editor">0</field>
<field type="CharField" name="state_change_notice_to">mext-chairs@tools.ietf.org,Francis.Dupont@fdupont.fr,jeanmichel.combes@orange-ftgroup.com</field>
<field type="IntegerField" name="dnp">0</field>
<field type="DateField" name="dnp_date"><None></None></field>
<field type="IntegerField" name="noproblem">0</field>
<field to="idtracker.iesglogin" name="resurrect_requested_by" rel="ManyToOneRel"><None></None></field>
<field type="IntegerField" name="approved_in_minute">1</field>
</object>
<object pk="19892" model="idtracker.internetdraft">
<field type="CharField" name="title">Uniform Resource Name (URN) Syntax</field>
<field type="CharField" name="id_document_key">UNIFORM RESOURCE NAME (URN) SYNTAX</field>
<field to="idtracker.acronym" name="group" rel="ManyToOneRel">1027</field>
<field type="CharField" name="filename">draft-ah-rfc2141bis-urn</field>
<field type="CharField" name="revision">00</field>
<field type="DateField" name="revision_date">2010-03-25</field>
<field type="CharField" name="file_type">.txt</field>
<field type="IntegerField" name="txt_page_count">18</field>
<field type="CharField" name="local_path"><None></None></field>
<field type="DateField" name="start_date">2010-03-25</field>
<field type="DateField" name="expiration_date"><None></None></field>
<field type="TextField" name="abstract">Uniform Resource Names (URNs) are intended to serve as persistent,
location-independent, resource identifiers. This document serves as
the foundation of the 'urn' URI Scheme according to RFC 3986 and sets
forward the canonical syntax for URNs, which subdivides URNs into
"namespaces". A discussion of both existing legacy and new
namespaces and requirements for URN presentation and transmission are
presented. Finally, there is a discussion of URN equivalence and how
to determine it. This document supersedes RFC 2141.
The requirements and procedures for URN Namespace registration
documents are currently set forth in RFC 3406, which is also expected
to be updated by an independent, revised specification soon.
Discussion
This draft version has been obtained by importing the text from RFC
2141 into modern tools and making a first round of updating steps.
It is intended to serve as one of the starting points for an effort
to bring URN RFCs in alignment with STD 63, STD 68, BCP 26, and the
requirements from emerging distributed national and international URN
resolution systems, and advance them on the IETF Standards Track.
Until a more specific mailing list is established, comments are
welcome on the uri-review@ietf.org mailing list (or sent to the
document editor).</field>
<field type="DateField" name="dunn_sent_date"><None></None></field>
<field type="DateField" name="extension_date"><None></None></field>
<field to="idtracker.idstatus" name="status" rel="ManyToOneRel">1</field>
<field to="idtracker.idintendedstatus" name="intended_status" rel="ManyToOneRel">8</field>
<field type="DateField" name="lc_sent_date"><None></None></field>
<field type="CharField" name="lc_changes"><None></None></field>
<field type="DateField" name="lc_expiration_date"><None></None></field>
<field type="DateField" name="b_sent_date"><None></None></field>
<field type="DateField" name="b_discussion_date"><None></None></field>
<field type="DateField" name="b_approve_date"><None></None></field>
<field type="DateField" name="wgreturn_date"><None></None></field>
<field type="IntegerField" name="rfc_number"><None></None></field>
<field type="TextField" name="comments"><None></None></field>
<field type="DateField" name="last_modified_date">2010-03-25</field>
<field to="idtracker.internetdraft" name="replaced_by" rel="ManyToOneRel"><None></None></field>
<field type="BooleanField" name="review_by_rfc_editor">0</field>
<field type="BooleanField" name="expired_tombstone">0</field>
</object>
<object pk="1027" model="idtracker.acronym">
<field type="CharField" name="acronym">none</field>
<field type="CharField" name="name">Individual Submissions</field>
<field type="CharField" name="name_key">INDIVIDUAL SUBMISSIONS</field>
</object>
<object pk="1027" model="idtracker.ietfwg">
<field to="idtracker.wgtype" name="group_type" rel="ManyToOneRel">4</field>
<field type="DateField" name="proposed_date"><None></None></field>
<field type="DateField" name="start_date"><None></None></field>
<field type="DateField" name="dormant_date"><None></None></field>
<field type="DateField" name="concluded_date"><None></None></field>
<field to="idtracker.wgstatus" name="status" rel="ManyToOneRel">1</field>
<field to="idtracker.areadirector" name="area_director" rel="ManyToOneRel">112</field>
<field type="CharField" name="meeting_scheduled">NO</field>
<field type="CharField" name="email_address"></field>
<field type="CharField" name="email_subscribe"></field>
<field type="CharField" name="email_keyword"></field>
<field type="CharField" name="email_archive"></field>
<field type="TextField" name="comments">This is here so that 'none' can be entered in, for example, idform.</field>
<field type="DateField" name="last_modified_date">2002-06-24</field>
<field type="CharField" name="meeting_scheduled_old">NO</field>
</object>
</django-objects>

View file

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="1791" model="iesg.wgaction">
<field type="TextField" name="note"></field>
<field type="DateField" name="status_date">2010-04-22</field>
<field type="BooleanField" name="agenda">1</field>
<field type="CharField" name="token_name">Robert</field>
<field type="IntegerField" name="category">13</field>
<field type="DateField" name="telechat_date">2010-05-06</field>
</object>
<object pk="1784" model="iesg.wgaction">
<field type="TextField" name="note"></field>
<field type="DateField" name="status_date">2010-04-23</field>
<field type="BooleanField" name="agenda">1</field>
<field type="CharField" name="token_name">Peter</field>
<field type="IntegerField" name="category">12</field>
<field type="DateField" name="telechat_date">2010-05-06</field>
</object>
<object pk="1775" model="iesg.wgaction">
<field type="TextField" name="note"></field>
<field type="DateField" name="status_date">2010-01-19</field>
<field type="BooleanField" name="agenda">1</field>
<field type="CharField" name="token_name">Lars</field>
<field type="IntegerField" name="category">13</field>
<field type="DateField" name="telechat_date">2010-05-06</field>
</object>
<object pk="1775" model="idtracker.acronym">
<field type="CharField" name="acronym">conex</field>
<field type="CharField" name="name">Congestion Exposure</field>
<field type="CharField" name="name_key">CONGESTION E</field>
</object>
<object pk="1784" model="idtracker.acronym">
<field type="CharField" name="acronym">newprep</field>
<field type="CharField" name="name">Stringprep after IDNA2008</field>
<field type="CharField" name="name_key">STRINGPREP A</field>
</object>
<object pk="1791" model="idtracker.acronym">
<field type="CharField" name="acronym">soc</field>
<field type="CharField" name="name">SIP Overload Control</field>
<field type="CharField" name="name_key">SIP OVERLOAD CONTROL</field>
</object>
<object pk="1389" model="idtracker.acronym">
<field type="CharField" name="acronym">sieve</field>
<field type="CharField" name="name">Sieve Mail Filtering Language</field>
<field type="CharField" name="name_key">SIEVE MAIL F</field>
</object>
</django-objects>

View file

@ -1,74 +0,0 @@
#!/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
from ietf.idtracker.models import *
from ietf.iesg.models import *
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
# base data
base = []
area_directors = AreaDirector.objects.all()
broken_logins = ('bthorson', 'members', 'iab')
base.extend(area_directors)
base.extend(PersonOrOrgInfo.objects.filter(areadirector__in=area_directors))
base.extend(IESGLogin.objects.filter(Q(login_name="klm") | Q(person__in=[a.person for a in area_directors])).exclude(login_name__in=broken_logins))
base.extend(EmailAddress.objects.filter(person_or_org__areadirector__in=area_directors, priority=1))
base.extend(IDStatus.objects.all())
base.extend(IDIntendedStatus.objects.all())
base.extend(IDSubState.objects.all())
base.extend(IDState.objects.all())
base.extend(WGType.objects.all())
base.extend(TelechatDates.objects.all())
base.extend(Acronym.objects.filter(acronym_id=Acronym.INDIVIDUAL_SUBMITTER))
base.extend(IDDates.objects.all())
output("base", base)
# specific drafts
draftdata = []
d = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
draftdata.extend([d, d.idinternal, d.group, d.group.ietfwg])
ags = AreaGroup.objects.filter(group__exact=d.group.ietfwg.group_acronym)
draftdata.extend(ags)
draftdata.extend([a.area for a in ags])
draftdata.extend([a.area.area_acronym for a in ags])
d = InternetDraft.objects.get(filename="draft-ietf-mip6-cn-ipsec")
draftdata.extend([d, d.idinternal])
d = InternetDraft.objects.get(filename="draft-ah-rfc2141bis-urn")
draftdata.extend([d, d.group, d.group.ietfwg])
output("draft", draftdata)
# specific ballot info
d = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
output("ballot", [d.idinternal.ballot])
# specific WG actions
wgas = WGAction.objects.all()
output("wgactions", list(wgas) + list(Acronym.objects.filter(wgaction__in=wgas)) + [Acronym.objects.get(acronym="sieve")])

View file

@ -1 +0,0 @@
/*.pyc

View file

@ -1 +0,0 @@
#

View file

@ -1,191 +0,0 @@
# Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# * Neither the name of the Nokia Corporation and/or its
# subsidiary(-ies) nor the names of its contributors may be used
# to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from django import template
from django.core.urlresolvers import reverse as urlreverse
from django.conf import settings
from ietf.idtracker.models import IDInternal, BallotInfo
from ietf.idrfc.idrfc_wrapper import position_to_string, BALLOT_ACTIVE_STATES
from ietf.idtracker.templatetags.ietf_filters import in_group, timesince_days
from ietf.ietfauth.decorators import has_role
from ietf.doc.models import BallotDocEvent
register = template.Library()
def get_user_name(context):
if 'user' in context and context['user'].is_authenticated():
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.person.models import Person
try:
return context['user'].get_profile().plain_name()
except Person.DoesNotExist:
return None
person = context['user'].get_profile().person()
if person:
return str(person)
return None
def render_ballot_icon(user, doc):
if not doc:
return ""
if doc.type_id == "draft":
s = doc.get_state("draft-iesg")
if s and s.name not in BALLOT_ACTIVE_STATES:
return ""
elif doc.type_id == "charter":
if doc.get_state_slug() not in ("intrev", "iesgrev"):
return ""
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
if not ballot:
return ""
edit_position_url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
def sort_key(t):
_, pos = t
if not pos:
return (2, 0)
elif pos.pos.blocking:
return (0, pos.pos.order)
else:
return (1, pos.pos.order)
positions = list(doc.active_ballot().active_ad_positions().items())
positions.sort(key=sort_key)
cm = ""
if has_role(user, "Area Director"):
cm = ' oncontextmenu="editBallot(\''+str(edit_position_url)+'\');return false;"'
res = ['<table class="ballot_icon" title="IESG Evaluation Record (click to show more, right-click to edit position)" onclick="showBallot(\'' + doc.name + '\',\'' + str(edit_position_url) + '\')"' + cm + '>']
res.append("<tr>")
for i, (ad, pos) in enumerate(positions):
if i > 0 and i % 5 == 0:
res.append("</tr>")
res.append("<tr>")
c = "position-%s" % (pos.pos.slug if pos else "norecord")
if ad.user_id == user.id:
c += " my"
res.append('<td class="%s" />' % c)
res.append("</tr>")
res.append("</table>")
return "".join(res)
class BallotIconNode(template.Node):
def __init__(self, doc_var):
self.doc_var = doc_var
def render(self, context):
doc = template.resolve_variable(self.doc_var, context)
if hasattr(doc, "_idinternal"):
# hack for old schema
doc = doc._idinternal
return render_ballot_icon(context.get("user"), doc)
def do_ballot_icon(parser, token):
try:
tagName, docName = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
return BallotIconNode(docName)
register.tag('ballot_icon', do_ballot_icon)
@register.filter
def my_position(doc, user):
user_name = get_user_name({'user':user})
if not user_name:
return None
if not in_group(user, "Area_Director"):
return None
if not doc.in_ietf_process():
return None
if not doc.ietf_process.has_iesg_ballot():
return None
ballot = doc.ietf_process.iesg_ballot()
return ballot.position_for_ad(user_name)
@register.filter
def state_age_colored(doc):
if not doc.in_ietf_process():
return ""
if doc.is_id_wrapper and not doc.draft_status in ["Active", "RFC"]:
# Don't show anything for expired/withdrawn/replaced drafts
return ""
main_state = doc.ietf_process.main_state
sub_state = doc.ietf_process.sub_state
if main_state in ["Dead","AD is watching","RFC Published"]:
return ""
days = timesince_days(doc.ietf_process.state_date())
# loosely based on
# http://trac.tools.ietf.org/group/iesg/trac/wiki/PublishPath
if main_state == "In Last Call":
goal1 = 30
goal2 = 30
elif main_state == "RFC Ed Queue":
goal1 = 60
goal2 = 120
elif main_state in ["Last Call Requested", "Approved-announcement to be sent"]:
goal1 = 4
goal2 = 7
elif sub_state == "Revised ID Needed":
goal1 = 14
goal2 = 28
elif main_state == "Publication Requested":
goal1 = 7
goal2 = 14
elif main_state == "AD Evaluation":
goal1 = 14
goal2 = 28
else:
goal1 = 14
goal2 = 28
if days > goal2:
class_name = "ietf-small ietf-highlight-r"
elif days > goal1:
class_name = "ietf-small ietf-highlight-y"
else:
class_name = "ietf-small"
if days > goal1:
title = ' title="Goal is &lt;%d days"' % (goal1,)
else:
title = ''
return '<span class="%s"%s>(for&nbsp;%d&nbsp;day%s)</span>' % (class_name,title,days,('','s')[days != 1])

View file

@ -1,29 +0,0 @@
200 /
200 /doc/
200,heavy /doc/all/
200,heavy /doc/active/
# current AD -- needs to be updated at some point
200 /doc/ad/robert.sparks/
# former AD
200 /doc/ad/sam.hartman/
404 /doc/ad/no.body/
200 /doc/search/
200 /doc/search/?rfcs=on&name=snmp
200 /doc/search/?rfcs=on&name=nfs&by=ad&ad=112773
200 /doc/search/?activeDrafts=on&name=sipping
200 /doc/search/?oldDrafts=on&name=tls
200 /doc/search/?activeDrafts=on&oldDrafts=on&ad=112773&by=ad
200 /doc/search/?activeDrafts=on&state=12&by=state
200 /doc/search/?activeDrafts=on&oldDrafts=on&subState=need-rev&by=state
200 /doc/search/?activeDrafts=on&oldDrafts=on&rfcs=on&ad=112773&name=nfs&by=ad
200 /doc/search/?rfcs=on&group=tls&by=group
200 /doc/search/?activeDrafts=on&group=tls&by=group
200 /doc/search/?activeDrafts=on&oldDrafts=on&rfcs=on&author=eronen&by=author
200 /doc/search/?activeDrafts=on&oldDrafts=on&rfcs=on&area=934&name=ldap&by=area
200 /doc/search/?activeDrafts=on&name=asdfsadfsdfasdf
200 /doc/search/?activeDrafts=on&name=%EF%BD%8C #non-ASCII
# Test case for missing publication date
200 /doc/search/?oldDrafts=on&name=ppvpn

View file

@ -1,179 +0,0 @@
from django.conf import settings
from ietf.idtracker.models import InternetDraft, DocumentComment, BallotInfo, IESGLogin
from ietf.idrfc.mails import *
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream
def add_document_comment(request, doc, text, ballot=None):
if request:
login = IESGLogin.objects.get(login_name=request.user.username)
else:
login = None
c = DocumentComment()
c.document = doc.idinternal
c.public_flag = True
c.version = doc.revision_display()
c.comment_text = text
c.created_by = login
if ballot:
c.ballot = ballot
c.rfc_flag = doc.idinternal.rfc_flag
c.save()
def generate_ballot(request, doc):
ballot = BallotInfo()
ballot.ballot = doc.idinternal.ballot_id
ballot.active = False
ballot.last_call_text = generate_last_call_announcement(request, doc)
ballot.approval_text = generate_approval_mail(request, doc)
ballot.ballot_writeup = render_to_string("idrfc/ballot_writeup.txt")
ballot.save()
doc.idinternal.ballot = ballot
return ballot
def log_state_changed(request, doc, by, email_watch_list=True, note=''):
change = u"State changed to <b>%s</b> from %s." % (
doc.idinternal.docstate(),
format_document_state(doc.idinternal.prev_state,
doc.idinternal.prev_sub_state))
if note:
change += "<br>%s" % note
c = DocumentComment()
c.document = doc.idinternal
c.public_flag = True
c.version = doc.revision_display()
c.comment_text = change
if doc.idinternal.docstate()=="In Last Call":
c.comment_text += "\n\n<b>The following Last Call Announcement was sent out:</b>\n\n"
c.comment_text += doc.idinternal.ballot.last_call_text
if isinstance(by, IESGLogin):
c.created_by = by
c.result_state = doc.idinternal.cur_state
c.origin_state = doc.idinternal.prev_state
c.rfc_flag = doc.idinternal.rfc_flag
c.save()
if email_watch_list:
email_state_changed(request, doc, strip_tags(change))
return change
def log_state_changedREDESIGN(request, doc, by, prev_iesg_state, prev_iesg_tag):
from ietf.doc.models import DocEvent, IESG_SUBSTATE_TAGS
state = doc.get_state("draft-iesg")
state_name = state.name
tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
if tags:
state_name += "::" + tags[0].name
prev_state_name = prev_iesg_state.name if prev_iesg_state else "I-D Exists"
if prev_iesg_tag:
prev_state_name += "::" + prev_iesg_tag.name
e = DocEvent(doc=doc, by=by)
e.type = "changed_document"
e.desc = u"State changed to <b>%s</b> from %s" % (state_name, prev_state_name)
e.save()
return e
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
log_state_changed = log_state_changedREDESIGN
def update_telechat(request, idinternal, new_telechat_date, new_returning_item=None):
on_agenda = bool(new_telechat_date)
if new_returning_item == None:
new_returning_item = idinternal.returning_item
returning_item_changed = False
if idinternal.returning_item != bool(new_returning_item):
idinternal.returning_item = bool(new_returning_item)
returning_item_changed = True
# auto-update returning item
if (not returning_item_changed and
on_agenda and idinternal.agenda
and new_telechat_date != idinternal.telechat_date):
idinternal.returning_item = True
# update agenda
doc = idinternal.document()
if bool(idinternal.agenda) != on_agenda:
if on_agenda:
add_document_comment(request, doc,
"Placed on agenda for telechat - %s" % new_telechat_date)
idinternal.telechat_date = new_telechat_date
else:
add_document_comment(request, doc,
"Removed from agenda for telechat")
idinternal.agenda = on_agenda
elif on_agenda and new_telechat_date != idinternal.telechat_date:
add_document_comment(request, doc,
"Telechat date has been changed to <b>%s</b> from <b>%s</b>" %
(new_telechat_date,
idinternal.telechat_date))
idinternal.telechat_date = new_telechat_date
def update_telechatREDESIGN(request, doc, by, new_telechat_date, new_returning_item=None):
from ietf.doc.models import TelechatDocEvent
on_agenda = bool(new_telechat_date)
prev = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
prev_returning = bool(prev and prev.returning_item)
prev_telechat = prev.telechat_date if prev else None
prev_agenda = bool(prev_telechat)
returning_item_changed = bool(new_returning_item != None and new_returning_item != prev_returning)
if new_returning_item == None:
returning = prev_returning
else:
returning = new_returning_item
if returning == prev_returning and new_telechat_date == prev_telechat:
# fully updated, nothing to do
return
# auto-update returning item
if (not returning_item_changed and on_agenda and prev_agenda
and new_telechat_date != prev_telechat):
returning = True
e = TelechatDocEvent()
e.type = "scheduled_for_telechat"
e.by = by
e.doc = doc
e.returning_item = returning
e.telechat_date = new_telechat_date
if on_agenda != prev_agenda:
if on_agenda:
e.desc = "Placed on agenda for telechat - %s" % (new_telechat_date)
else:
e.desc = "Removed from agenda for telechat"
elif on_agenda and new_telechat_date != prev_telechat:
e.desc = "Telechat date has been changed to <b>%s</b> from <b>%s</b>" % (
new_telechat_date, prev_telechat)
else:
# we didn't reschedule but flipped returning item bit - let's
# just explain that
if returning:
e.desc = "Set telechat returning item indication"
else:
e.desc = "Removed telechat returning item indication"
e.save()
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
update_telechat = update_telechatREDESIGN

View file

@ -1,40 +0,0 @@
# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# * Neither the name of the Nokia Corporation and/or its
# subsidiary(-ies) nor the names of its contributors may be used
# to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from django.shortcuts import render_to_response
from django.template import RequestContext
from ietf.idrfc.views_search import SearchForm
def main(request):
form = SearchForm()
return render_to_response('idrfc/main.html', {'form':form}, context_instance=RequestContext(request))

View file

@ -1,10 +0,0 @@
# Copyright The IETF Trust 2007, All Rights Reserved
#
import doctest, unittest
from ietf.idtracker.templatetags import ietf_filters
class TemplateTagTest(unittest.TestCase):
def test_template_tags(self):
failures, tests = doctest.testmod(ietf_filters)
self.assertEqual(failures, 0)

View file

@ -7,7 +7,6 @@ from django.conf import settings
from pyquery import PyQuery
from ietf.idrfc.models import RfcIndex
from ietf.idtracker.models import *
from ietf.iesg.models import *
from ietf.utils.test_utils import SimpleUrlTestCase, RealDatabaseTest, canonicalize_feed, login_testing_unauthorized

View file

@ -49,11 +49,10 @@ from django.utils import simplejson as json
from django import forms
from ietf.iesg.models import TelechatDates, TelechatAgendaItem, WGAction
from ietf.idrfc.idrfc_wrapper import IdWrapper, RfcWrapper
from ietf.idrfc.models import RfcIndex
from ietf.idrfc.utils import update_telechat
from ietf.doc.utils import update_telechat
from ietf.ietfauth.decorators import group_required, role_required
from ietf.idtracker.templatetags.ietf_filters import in_group
from ietf.ipr.models import IprDocAlias
from ietf.ietfauth.utils import has_role
from ietf.ipr.models import IprDocAlias
from ietf.doc.models import Document, TelechatDocEvent, LastCallDocEvent, ConsensusDocEvent
from ietf.group.models import Group, GroupMilestone
@ -603,61 +602,27 @@ def telechat_docs_tarfile(request,year,month,day):
return response
def discusses(request):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
res = []
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:
found = True
break
if not found:
continue
if d.rfc_flag:
doc = RfcWrapper(d)
else:
doc = IdWrapper(draft=d)
if doc.in_ietf_process() and doc.ietf_process.has_active_iesg_ballot():
res.append(doc)
return direct_to_template(request, 'iesg/discusses.html', {'docs':res})
positions = Position.objects.filter(discuss=1)
res = []
try:
ids = set()
except NameError:
# for Python 2.3
from sets import Set as set
ids = set()
for p in positions:
try:
draft = p.ballot.drafts.filter(primary_flag=1)
if len(draft) > 0 and draft[0].rfc_flag:
if not -draft[0].draft_id in ids:
ids.add(-draft[0].draft_id)
try:
ri = RfcIndex.objects.get(rfc_number=draft[0].draft_id)
doc = RfcWrapper(ri)
if doc.in_ietf_process() and doc.ietf_process.has_active_iesg_ballot():
res.append(doc)
except RfcIndex.DoesNotExist:
# NOT QUITE RIGHT, although this should never happen
pass
if len(draft) > 0 and not draft[0].rfc_flag and draft[0].draft.id_document_tag not in ids:
ids.add(draft[0].draft.id_document_tag)
doc = IdWrapper(draft=draft[0])
if doc.in_ietf_process() and doc.ietf_process.has_active_iesg_ballot():
res.append(doc)
except IDInternal.DoesNotExist:
pass
return direct_to_template(request, 'iesg/discusses.html', {'docs':res})
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:
found = True
break
if not found:
continue
if d.rfc_flag:
doc = RfcWrapper(d)
else:
doc = IdWrapper(draft=d)
if doc.in_ietf_process() and doc.ietf_process.has_active_iesg_ballot():
res.append(doc)
return direct_to_template(request, 'iesg/discusses.html', {'docs':res})
@role_required('Area Director', 'Secretariat')
def milestones_needing_review(request):
@ -747,7 +712,7 @@ def get_possible_wg_actions():
def working_group_actions(request):
current_items = WGAction.objects.order_by('status_date').select_related()
if request.method == 'POST' and in_group(request.user, 'Secretariat'):
if request.method == 'POST' and has_role(request.user, 'Secretariat'):
filename = request.POST.get('filename')
if filename and filename in os.listdir(settings.IESG_WG_EVALUATION_DIR):
if 'delete' in request.POST:

View file

@ -260,7 +260,7 @@ def session_agenda(request, num, session):
if d:
agenda = d[0]
content = read_agenda_file(num, agenda)
content = read_agenda_file(num, agenda) or "Could not read agenda file"
_, ext = os.path.splitext(agenda.external_url)
ext = ext.lstrip(".").lower()
@ -331,33 +331,34 @@ def read_agenda_file(num, doc):
return None
def session_draft_list(num, session):
#extensions = ["html", "htm", "txt", "HTML", "HTM", "TXT", ]
result = []
found = False
try:
agenda = Document.objects.filter(type="agenda",
session__meeting__number=num,
session__group__acronym=session,
states=State.objects.get(type="agenda", slug="active")).distinct().get()
except Document.DoesNotExist:
raise Http404
drafts = set()
content = read_agenda_file(num, agenda)
if content:
drafts.update(re.findall('(draft-[-a-z0-9]*)', content))
for agenda in Document.objects.filter(type="agenda", session__meeting__number=num, session__group__acronym=session):
content = read_agenda_file(num, agenda)
if content != None:
found = True
drafts.update(re.findall('(draft-[-a-z0-9]*)', content))
if not found:
raise Http404("No agenda for the %s group of IETF %s is available" % (session, num))
result = []
for draft in drafts:
try:
if (re.search('-[0-9]{2}$',draft)):
if re.search('-[0-9]{2}$', draft):
doc_name = draft
else:
id = InternetDraft.objects.get(filename=draft)
#doc = IdWrapper(id)
doc_name = draft + "-" + id.revision
result.append(doc_name)
except InternetDraft.DoesNotExist:
doc = Document.objects.get(filename=draft)
doc_name = draft + "-" + doc.rev
if doc_name not in result:
result.append(doc_name)
except Document.DoesNotExist:
pass
return sorted(list(set(result)))
return sorted(result)
def session_draft_tarfile(request, num, session):

View file

@ -7,7 +7,7 @@ from django.template.defaultfilters import linebreaksbr, force_escape
from ietf.utils.pipe import pipe
from ietf.ietfauth.decorators import has_role
from ietf.idtracker.templatetags.ietf_filters import wrap_text
from ietf.doc.templatetags.ietf_filters import wrap_text
from ietf.person.models import Person
from ietf.nomcom.models import Feedback

View file

@ -13,9 +13,8 @@ from ietf.doc.utils import get_document_content, log_state_changed
from ietf.group.models import Group
from ietf.name.models import BallotPositionName
from ietf.person.models import Person
from ietf.idrfc.lastcall import request_last_call
from ietf.idrfc.mails import email_owner, email_state_changed
from ietf.idrfc.utils import add_document_comment
from ietf.doc.lastcall import request_last_call
from ietf.doc.mails import email_ad, email_state_changed
from ietf.iesg.models import TelechatDate, TelechatAgendaItem, WGAction
from ietf.iesg.views import _agenda_data
@ -230,7 +229,7 @@ def doc_detail(request, date, name):
if request.method == 'POST':
button_text = request.POST.get('submit', '')
# logic from idrfc/views_ballot.py EditPositionRedesign
# logic from doc/views_ballot.py EditPositionRedesign
if button_text == 'update_ballot':
formset = BallotFormset(request.POST, initial=initial_ballot)
state_form = ChangeStateForm(initial=initial_state)
@ -257,7 +256,7 @@ def doc_detail(request, date, name):
url = reverse('telechat_doc_detail', kwargs={'date':date,'name':name})
return HttpResponseRedirect(url)
# logic from idrfc/views_edit.py change_stateREDESIGN
# logic from doc/views_draft.py change_state
elif button_text == 'update_state':
formset = BallotFormset(initial=initial_ballot)
state_form = ChangeStateForm(request.POST, initial=initial_state)
@ -291,7 +290,7 @@ def doc_detail(request, date, name):
doc.save()
email_state_changed(request, doc, e.desc)
email_owner(request, doc, doc.ad, login, e.desc)
email_ad(request, doc, doc.ad, login, e.desc)
if state.slug == "lc-req":
request_last_call(request, doc)
@ -436,4 +435,4 @@ def roll_call(request, date):
'people':sorted_ads},
RequestContext(request, {}),
)

View file

@ -1,7 +1,7 @@
# Standard settings except we use SQLite, this is useful for speeding
# up tests that depend on the test database, try for instance:
#
# ./manage.py test --settings=settings_sqlitetest idrfc.ChangeStateTestCase
# ./manage.py test --settings=settings_sqlitetest doc.ChangeStateTestCase
#
from settings import *

View file

@ -47,53 +47,6 @@ def request_full_url(request, submission):
def perform_post(request, submission):
group_id = submission.group_acronym and submission.group_acronym.pk or NONE_WG
state_change_msg = ''
try:
draft = InternetDraft.objects.get(filename=submission.filename)
draft.title = submission.id_document_name
draft.group_id = group_id
draft.filename = submission.filename
draft.revision = submission.revision
draft.revision_date = submission.submission_date
draft.file_type = submission.file_type
draft.txt_page_count = submission.txt_page_count
draft.last_modified_date = datetime.date.today()
draft.abstract = submission.abstract
draft.status_id = 1 # Active
draft.expired_tombstone = 0
draft.save()
except InternetDraft.DoesNotExist:
draft = InternetDraft.objects.create(
title=submission.id_document_name,
group_id=group_id,
filename=submission.filename,
revision=submission.revision,
revision_date=submission.submission_date,
file_type=submission.file_type,
txt_page_count=submission.txt_page_count,
start_date=datetime.date.today(),
last_modified_date=datetime.date.today(),
abstract=submission.abstract,
status_id=1, # Active
intended_status_id=8, # None
)
update_authors(draft, submission)
if draft.idinternal:
from ietf.idrfc.utils import add_document_comment
add_document_comment(None, draft, "New version available")
if draft.idinternal.cur_sub_state_id == 5 and draft.idinternal.rfc_flag == 0: # Substate 5 Revised ID Needed
draft.idinternal.prev_sub_state_id = draft.idinternal.cur_sub_state_id
draft.idinternal.cur_sub_state_id = 2 # Substate 2 AD Followup
draft.idinternal.save()
state_change_msg = "Sub state has been changed to AD Follow up from New Id Needed"
add_document_comment(None, draft, state_change_msg)
move_docs(submission)
submission.status_id = POSTED
send_announcements(submission, draft, state_change_msg)
submission.save()
def perform_postREDESIGN(request, submission):
system = Person.objects.get(name="(System)")
group_id = submission.group_acronym_id or NONE_WG
@ -163,7 +116,7 @@ def perform_postREDESIGN(request, submission):
# clean up old files
if prev_rev != draft.rev:
from ietf.idrfc.expire import move_draft_files_to_archive
from ietf.doc.expire import move_draft_files_to_archive
move_draft_files_to_archive(draft, prev_rev)
# automatic state changes
@ -189,9 +142,6 @@ def perform_postREDESIGN(request, submission):
submission.save()
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
perform_post = perform_postREDESIGN
def send_announcements(submission, draft, state_change_msg):
announce_to_lists(request, submission)
if draft.idinternal and not draft.idinternal.rfc_flag:

View file

@ -5,8 +5,8 @@ from django.conf import settings
from ietf.doc.models import *
from ietf.doc.utils import add_state_change_event
from ietf.doc.mails import email_ad, email_state_changed, email_authors
from ietf.person.models import *
from ietf.idrfc.mails import email_owner, email_state_changed, email_authors
from ietf.utils.timezone import *
#PROTOCOLS_URL = "http://www.iana.org/protocols/"
@ -200,7 +200,7 @@ def update_history_with_changes(changes, send_email=True):
if send_email and (state != prev_state):
email_state_changed(None, doc, "IANA %s state changed to %s" % (kind, state.name))
email_owner(None, doc, doc.ad, system, "IANA %s state changed to %s" % (kind, state.name))
email_ad(None, doc, doc.ad, system, "IANA %s state changed to %s" % (kind, state.name))
if doc.time < timestamp:
doc.time = timestamp

View file

@ -32,9 +32,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% endcomment %}
{% for area in areas %}
{% if area.area.active_wgs %}
<li class="yuimenuitem"><a class="yuimenuitemlabel">{{area.short_name }}</a><div id="wgs-{{area.area.area_acronym}}" class="yuimenu"><div class="bd"><ul>{% for wg in area.area.active_wgs %}
<li class="yuimenuitem"><a class="yuimenuitemlabel" href="/wg/{{wg.group_acronym}}/">{{wg.group_acronym}} &mdash; {{wg.group_acronym.name}}</a></li>{% endfor %}
<li class="yuimenuitem"><a class="yuimenuitemlabel">{{ area.short_area_name }}</a><div id="wgs-{{ area.acronym }}" class="yuimenu"><div class="bd"><ul>{% for g in area.active_groups %}
<li class="yuimenuitem"><a class="yuimenuitemlabel" href="/wg/{{ g.acronym }}/">{{ g.acronym }} &mdash; {{ g.name}}</a></li>{% endfor %}
</ul></div></div></li>
{% endif %}
{% endfor %}

View file

@ -6,7 +6,7 @@
<div class="actions">
{% if request.user|has_role:"Area Director" %}
<a href="{% url ietf.idrfc.views_ballot.edit_position name=doc.name ballot_id=ballot_id %}" class="button" style="margin-right: 1em;">Edit Position</a>
<a href="{% url ietf.doc.views_ballot.edit_position name=doc.name ballot_id=ballot_id %}" class="button" style="margin-right: 1em;">Edit Position</a>
{% endif %}
<a href="" class="button close">Close</a>

View file

@ -4,7 +4,7 @@
{% if editable and user|has_role:"Area Director,Secretariat" %}
<div class="ballot-actions">
{% if user|has_role:"Area Director" %}
<div class="action"><a href="{% url idrfc.views_ballot.edit_position name=doc.name,ballot_id=ballot.pk %}">Edit position</a></div>
<div class="action"><a href="{% url ietf.doc.views_ballot.edit_position name=doc.name,ballot_id=ballot.pk %}">Edit position</a></div>
{% endif %}
{% if doc.type_id == "draft" or doc.type_id == "conflrev" %}
@ -28,7 +28,7 @@
<div class="position-group">
<div class="heading"><span class="square position-{{ n.slug }}"></span> {{ n.name }}</div>
{% for p in positions %}
<div>{% if p.old_ad %}[{% endif %}<a{% if user|has_role:"Secretariat" %} href="{% url idrfc.views_ballot.edit_position name=doc.name,ballot_id=ballot.pk %}?ad={{ p.ad.pk }}" title="Click to edit the position of {{ p.ad.plain_name }}"{% endif %}>{{ p.ad.plain_name }}</a>{% if p.old_ad %}]{% endif %}{% if p.comment or p.discuss %}&nbsp;<a href="#{{ p.ad.plain_name|slugify }}"><img src="/images/comment.png" width="14" height="12" alt="*" border="0"/></a>{% endif %}</div>
<div>{% if p.old_ad %}[{% endif %}<a{% if user|has_role:"Secretariat" %} href="{% url ietf.doc.views_ballot.edit_position name=doc.name,ballot_id=ballot.pk %}?ad={{ p.ad.pk }}" title="Click to edit the position of {{ p.ad.plain_name }}"{% endif %}>{{ p.ad.plain_name }}</a>{% if p.old_ad %}]{% endif %}{% if p.comment or p.discuss %}&nbsp;<a href="#{{ p.ad.plain_name|slugify }}"><img src="/images/comment.png" width="14" height="12" alt="*" border="0"/></a>{% endif %}</div>
{% if p.old_positions %}<div class="was">(was {{ p.old_positions|join:", " }})</div>{% endif %}
{% empty %}
<i>none</i>

View file

@ -25,7 +25,7 @@
{% if snapshot %}Snapshot of{% endif %}
{% if doc.get_state_slug != "approved" %}Proposed{% endif %}
Charter for "{{ group.name }}"
(<a href="{% url ietf.wginfo.views.wg_charter acronym=group.acronym %}">{{ group.acronym }}</a>) {{ group.type.name }}
(<a {% if group.type.slug == "wg" %}href="{% url ietf.wginfo.views.wg_charter acronym=group.acronym %}"{% endif %}>{{ group.acronym }}</a>) {{ group.type.name }}
</div>
<table id="metatable" width="100%">

View file

@ -36,7 +36,7 @@
</tr>
{% endfor %}
<tr>
<td><a href="/doc/help/state/status-change/">Review State</a>:</td>
<td><a href="{% url state_help type="status-change" %}">Review State</a>:</td>
<td>
<div>
<a title="{{ doc.get_state.desc }}"{% if not snapshot and user|has_role:"Area Director,Secretariat" %} class="editlink" href="{% url status_change_change_state name=doc.name %}"{% endif %}>{{ doc.get_state.name }}</a>

View file

@ -5,7 +5,7 @@
{% block content %}
<h1>Documents for {{ ad_name }}</h1>
{% include "idrfc/search_results.html" %}
{% include "doc/search/search_results.html" %}
{% endblock %}

View file

@ -5,7 +5,7 @@
{% block content %}
<h1>Internet-Drafts in IETF Last Call</h1>
{% include "idrfc/search_results.html" %}
{% include "doc/search/search_results.html" %}
{% endblock %}

View file

@ -54,7 +54,7 @@ td.ietf-main-intro { width:200px; background:#fff5df; padding:8px; border:1px so
<tr valign="top"><td class="ietf-box ietf-main-search">
<h1>Search Internet-Drafts and RFCs</h1>
{% include "idrfc/search_form.html" %}
{% include "doc/search/search_form.html" %}
</td>
<td style="width:8px;">&nbsp;</td>
<td class="ietf-main-intro">

Some files were not shown because too many files have changed in this diff Show more