Ported last call text and ballot writeup views with friends and tests to new schema
- Legacy-Id: 2860
This commit is contained in:
parent
280080e55a
commit
bf29f1a5f9
|
@ -9,7 +9,7 @@ from django.conf import settings
|
|||
|
||||
from ietf.utils.mail import send_mail, send_mail_text
|
||||
from ietf.idtracker.models import *
|
||||
from doc.models import Text
|
||||
from doc.models import Text, BallotPosition, Expiration
|
||||
from person.models import Email
|
||||
|
||||
def email_state_changed(request, doc, text):
|
||||
|
@ -94,6 +94,8 @@ def generate_ballot_writeup(request, doc):
|
|||
e.content = unicode(render_to_string("idrfc/ballot_writeup.txt"))
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
||||
def generate_last_call_announcement(request, doc):
|
||||
status = full_intended_status(doc.intended_status).replace("a ", "").replace("an ", "")
|
||||
|
||||
|
@ -156,7 +158,6 @@ def generate_last_call_announcementREDESIGN(request, doc):
|
|||
)
|
||||
)
|
||||
|
||||
from doc.models import Text
|
||||
e = Text()
|
||||
e.type = "changed_last_call_text"
|
||||
e.by = request.user.get_profile().email()
|
||||
|
@ -164,6 +165,8 @@ def generate_last_call_announcementREDESIGN(request, doc):
|
|||
e.desc = u"Last call announcement was generated by %s" % e.by.get_name()
|
||||
e.content = unicode(mail)
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
|
@ -250,7 +253,6 @@ def generate_approval_mailREDESIGN(request, doc):
|
|||
else:
|
||||
mail = generate_approval_mail_approved(request, doc)
|
||||
|
||||
from doc.models import Text
|
||||
e = Text()
|
||||
e.type = "changed_ballot_approval_text"
|
||||
e.by = request.user.get_profile().email()
|
||||
|
@ -259,6 +261,8 @@ def generate_approval_mailREDESIGN(request, doc):
|
|||
e.content = unicode(mail)
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
||||
def generate_approval_mail_approved(request, doc):
|
||||
doc.full_status = full_intended_status(doc.intended_std_level.name)
|
||||
status = doc.full_status.replace("a ", "").replace("an ", "")
|
||||
|
@ -467,7 +471,79 @@ def generate_issue_ballot_mail(request, doc):
|
|||
ad_feedback=ad_feedback
|
||||
)
|
||||
)
|
||||
|
||||
def generate_issue_ballot_mailREDESIGN(request, doc):
|
||||
full_status = full_intended_status(doc.intended_std_level.name)
|
||||
status = full_status.replace("a ", "").replace("an ", "")
|
||||
|
||||
active_ads = Email.objects.filter(role__name="ad", role__group__state="active")
|
||||
|
||||
e = doc.latest_event(type="started_iesg_process")
|
||||
positions = BallotPosition.objects.filter(doc=doc, type="changed_ballot_position", time__gte=e.time).order_by("-time", '-id').select_related('ad')
|
||||
|
||||
# format positions and setup discusses and comments
|
||||
ad_feedback = []
|
||||
seen = set()
|
||||
active_ad_positions = []
|
||||
inactive_ad_positions = []
|
||||
for p in positions:
|
||||
if p.ad in seen:
|
||||
continue
|
||||
|
||||
seen.add(p.ad)
|
||||
|
||||
def formatted(val):
|
||||
if val:
|
||||
return "[ X ]"
|
||||
else:
|
||||
return "[ ]"
|
||||
|
||||
fmt = u"%-21s%-10s%-11s%-9s%-10s" % (
|
||||
p.ad.get_name()[:21],
|
||||
formatted(p.pos_id == "yes"),
|
||||
formatted(p.pos_id == "noobj"),
|
||||
formatted(p.pos_id == "discuss"),
|
||||
"[ R ]" if p.pos_id == "recuse" else formatted(p.pos_id == "abstain"),
|
||||
)
|
||||
|
||||
if p.ad in active_ads:
|
||||
active_ad_positions.append(fmt)
|
||||
if not p.pos_id == "discuss":
|
||||
p.discuss = ""
|
||||
if p.comment or p.discuss:
|
||||
ad_feedback.append(p)
|
||||
else:
|
||||
inactive_ad_positions.append(fmt)
|
||||
|
||||
active_ad_positions.sort()
|
||||
inactive_ad_positions.sort()
|
||||
ad_feedback.sort(key=lambda p: p.ad.get_name())
|
||||
|
||||
e = doc.latest_event(Expiration, type="sent_last_call")
|
||||
last_call_expires = e.expires if e else None
|
||||
|
||||
e = doc.latest_event(Text, type="changed_ballot_approval_text")
|
||||
approval_text = e.content if e else ""
|
||||
|
||||
e = doc.latest_event(Text, type="changed_ballot_writeup_text")
|
||||
ballot_writeup = e.content if e else ""
|
||||
|
||||
return render_to_string("idrfc/issue_ballot_mailREDESIGN.txt",
|
||||
dict(doc=doc,
|
||||
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
||||
status=status,
|
||||
active_ad_positions=active_ad_positions,
|
||||
inactive_ad_positions=inactive_ad_positions,
|
||||
ad_feedback=ad_feedback,
|
||||
last_call_expires=last_call_expires,
|
||||
approval_text=approval_text,
|
||||
ballot_writeup=ballot_writeup,
|
||||
)
|
||||
)
|
||||
|
||||
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 message to IANA for each in ballot set
|
||||
import email
|
||||
|
@ -485,6 +561,25 @@ def email_iana(request, doc, to, msg):
|
|||
extra=extra,
|
||||
bcc="fenner@research.att.com")
|
||||
|
||||
def email_ianaREDESIGN(request, doc, to, msg):
|
||||
# fix up message and send it with extra info on doc in headers
|
||||
import email
|
||||
parsed_msg = email.message_from_string(msg.encode("utf-8"))
|
||||
|
||||
extra = {}
|
||||
extra["Reply-To"] = "noreply@ietf.org"
|
||||
extra["X-IETF-Draft-string"] = doc.name
|
||||
extra["X-IETF-Draft-revision"] = doc.rev
|
||||
|
||||
send_mail_text(request, "IANA <%s>" % to,
|
||||
parsed_msg["From"], parsed_msg["Subject"],
|
||||
parsed_msg.get_payload(),
|
||||
extra=extra,
|
||||
bcc="fenner@research.att.com")
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
email_iana = email_ianaREDESIGN
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -97,40 +97,42 @@ def make_test_data():
|
|||
login_name="ad",
|
||||
password="foo",
|
||||
user_level=1,
|
||||
first_name="Aread",
|
||||
last_name="Irector",
|
||||
first_name=porg.first_name,
|
||||
last_name=porg.last_name,
|
||||
person=porg,
|
||||
)
|
||||
|
||||
p = Person.objects.create(
|
||||
name="Ano Therdir",
|
||||
ascii="Ano Therdir",
|
||||
)
|
||||
email = Email.objects.create(
|
||||
address="ano@ietf.org",
|
||||
person=p)
|
||||
Role.objects.create(
|
||||
name_id="ad",
|
||||
group=area,
|
||||
email=email)
|
||||
porg = PersonOrOrgInfo.objects.create(
|
||||
first_name="Ano",
|
||||
last_name="Therdir",
|
||||
middle_initial="",
|
||||
)
|
||||
EmailAddress.objects.create(
|
||||
person_or_org=porg,
|
||||
priority=1,
|
||||
address=ad.address,
|
||||
)
|
||||
IESGLogin.objects.create(
|
||||
login_name="ad2",
|
||||
password="foo",
|
||||
user_level=1,
|
||||
first_name="Ano",
|
||||
last_name="Therdir",
|
||||
person=porg,
|
||||
)
|
||||
# create a bunch of ads for swarm tests
|
||||
for i in range(1, 10):
|
||||
p = Person.objects.create(
|
||||
name="Ad No%s" % i,
|
||||
ascii="Ad No%s" % i,
|
||||
)
|
||||
email = Email.objects.create(
|
||||
address="ad%s@ietf.org" % i,
|
||||
person=p)
|
||||
Role.objects.create(
|
||||
name_id="ad" if i <= 5 else "ex-ad",
|
||||
group=area,
|
||||
email=email)
|
||||
porg = PersonOrOrgInfo.objects.create(
|
||||
first_name="Ad",
|
||||
last_name="No%s" % i,
|
||||
middle_initial="",
|
||||
)
|
||||
EmailAddress.objects.create(
|
||||
person_or_org=porg,
|
||||
priority=1,
|
||||
address=ad.address,
|
||||
)
|
||||
IESGLogin.objects.create(
|
||||
login_name="ad%s" % i,
|
||||
password="foo",
|
||||
user_level=1,
|
||||
first_name=porg.first_name,
|
||||
last_name=porg.last_name,
|
||||
person=porg,
|
||||
)
|
||||
|
||||
p = Person.objects.create(
|
||||
name="Sec Retary",
|
||||
|
@ -153,8 +155,8 @@ def make_test_data():
|
|||
login_name="secretary",
|
||||
password="foo",
|
||||
user_level=0,
|
||||
first_name="Sec",
|
||||
last_name="Retary",
|
||||
first_name=porg.first_name,
|
||||
last_name=porg.last_name,
|
||||
person=porg,
|
||||
)
|
||||
|
||||
|
@ -295,8 +297,6 @@ class ChangeStateTestCase(django.test.TestCase):
|
|||
|
||||
# comment
|
||||
self.assertTrue("Last call was requested" in draft.event_set.all()[0].desc)
|
||||
|
||||
# FIXME: test regeneration of announcement when it's not approved/via rfc editor
|
||||
|
||||
|
||||
class EditInfoTestCase(django.test.TestCase):
|
||||
|
@ -327,7 +327,7 @@ class EditInfoTestCase(django.test.TestCase):
|
|||
events_before = draft.event_set.count()
|
||||
mailbox_before = len(mail_outbox)
|
||||
|
||||
new_ad = Email.objects.get(address="ano@ietf.org")
|
||||
new_ad = Email.objects.get(address="ad1@ietf.org")
|
||||
|
||||
r = self.client.post(url,
|
||||
dict(intended_std_level=str(draft.intended_std_level.pk),
|
||||
|
@ -702,10 +702,10 @@ class DeferBallotTestCase(django.test.TestCase):
|
|||
self.assertEquals(draft.iesg_state_id, "iesg-eva")
|
||||
|
||||
class BallotWriteupsTestCase(django.test.TestCase):
|
||||
fixtures = ['base', 'draft', 'ballot']
|
||||
fixtures = ['names']
|
||||
|
||||
def test_edit_last_call_text(self):
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_ballot_lastcall', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
|
@ -715,7 +715,9 @@ class BallotWriteupsTestCase(django.test.TestCase):
|
|||
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",
|
||||
|
@ -729,8 +731,8 @@ class BallotWriteupsTestCase(django.test.TestCase):
|
|||
last_call_text="This is a simple test.",
|
||||
save_last_call_text="1"))
|
||||
self.assertEquals(r.status_code, 200)
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
self.assertTrue("This is a simple test" in draft.idinternal.ballot.last_call_text)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("This is a simple test" in draft.latest_event(Text, type="changed_last_call_text").content)
|
||||
|
||||
# test regenerate
|
||||
r = self.client.post(url, dict(
|
||||
|
@ -738,28 +740,33 @@ class BallotWriteupsTestCase(django.test.TestCase):
|
|||
regenerate_last_call_text="1"))
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
self.assertTrue("Subject: Last Call" in draft.idinternal.ballot.last_call_text)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("Subject: Last Call" in draft.latest_event(Text, type="changed_last_call_text").content)
|
||||
|
||||
|
||||
def test_request_last_call(self):
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_ballot_lastcall', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
mailbox_before = len(mail_outbox)
|
||||
# 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(mail_outbox)
|
||||
|
||||
# send
|
||||
r = self.client.post(url, dict(
|
||||
last_call_text=draft.idinternal.ballot.last_call_text,
|
||||
last_call_text=draft.latest_event(Text, type="changed_last_call_text").content,
|
||||
send_last_call_request="1"))
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
self.assertEquals(draft.idinternal.cur_state_id, IDState.LAST_CALL_REQUESTED)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.iesg_state_id, "lc-req")
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 3)
|
||||
|
||||
self.assertTrue("Last Call" in mail_outbox[-1]['Subject'])
|
||||
self.assertTrue(draft.name in mail_outbox[-1]['Subject'])
|
||||
|
||||
def test_edit_ballot_writeup(self):
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
|
@ -775,43 +782,66 @@ class BallotWriteupsTestCase(django.test.TestCase):
|
|||
ballot_writeup="This is a simple test.",
|
||||
save_ballot_writeup="1"))
|
||||
self.assertEquals(r.status_code, 200)
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
self.assertTrue("This is a simple test" in draft.idinternal.ballot.ballot_writeup)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("This is a simple test" in draft.latest_event(Text, type="changed_ballot_writeup_text").content)
|
||||
|
||||
def test_issue_ballot(self):
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
draft.idinternal.ballot.ballot_issued = False
|
||||
draft.idinternal.ballot.save()
|
||||
active = IESGLogin.objects.filter(user_level=1)
|
||||
Position.objects.create(ad=active[0], yes=1, noobj=0, discuss=0, abstain=0, recuse=0, ballot=draft.idinternal.ballot)
|
||||
Position.objects.create(ad=active[1], yes=0, noobj=1, discuss=0, abstain=0, recuse=0, ballot=draft.idinternal.ballot)
|
||||
Position.objects.create(ad=active[2], yes=0, noobj=1, discuss=-1, abstain=0, recuse=0, ballot=draft.idinternal.ballot)
|
||||
Position.objects.create(ad=active[3], yes=0, noobj=0, discuss=1, abstain=0, recuse=0, ballot=draft.idinternal.ballot)
|
||||
Position.objects.create(ad=active[4], yes=0, noobj=0, discuss=0, abstain=1, recuse=0, ballot=draft.idinternal.ballot)
|
||||
Position.objects.create(ad=active[5], yes=0, noobj=0, discuss=0, abstain=0, recuse=1, ballot=draft.idinternal.ballot)
|
||||
inactive = IESGLogin.objects.filter(user_level=2)
|
||||
Position.objects.create(ad=inactive[0], yes=1, noobj=0, discuss=0, abstain=0, recuse=0, ballot=draft.idinternal.ballot)
|
||||
IESGDiscuss.objects.create(ad=active[1], active=True, date=datetime.date.today(), text="test " * 20, ballot=draft.idinternal.ballot)
|
||||
IESGComment.objects.create(ad=active[2], active=True, date=datetime.date.today(), text="test " * 20, ballot=draft.idinternal.ballot)
|
||||
IESGDiscuss.objects.create(ad=active[3], active=True, date=datetime.date.today(), text="test " * 20, ballot=draft.idinternal.ballot)
|
||||
IESGComment.objects.create(ad=active[3], active=True, date=datetime.date.today(), text="test " * 20, ballot=draft.idinternal.ballot)
|
||||
def create_pos(num, vote, comment="", discuss=""):
|
||||
ad = Email.objects.get(address="ad%s@ietf.org" % num)
|
||||
e = BallotPosition()
|
||||
e.doc = draft
|
||||
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")
|
||||
|
||||
# we need approval text to be able to submit
|
||||
e = Text()
|
||||
e.doc = draft
|
||||
e.by = Email.objects.get(address="aread@ietf.org")
|
||||
e.type = "changed_ballot_approval_text"
|
||||
e.content = "The document has been approved."
|
||||
e.save()
|
||||
|
||||
mailbox_before = len(mail_outbox)
|
||||
|
||||
r = self.client.post(url, dict(
|
||||
ballot_writeup=draft.idinternal.ballot.ballot_writeup,
|
||||
approval_text=draft.idinternal.ballot.approval_text,
|
||||
ballot_writeup="This is a test.",
|
||||
issue_ballot="1"))
|
||||
self.assertEquals(r.status_code, 200)
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
|
||||
self.assertTrue(draft.idinternal.ballot.ballot_issued)
|
||||
self.assertTrue(draft.latest_event(type="sent_ballot_announcement"))
|
||||
self.assertEquals(len(mail_outbox), mailbox_before + 2)
|
||||
self.assertTrue("Evaluation:" in mail_outbox[-2]['Subject'])
|
||||
|
||||
issue_email = mail_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 document has been approved" in str(issue_email))
|
||||
|
||||
def test_edit_approval_text(self):
|
||||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
|
@ -850,6 +880,8 @@ class BallotWriteupsTestCase(django.test.TestCase):
|
|||
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
|
||||
self.assertTrue("Subject: Protocol Action" in draft.idinternal.ballot.approval_text)
|
||||
|
||||
# FIXME: test regeneration of announcement when it's not approved/via rfc editor
|
||||
|
||||
class ApproveBallotTestCase(django.test.TestCase):
|
||||
fixtures = ['base', 'draft', 'ballot']
|
||||
|
||||
|
|
|
@ -670,6 +670,7 @@ def lastcalltext(request, name):
|
|||
|
||||
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,
|
||||
|
@ -678,6 +679,101 @@ def lastcalltext(request, name):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
class LastCallTextFormREDESIGN(forms.Form):
|
||||
last_call_text = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
||||
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", "")
|
||||
|
||||
@group_required('Area_Director','Secretariat')
|
||||
def lastcalltextREDESIGN(request, name):
|
||||
"""Editing of the last call text"""
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
if not doc.iesg_state:
|
||||
raise Http404()
|
||||
|
||||
login = request.user.get_profile().email()
|
||||
|
||||
existing = doc.latest_event(Text, type="changed_last_call_text")
|
||||
if not existing:
|
||||
existing = generate_last_call_announcement(request, doc)
|
||||
|
||||
form = LastCallTextForm(initial=dict(last_call_text=existing.content))
|
||||
|
||||
if request.method == 'POST':
|
||||
if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST:
|
||||
form = LastCallTextForm(request.POST)
|
||||
if form.is_valid():
|
||||
t = form.cleaned_data['last_call_text']
|
||||
if t != existing.content:
|
||||
e = Text(doc=doc, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_last_call_text"
|
||||
e.desc = "Last call announcement was changed by %s" % login.get_name()
|
||||
e.content = t
|
||||
e.save()
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
if "send_last_call_request" in request.POST:
|
||||
save_document_in_history(doc)
|
||||
|
||||
prev = doc.iesg_state
|
||||
doc.iesg_state = IesgDocStateName.objects.get(slug='lc-req')
|
||||
e = log_state_changed(request, doc, login, prev)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
email_state_changed(request, doc, e.desc)
|
||||
email_owner(request, doc, doc.ad, login, e.desc)
|
||||
|
||||
request_last_call(request, doc)
|
||||
|
||||
return render_to_response('idrfc/last_call_requested.html',
|
||||
dict(doc=doc),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
if "regenerate_last_call_text" in request.POST:
|
||||
e = generate_last_call_announcement(request, doc)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
# make sure form has the updated text
|
||||
form = LastCallTextForm(initial=dict(last_call_text=e.content))
|
||||
|
||||
|
||||
can_request_last_call = doc.iesg_state.order < 27
|
||||
can_make_last_call = doc.iesg_state.order < 20
|
||||
can_announce = doc.iesg_state.order > 19
|
||||
|
||||
need_intended_status = ""
|
||||
if not doc.intended_std_level:
|
||||
need_intended_status = doc.file_tag()
|
||||
|
||||
return render_to_response('idrfc/ballot_lastcalltext.html',
|
||||
dict(doc=doc,
|
||||
back_url=doc.get_absolute_url(),
|
||||
last_call_form=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))
|
||||
|
||||
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"""
|
||||
|
@ -734,7 +830,8 @@ def ballot_writeupnotes(request, name):
|
|||
doc.idinternal.save()
|
||||
|
||||
return render_to_response('idrfc/ballot_issued.html',
|
||||
dict(doc=doc),
|
||||
dict(doc=doc,
|
||||
back_url=doc.idinternal.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
|
@ -752,6 +849,93 @@ def ballot_writeupnotes(request, name):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class BallotWriteupFormREDESIGN(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):
|
||||
"""Editing of ballot write-up and notes"""
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
if not doc.iesg_state:
|
||||
raise Http404()
|
||||
|
||||
login = request.user.get_profile().email()
|
||||
|
||||
approval = doc.latest_event(Text, type="changed_ballot_approval_text")
|
||||
|
||||
existing = doc.latest_event(Text, type="changed_ballot_writeup_text")
|
||||
if not existing:
|
||||
existing = generate_ballot_writeup(request, doc)
|
||||
|
||||
form = BallotWriteupForm(initial=dict(ballot_writeup=existing.content))
|
||||
|
||||
if request.method == 'POST' and "save_ballot_writeup" in request.POST or "issue_ballot" in request.POST:
|
||||
form = BallotWriteupForm(request.POST)
|
||||
if form.is_valid():
|
||||
t = form.cleaned_data["ballot_writeup"]
|
||||
if t != existing.content:
|
||||
e = Text(doc=doc, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_ballot_writeup_text"
|
||||
e.desc = "Ballot writeup was changed by %s" % login.get_name()
|
||||
e.content = t
|
||||
e.save()
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
if "issue_ballot" in request.POST and approval:
|
||||
if in_group(request.user, "Area_Director") and not doc.latest_event(BallotPosition, ad=login):
|
||||
# sending the ballot counts as a yes
|
||||
pos = BallotPosition(doc=doc, by=login)
|
||||
pos.type = "changed_ballot_position"
|
||||
pos.ad = login
|
||||
pos.pos_id = "yes"
|
||||
pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.get_name())
|
||||
pos.save()
|
||||
|
||||
msg = generate_issue_ballot_mail(request, doc)
|
||||
send_mail_preformatted(request, msg)
|
||||
|
||||
email_iana(request, doc, 'drafts-eval@icann.org', msg)
|
||||
|
||||
e = Event(doc=doc, by=login)
|
||||
e.by = login
|
||||
e.type = "sent_ballot_announcement"
|
||||
e.desc = "Ballot has been issued by %s" % login.get_name()
|
||||
e.save()
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
return render_to_response('idrfc/ballot_issued.html',
|
||||
dict(doc=doc,
|
||||
back_url=doc.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
need_intended_status = ""
|
||||
if not doc.intended_std_level:
|
||||
need_intended_status = doc.file_tag()
|
||||
|
||||
return render_to_response('idrfc/ballot_writeupnotesREDESIGN.html',
|
||||
dict(doc=doc,
|
||||
back_url=doc.get_absolute_url(),
|
||||
ballot_issued=bool(doc.latest_event(type="sent_ballot_announcement")),
|
||||
ballot_writeup_form=form,
|
||||
need_intended_status=need_intended_status,
|
||||
approval=approval,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
BallotWriteupForm = BallotWriteupFormREDESIGN
|
||||
ballot_writeupnotes = ballot_writeupnotesREDESIGN
|
||||
|
||||
|
||||
@group_required('Area_Director','Secretariat')
|
||||
def ballot_approvaltext(request, name):
|
||||
"""Editing of approval text"""
|
||||
|
|
|
@ -179,6 +179,9 @@ class InternetDraft(models.Model):
|
|||
return self.filename
|
||||
def file_tag(self):
|
||||
return "<%s-%s.txt>" % (self.filename, self.revision_display())
|
||||
def name(self):
|
||||
# small hack to make model forward-compatible with new schema
|
||||
return self.filename
|
||||
def group_acronym(self):
|
||||
return self.group.acronym
|
||||
def idstate(self):
|
||||
|
@ -397,6 +400,9 @@ class Rfc(models.Model):
|
|||
return "%s.txt" % ( self.filename() )
|
||||
def filename(self):
|
||||
return "rfc%d" % ( self.rfc_number )
|
||||
def name(self):
|
||||
# small hack to make model forward-compatible with new schema
|
||||
return self.filename()
|
||||
def revision(self):
|
||||
return "RFC"
|
||||
def revision_display(self):
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
<p>Ballot has been sent out.</p>
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{ doc.idinternal.get_absolute_url }}">Back to document</a>
|
||||
<a href="{{ back_url }}">Back to document</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -25,7 +25,7 @@ form #id_last_call_text {
|
|||
{% endif %}
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{ doc.idinternal.get_absolute_url }}">Back</a>
|
||||
<a href="{{ back_url }}">Back</a>
|
||||
<input type="submit" name="save_last_call_text" value="Save Last Call Text" />
|
||||
<input type="submit" name="regenerate_last_call_text" value="Regenerate Last Call Text" />
|
||||
{% if can_request_last_call and not need_intended_status %}
|
||||
|
@ -38,7 +38,7 @@ form #id_last_call_text {
|
|||
{% if user|in_group:"Secretariat" %}
|
||||
<p>
|
||||
{% if can_make_last_call %}
|
||||
<a href="{% url doc_make_last_call name=doc.filename %}">Make Last Call</a>
|
||||
<a href="{% url doc_make_last_call name=doc.name %}">Make Last Call</a>
|
||||
{% endif %}
|
||||
|
||||
</p>
|
||||
|
|
36
ietf/templates/idrfc/ballot_writeupnotesREDESIGN.html
Normal file
36
ietf/templates/idrfc/ballot_writeupnotesREDESIGN.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Ballot writeup and notes for {{ doc }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form #id_ballot_writeup {
|
||||
width: 700px;
|
||||
height: 600px;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Ballot writeup and notes for {{ doc }}</h1>
|
||||
|
||||
|
||||
<form action="" method="POST">
|
||||
|
||||
<p>(Technical Summary, Working Group Summary, Document Quality,
|
||||
Personnel, RFC Editor Note, IRTF Note, IESG Note, IANA Note)</p>
|
||||
|
||||
<p>This text will be appended to all announcements and messages to
|
||||
the IRTF or RFC Editor.</p>
|
||||
|
||||
{{ ballot_writeup_form.ballot_writeup }}
|
||||
|
||||
{% if not approval %}<p style="font-style:italic">Ballot cannot be issued before <a href="{% url doc_ballot_approvaltext name=doc.name %}">announcement text</a> is added.</p>{% endif %}
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{ back_url }}">Back</a>
|
||||
<input type="submit" name="save_ballot_writeup" value="Save Ballot Writeup" />
|
||||
<input style="margin-left: 8px" type="submit" {% if not approval %}disabled="disabled"{% endif %} name="issue_ballot" value="Save and {% if ballot_issued %}Re-{% endif %}Issue Ballot" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
{% endblock%}
|
39
ietf/templates/idrfc/issue_ballot_mailREDESIGN.txt
Normal file
39
ietf/templates/idrfc/issue_ballot_mailREDESIGN.txt
Normal file
|
@ -0,0 +1,39 @@
|
|||
To: Internet Engineering Steering Group <iesg@ietf.org>
|
||||
From: IESG Secretary <iesg-secretary@ietf.org>
|
||||
Reply-To: IESG Secretary <iesg-secretary@ietf.org>
|
||||
Subject: Evaluation: {{ doc.file_tag|safe }} to {{ status }}
|
||||
|
||||
{% filter wordwrap:73 %}Evaluation for {{ doc.file_tag|safe }} can be found at {{ doc_url }}
|
||||
|
||||
{% if last_call_expires %}Last call to expire on: {{ last_call_expires }}
|
||||
|
||||
{% endif %}{% endfilter %}
|
||||
Please return the full line with your position.
|
||||
|
||||
Yes No-Objection Discuss Abstain
|
||||
{% for fmt in active_ad_positions %}{{ fmt|safe }}
|
||||
{% endfor %}{% if inactive_ad_positions %}
|
||||
|
||||
{% for fmt in inactive_ad_positions %}{{ fmt|safe }}
|
||||
{% endfor %}{% endif %}
|
||||
|
||||
"Yes" or "No-Objection" positions from 2/3 of non-recused ADs,
|
||||
with no "Discuss" positions, are needed for approval.
|
||||
|
||||
DISCUSSES AND COMMENTS
|
||||
======================
|
||||
{% filter wordwrap:79 %}{% for pos in ad_feedback %}{{ pos.ad.get_name }}:
|
||||
|
||||
{% if pos.discuss %}Discuss [{{ pos.discuss_time|date:"Y-m-d" }}]:
|
||||
{{ pos.discuss }}
|
||||
|
||||
{% endif %}{% if pos.comment %}Comment [{{ pos.comment_time|date:"Y-m-d" }}]:
|
||||
{{ pos.comment }}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}{% endfilter %}
|
||||
---- following is a DRAFT of message to be sent AFTER approval ---
|
||||
{{ approval_text|safe }}{% if ballot_writeup %}
|
||||
|
||||
{{ ballot_writeup|safe }}
|
||||
{% endif %}
|
|
@ -106,8 +106,8 @@ class InternetDraft(Document):
|
|||
#lc_expiration_date = models.DateField(null=True, blank=True)
|
||||
@property
|
||||
def lc_expiration_date(self):
|
||||
e = self.latest_event(type="sent_last_call")
|
||||
return e.expiration.expires if e else None
|
||||
e = self.latest_event(Expiration, type="sent_last_call")
|
||||
return e.expires if e else None
|
||||
|
||||
#b_sent_date = models.DateField(null=True, blank=True)
|
||||
@property
|
||||
|
@ -171,11 +171,11 @@ class InternetDraft(Document):
|
|||
def calc_process_start_end(self):
|
||||
import datetime
|
||||
start, end = datetime.datetime.min, datetime.datetime.max
|
||||
e = self.ballot.latest_event(type="started_iesg_process")
|
||||
e = self.latest_event(type="started_iesg_process")
|
||||
if e:
|
||||
start = e.time
|
||||
if self.ballot.state_id == "rfc" and self.ballot.name.startswith("draft") and not hasattr(self.ballot, "viewing_as_rfc"):
|
||||
previous_process = self.ballot.latest_event(type="started_iesg_process", time__lt=e.time)
|
||||
if self.state_id == "rfc" and self.name.startswith("draft") and not hasattr(self, "viewing_as_rfc"):
|
||||
previous_process = self.latest_event(type="started_iesg_process", time__lt=e.time)
|
||||
if previous_process:
|
||||
start = previous_process.time
|
||||
end = e.time
|
||||
|
|
Loading…
Reference in a new issue