# Copyright The IETF Trust 2013-2020, All Rights Reserved
# -*- coding: utf-8 -*-
import datetime
import mock
from pyquery import PyQuery
import debug # pyflakes:ignore
from django.test import RequestFactory
from django.utils.text import slugify
from django.urls import reverse as urlreverse
from django.utils import timezone
from ietf.doc.models import (Document, State, DocEvent,
BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, TelechatDocEvent)
from ietf.doc.factories import (DocumentFactory, IndividualDraftFactory, IndividualRfcFactory, WgDraftFactory,
BallotPositionDocEventFactory, BallotDocEventFactory, IRSGBallotDocEventFactory)
from ietf.doc.templatetags.ietf_filters import can_defer
from ietf.doc.utils import create_ballot_if_not_open
from ietf.doc.views_ballot import parse_ballot_edit_return_point
from ietf.doc.views_doc import document_ballot_content
from ietf.group.models import Group, Role
from ietf.group.factories import GroupFactory, RoleFactory, ReviewTeamFactory
from ietf.ipr.factories import HolderIprDisclosureFactory
from ietf.name.models import BallotPositionName
from ietf.iesg.models import TelechatDate
from ietf.person.models import Person, PersonalApiKey
from ietf.person.factories import PersonFactory
from ietf.person.utils import get_active_ads
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
from ietf.utils.mail import outbox, empty_outbox, get_payload_text
from ietf.utils.text import unwrap
from ietf.utils.timezone import date_today, datetime_today
class EditPositionTests(TestCase):
def test_edit_position(self):
ad = Person.objects.get(user__username="ad")
draft = IndividualDraftFactory(ad=ad,stream_id='ietf')
ballot = create_ballot_if_not_open(None, draft, ad, 'approve')
url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=draft.name,
ballot_id=ballot.pk))
login_testing_unauthorized(self, "ad", url)
ad = Person.objects.get(name="Areað Irector")
# normal get
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name=position]')) > 0)
self.assertEqual(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.assertEqual(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(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.assertEqual(draft.docevent_set.count(), events_before + 3)
# recast vote
events_before = draft.docevent_set.count()
r = self.client.post(url, dict(position="noobj"))
self.assertEqual(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(pos.pos.slug, "noobj")
self.assertEqual(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.assertEqual(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(pos.pos.slug, "norecord")
self.assertEqual(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.assertEqual(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(pos.pos.slug, "norecord")
self.assertEqual(draft.docevent_set.count(), events_before + 2)
self.assertTrue("Ballot comment text updated" in pos.desc)
def test_api_set_position(self):
ad = Person.objects.get(name="Areað Irector")
draft = WgDraftFactory(ad=ad)
url = urlreverse('ietf.doc.views_ballot.api_set_position')
create_ballot_if_not_open(None, draft, ad, 'approve')
ad.user.last_login = timezone.now()
ad.user.save()
apikey = PersonalApiKey.objects.create(endpoint=url, person=ad)
# vote
events_before = draft.docevent_set.count()
mailbox_before = len(outbox)
r = self.client.post(url, dict(
apikey=apikey.hash(),
doc=draft.name,
position="discuss",
discuss=" This is a discussion test. \n ",
comment=" This is a test. \n ")
)
self.assertContains(r, "Done")
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(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.assertEqual(draft.docevent_set.count(), events_before + 3)
self.assertEqual(len(outbox), mailbox_before + 1)
# recast vote
events_before = draft.docevent_set.count()
mailbox_before = len(outbox)
r = self.client.post(url, dict(apikey=apikey.hash(), doc=draft.name, position="noobj"))
self.assertEqual(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(pos.pos.slug, "noobj")
self.assertEqual(draft.docevent_set.count(), events_before + 1)
self.assertTrue("Position for" in pos.desc)
self.assertEqual(len(outbox), mailbox_before + 1)
m = outbox[-1]
self.assertIn('No Objection', m['Subject'])
self.assertIn('iesg@', m['To'])
self.assertIn(draft.name, m['Cc'])
self.assertIn(draft.group.acronym+'-chairs@', m['Cc'])
# clear vote
events_before = draft.docevent_set.count()
mailbox_before = len(outbox)
r = self.client.post(url, dict(apikey=apikey.hash(), doc=draft.name, position="norecord"))
self.assertEqual(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(pos.pos.slug, "norecord")
self.assertEqual(draft.docevent_set.count(), events_before + 1)
self.assertTrue("Position for" in pos.desc)
self.assertEqual(len(outbox), mailbox_before + 1)
m = outbox[-1]
self.assertIn('No Record', m['Subject'])
# change comment
events_before = draft.docevent_set.count()
mailbox_before = len(outbox)
r = self.client.post(url, dict(apikey=apikey.hash(), doc=draft.name, position="norecord", comment="New comment."))
self.assertEqual(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(pos.pos.slug, "norecord")
self.assertEqual(draft.docevent_set.count(), events_before + 2)
self.assertTrue("Ballot comment text updated" in pos.desc)
self.assertEqual(len(outbox), mailbox_before + 1)
m = outbox[-1]
self.assertIn('COMMENT', m['Subject'])
self.assertIn('New comment', get_payload_text(m))
def test_edit_position_as_secretary(self):
draft = IndividualDraftFactory()
ad = Person.objects.get(user__username="ad")
ballot = create_ballot_if_not_open(None, draft, ad, 'approve')
url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=draft.name, ballot_id=ballot.pk))
ad = Person.objects.get(name="Areað Irector")
url += "?balloter=%s" % ad.pk
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEqual(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.assertEqual(r.status_code, 302)
pos = draft.latest_event(BallotPositionDocEvent, balloter=ad)
self.assertEqual(pos.pos.slug, "discuss")
self.assertEqual(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 = IndividualDraftFactory()
ad = Person.objects.get(user__username="ad")
ballot = create_ballot_if_not_open(None, draft, ad, 'approve')
url = urlreverse('ietf.doc.views_ballot.edit_position', kwargs=dict(name=draft.name, ballot_id=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.assertEqual(r.status_code, 403)
def test_send_ballot_comment(self):
ad = Person.objects.get(user__username="ad")
draft = WgDraftFactory(ad=ad,group__acronym='mars')
draft.notify = "somebody@example.com"
draft.save_with_history([DocEvent.objects.create(doc=draft, rev=draft.rev, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
ballot = create_ballot_if_not_open(None, draft, ad, 'approve')
BallotPositionDocEvent.objects.create(
doc=draft, rev=draft.rev, type="changed_ballot_position",
by=ad, balloter=ad, ballot=ballot, pos=BallotPositionName.objects.get(slug="discuss"),
discuss="This draft seems to be lacking a clearer title?",
discuss_time=timezone.now(),
comment="Test!",
comment_time=timezone.now())
url = urlreverse('ietf.doc.views_ballot.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.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form input[name="extra_cc"]')) > 0)
# send
mailbox_before = len(outbox)
r = self.client.post(url, dict(extra_cc="test298347@example.com", cc_choices=['doc_notify','doc_group_chairs']))
self.assertEqual(r.status_code, 302)
self.assertEqual(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))
self.assertTrue("iesg@" in m['To'])
# cc_choice doc_group_chairs
self.assertTrue("mars-chairs@" in m['Cc'])
# cc_choice doc_notify
self.assertTrue("somebody@example.com" in m['Cc'])
# cc_choice doc_group_email_list was not selected
self.assertFalse(draft.group.list_email in m['Cc'])
# extra-cc
self.assertTrue("test298347@example.com" in m['Cc'])
r = self.client.post(url, dict(cc=""))
self.assertEqual(r.status_code, 302)
self.assertEqual(len(outbox), mailbox_before + 2)
m = outbox[-1]
self.assertTrue("iesg@" in m['To'])
self.assertFalse(m['Cc'] and draft.group.list_email in m['Cc'])
class BallotWriteupsTests(TestCase):
def test_edit_last_call_text(self):
draft = IndividualDraftFactory(ad=Person.objects.get(user__username='ad'),states=[('draft','active'),('draft-iesg','ad-eval')])
url = urlreverse('ietf.doc.views_ballot.lastcalltext', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('textarea[name=last_call_text]')), 1)
self.assertTrue(q('[type=submit]:contains("Save")'))
# we're Secretariat, so we got The Link
self.assertEqual(len(q('a:contains("Issue 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.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form .is-invalid')) > 0)
# save
r = self.client.post(url, dict(
last_call_text="This is a simple test.",
save_last_call_text="1"))
self.assertEqual(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.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
text = q("[name=last_call_text]").text()
self.assertTrue("Subject: Last Call" in text)
def test_request_last_call(self):
ad = Person.objects.get(user__username="ad")
draft = IndividualDraftFactory(ad=ad,states=[('draft-iesg','iesg-eva')])
url = urlreverse('ietf.doc.views_ballot.lastcalltext', 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.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
text = q("[name=last_call_text]").text()
mailbox_before = len(outbox)
# send
r = self.client.post(url, dict(
last_call_text=text,
send_last_call_request="1"))
draft = Document.objects.get(name=draft.name)
self.assertEqual(draft.get_state_slug("draft-iesg"), "lc-req")
self.assertCountEqual(draft.action_holders.all(), [ad])
self.assertIn('Changed action holders', draft.latest_event(type='changed_action_holders').desc)
self.assertEqual(len(outbox), mailbox_before + 1)
self.assertTrue("Last Call" in outbox[-1]['Subject'])
self.assertTrue(draft.name in outbox[-1]['Subject'])
self.assertTrue('iesg-secretary@' in outbox[-1]['To'])
self.assertTrue('aread@' in outbox[-1]['Cc'])
def test_edit_ballot_writeup(self):
draft = IndividualDraftFactory(states=[('draft','active'),('draft-iesg','iesg-eva')])
url = urlreverse('ietf.doc.views_ballot.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,
rev=draft.rev,
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.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('textarea[name=ballot_writeup]')), 1)
self.assertTrue(q('[type=submit]:contains("Save")'))
self.assertContains(r, "IANA does not")
# save
r = self.client.post(url, dict(
ballot_writeup="This is a simple test.",
save_ballot_writeup="1"))
self.assertEqual(r.status_code, 200)
d = Document.objects.get(name=draft.name)
self.assertTrue("This is a simple test" in d.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text").text)
self.assertTrue('iesg-eva' == d.get_state_slug('draft-iesg'))
def test_edit_ballot_writeup_already_approved(self):
draft = IndividualDraftFactory(states=[('draft','active'),('draft-iesg','approved')])
url = urlreverse('ietf.doc.views_ballot.ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('textarea[name=ballot_writeup]')), 1)
self.assertTrue(q('[type=submit]:contains("Save")'))
# save
r = self.client.post(url, dict(
ballot_writeup="This is a simple test.",
save_ballot_writeup="1"))
self.assertEqual(r.status_code, 200)
d = Document.objects.get(name=draft.name)
self.assertTrue('approved' == d.get_state_slug('draft-iesg'))
def test_edit_ballot_rfceditornote(self):
draft = IndividualDraftFactory()
url = urlreverse('ietf.doc.views_ballot.ballot_rfceditornote', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# add a note to the RFC Editor
WriteupDocEvent.objects.create(
doc=draft,
rev=draft.rev,
desc="Changed text",
type="changed_rfc_editor_note_text",
text="This is a note for the RFC Editor.",
by=Person.objects.get(name="(System)"))
# normal get
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('textarea[name=rfc_editor_note]')), 1)
self.assertTrue(q('[type=submit]:contains("Save")'))
self.assertContains(r, "")
self.assertContains(r, "This is a note for the RFC Editor")
# save with a note
empty_outbox()
r = self.client.post(url, dict(
rfc_editor_note="This is a simple test.",
save_ballot_rfceditornote="1"))
self.assertEqual(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertTrue(draft.has_rfc_editor_note())
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text").text)
self.assertEqual(len(outbox), 0)
# clear the existing note
r = self.client.post(url, dict(
rfc_editor_note=" ",
clear_ballot_rfceditornote="1"))
self.assertEqual(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertFalse(draft.has_rfc_editor_note())
# Add a note after the doc is approved
empty_outbox()
draft.set_state(State.objects.get(type='draft-iesg',slug='approved'))
r = self.client.post(url, dict(
rfc_editor_note='This is a new note.',
save_ballot_rfceditornote="1"))
self.assertEqual(r.status_code, 302)
self.assertEqual(len(outbox),1)
self.assertIn('RFC Editor note changed',outbox[-1]['Subject'])
def test_issue_ballot(self):
ad = Person.objects.get(user__username="ad")
for case in ('none','past','future'):
draft = IndividualDraftFactory(ad=ad)
if case in ('past','future'):
LastCallDocEvent.objects.create(
by=Person.objects.get(name='(System)'),
type='sent_last_call',
doc=draft,
rev=draft.rev,
desc='issued last call',
expires = timezone.now()+datetime.timedelta(days = 1 if case=='future' else -1)
)
url = urlreverse('ietf.doc.views_ballot.ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "ad", url)
empty_outbox()
r = self.client.post(url, dict(
ballot_writeup="This is a test.",
issue_ballot="1"))
self.assertEqual(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertTrue(draft.latest_event(type="sent_ballot_announcement"))
self.assertEqual(len(outbox), 2)
self.assertTrue('Ballot issued:' in outbox[-2]['Subject'])
self.assertTrue('iesg@' in outbox[-2]['To'])
self.assertTrue('Ballot issued:' in outbox[-1]['Subject'])
self.assertTrue('drafts-eval@' in outbox[-1]['To'])
self.assertTrue('X-IETF-Draft-string' in outbox[-1])
if case=='none':
self.assertNotIn('call expire', get_payload_text(outbox[-1]))
elif case=='past':
self.assertIn('call expired', get_payload_text(outbox[-1]))
else:
self.assertIn('call expires', get_payload_text(outbox[-1]))
self.client.logout()
def test_issue_ballot_auto_state_change(self):
ad = Person.objects.get(user__username="ad")
draft = IndividualDraftFactory(ad=ad, states=[('draft','active'),('draft-iesg','writeupw')])
url = urlreverse('ietf.doc.views_ballot.ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('textarea[name=ballot_writeup]')), 1)
self.assertFalse(q('[class=form-text]:contains("not completed IETF Last Call")'))
self.assertTrue(q('[type=submit]:contains("Save")'))
self.assertCountEqual(draft.action_holders.all(), [])
# save
r = self.client.post(url, dict(
ballot_writeup="This is a simple test.",
issue_ballot="1"))
self.assertEqual(r.status_code, 200)
d = Document.objects.get(name=draft.name)
self.assertTrue('iesg-eva' == d.get_state_slug('draft-iesg'))
self.assertCountEqual(draft.action_holders.all(), [ad])
def test_issue_ballot_warn_if_early(self):
ad = Person.objects.get(user__username="ad")
draft = IndividualDraftFactory(ad=ad, states=[('draft','active'),('draft-iesg','lc')])
url = urlreverse('ietf.doc.views_ballot.ballot_writeupnotes', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# expect warning about issuing a ballot before IETF Last Call is done
# No last call has yet been issued
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('textarea[name=ballot_writeup]')), 1)
self.assertTrue(q('[class=text-danger]:contains("not completed IETF Last Call")'))
self.assertTrue(q('[type=submit]:contains("Save")'))
# Last call exists but hasn't expired
LastCallDocEvent.objects.create(
doc=draft,
expires=datetime_today()+datetime.timedelta(days=14),
by=Person.objects.get(name="(System)")
)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('[class=text-danger]:contains("not completed IETF Last Call")'))
# Last call exists and has expired
LastCallDocEvent.objects.filter(doc=draft).update(expires=datetime_today()-datetime.timedelta(days=2))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertFalse(q('[class=text-danger]:contains("not completed IETF Last Call")'))
for state_slug in ["lc", "watching", "ad-eval"]:
draft.set_state(State.objects.get(type="draft-iesg",slug=state_slug))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('[class=text-danger]:contains("It would be unexpected to issue a ballot while in this state.")'))
draft.set_state(State.objects.get(type="draft-iesg",slug="writeupw"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertFalse(q('[class=text-danger]:contains("It would be unexpected to issue a ballot while in this state.")'))
def test_edit_approval_text(self):
ad = Person.objects.get(user__username="ad")
draft = WgDraftFactory(ad=ad,states=[('draft','active'),('draft-iesg','iesg-eva')],intended_std_level_id='ps',group__parent=Group.objects.get(acronym='farfut'))
url = urlreverse('ietf.doc.views_ballot.ballot_approvaltext', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('textarea[name=approval_text]')), 1)
self.assertTrue(q('[type=submit]:contains("Save")'))
# save
r = self.client.post(url, dict(
approval_text="This is a simple test.",
save_approval_text="1"))
self.assertEqual(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.assertEqual(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.assertEqual(r.status_code, 200)
draft = Document.objects.get(name=draft.name)
self.assertIn("NOT be published", unwrap(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.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva"))
draft.save_with_history([DocEvent.objects.create(doc=draft, rev=draft.rev, type="changed_document", by=Person.objects.get(user__username="secretary"), desc="Test")])
r = self.client.post(url, dict(regenerate_approval_text="1"))
self.assertEqual(r.status_code, 200)
self.assertTrue("Subject: Results of IETF-conflict review" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
def test_edit_verify_permissions(self):
def verify_fail(username, url):
if username:
self.client.login(username=username, password=username+"+password")
r = self.client.get(url)
self.assertEqual(r.status_code,403)
def verify_can_see(username, url):
self.client.login(username=username, password=username+"+password")
r = self.client.get(url)
self.assertEqual(r.status_code,200)
q = PyQuery(r.content)
self.assertEqual(len(q("