diff --git a/ietf/doc/models.py b/ietf/doc/models.py
index c42b54c3f..7f65b78cc 100644
--- a/ietf/doc/models.py
+++ b/ietf/doc/models.py
@@ -259,11 +259,17 @@ class Document(DocumentInfo):
return self.latest_event(type="changed_document", desc__startswith="State changed to IESG Evaluation - Defer")
return None
+# This, and several other ballot related functions here, assume that there is only one active ballot for a document at any point in time.
+# If that assumption is violated, they will only expose the most recently created ballot
+ def ballot_open(self, ballot_type_slug):
+ e = self.latest_event(BallotDocEvent, ballot_type__slug=ballot_type_slug)
+ return e and not e.type == "closed_ballot"
+
def active_ballot(self):
+ """Returns the most recently created ballot if it isn't closed."""
ballot = self.latest_event(BallotDocEvent, type="created_ballot")
- e = self.latest_event(BallotDocEvent, ballot_type__slug=ballot.ballot_type.slug) if ballot else None
- open = e and not e.type == "closed_ballot"
- return ballot.ballot_type if open else None
+ open = self.ballot_open(ballot.ballot_type.slug) if ballot else False
+ return ballot if open else None
def active_ballot_positions(self):
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
@@ -281,7 +287,7 @@ class Document(DocumentInfo):
if ad not in res:
res[ad] = None
- return res.values()
+ return res
def displayname_with_link(self):
return '%s-%s' % (self.get_absolute_url(), self.name , self.rev)
diff --git a/ietf/doc/proxy.py b/ietf/doc/proxy.py
index c234b6167..6e7cdcbbc 100644
--- a/ietf/doc/proxy.py
+++ b/ietf/doc/proxy.py
@@ -550,10 +550,9 @@ class InternetDraft(Document):
def active_positions(self):
"""Returns a list of dicts, with AD and Position tuples"""
from ietf.person.proxy import IESGLogin as IESGLoginProxy
- from ietf.doc.utils import active_ballot_positions
res = []
- for ad, pos in active_ballot_positions(self).iteritems():
+ for ad, pos in self.active_ballot_positions().iteritems():
res.append(dict(ad=IESGLoginProxy().from_object(ad), pos=Position().from_object(pos) if pos else None))
res.sort(key=lambda x: x["ad"].last_name)
diff --git a/ietf/doc/tests_conflict_review.py b/ietf/doc/tests_conflict_review.py
index 9172f8c47..7c3e2925c 100644
--- a/ietf/doc/tests_conflict_review.py
+++ b/ietf/doc/tests_conflict_review.py
@@ -13,7 +13,7 @@ from django.core.urlresolvers import reverse as urlreverse
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.utils.test_data import make_test_data
from ietf.utils.mail import outbox
-from ietf.doc.utils import active_ballot, create_ballot_if_not_open, ballot_open
+from ietf.doc.utils import create_ballot_if_not_open
from ietf.doc.views_conflict_review import default_approval_text
from ietf.doc.models import Document,DocEvent,NewRevisionDocEvent,BallotPositionDocEvent,TelechatDocEvent,DocAlias,State
@@ -105,7 +105,7 @@ class ConflictReviewTestCase(django.test.TestCase):
review_doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
self.assertEquals(review_doc.get_state('conflrev').slug,'adrev')
self.assertTrue(review_doc.latest_event(DocEvent,type="added_comment").desc.startswith('RDNK84ZD'))
- self.assertFalse(active_ballot(review_doc))
+ self.assertFalse(review_doc.active_ballot())
# successful change to IESG Evaluation
iesgeval_pk = str(State.objects.get(slug='iesgeval',type__slug='conflrev').pk)
@@ -114,7 +114,7 @@ class ConflictReviewTestCase(django.test.TestCase):
review_doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
self.assertEquals(review_doc.get_state('conflrev').slug,'iesgeval')
self.assertTrue(review_doc.latest_event(DocEvent,type="added_comment").desc.startswith('TGmZtEjt'))
- self.assertTrue(active_ballot(review_doc))
+ self.assertTrue(review_doc.active_ballot())
self.assertEquals(review_doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position").pos_id,'yes')
@@ -234,7 +234,7 @@ class ConflictReviewTestCase(django.test.TestCase):
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
self.assertEquals(doc.get_state_slug(),approve_type+'-sent')
- self.assertFalse(ballot_open(doc, "conflrev"))
+ self.assertFalse(doc.ballot_open("conflrev"))
self.assertEquals(len(outbox), messages_before + 1)
self.assertTrue('Results of IETF-conflict review' in outbox[-1]['Subject'])
diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py
index 43a3fb78d..74656a981 100644
--- a/ietf/doc/utils.py
+++ b/ietf/doc/utils.py
@@ -36,34 +36,6 @@ def get_tags_for_stream_id(stream_id):
else:
return []
-# This, and several other utilities here, assume that there is only one active ballot for a document at any point in time.
-# If that assumption is violated, they will only expose the most recently created ballot
-def active_ballot(doc):
- """Returns the most recently created ballot if it isn't closed."""
- ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
- open = ballot_open(doc,ballot.ballot_type.slug) if ballot else False
- return ballot if open else None
-
-
-def active_ballot_positions(doc, ballot=None):
- """Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
- active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
- res = {}
-
- if not ballot:
- ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
- positions = BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ad__in=active_ads, ballot=ballot).select_related('ad', 'pos').order_by("-time", "-id")
-
- for pos in positions:
- if pos.ad not in res:
- res[pos.ad] = pos
-
- for ad in active_ads:
- if ad not in res:
- res[ad] = None
-
- return res
-
def needed_ballot_positions(doc, active_positions):
'''Returns text answering the question "what does this document
need to pass?". The return value is only useful if the document
@@ -102,12 +74,8 @@ def needed_ballot_positions(doc, active_positions):
return " ".join(answer)
-def ballot_open(doc, ballot_type_slug):
- e = doc.latest_event(BallotDocEvent, ballot_type__slug=ballot_type_slug)
- return e and not e.type == "closed_ballot"
-
def create_ballot_if_not_open(doc, by, ballot_type_slug):
- if not ballot_open(doc, ballot_type_slug):
+ if not doc.ballot_open(ballot_type_slug):
e = BallotDocEvent(type="created_ballot", by=by, doc=doc)
e.ballot_type = BallotType.objects.get(doc_type=doc.type, slug=ballot_type_slug)
e.desc = u'Created "%s" ballot' % e.ballot_type.name
@@ -115,7 +83,7 @@ def create_ballot_if_not_open(doc, by, ballot_type_slug):
def close_open_ballots(doc, by):
for t in BallotType.objects.filter(doc_type=doc.type_id):
- if ballot_open(doc, t.slug):
+ if doc.ballot_open(t.slug):
e = BallotDocEvent(type="closed_ballot", doc=doc, by=by)
e.ballot_type = t
e.desc = 'Closed "%s" ballot' % t.name
diff --git a/ietf/idrfc/templatetags/ballot_icon.py b/ietf/idrfc/templatetags/ballot_icon.py
index 8f72d54c4..0f797e20a 100644
--- a/ietf/idrfc/templatetags/ballot_icon.py
+++ b/ietf/idrfc/templatetags/ballot_icon.py
@@ -37,7 +37,6 @@ 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.utils import active_ballot_positions
from ietf.doc.models import BallotDocEvent
register = template.Library()
@@ -83,7 +82,7 @@ def render_ballot_icon(user, doc):
else:
return (1, pos.pos.order)
- positions = list(active_ballot_positions(doc, ballot).items())
+ positions = list(doc.active_ballot_positions().items())
positions.sort(key=sort_key)
cm = ""
diff --git a/ietf/idrfc/templatetags/ballot_icon_redesign.py b/ietf/idrfc/templatetags/ballot_icon_redesign.py
index 0cecb6c90..cfbbd2776 100644
--- a/ietf/idrfc/templatetags/ballot_icon_redesign.py
+++ b/ietf/idrfc/templatetags/ballot_icon_redesign.py
@@ -38,7 +38,6 @@ 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.utils import active_ballot_positions, active_ballot
from ietf.doc.models import BallotDocEvent, BallotPositionDocEvent
from datetime import date
@@ -90,7 +89,7 @@ def render_ballot_icon(user, doc):
else:
return (1, pos.pos.order)
- positions = list(active_ballot_positions(doc, ballot).items())
+ positions = list(doc.active_ballot_positions().items())
positions.sort(key=sort_key)
cm = ""
@@ -144,7 +143,7 @@ def my_position(doc, user):
return None
if not in_group(user, "Area_Director"):
return None
- ballot = active_ballot(doc)
+ ballot = doc.active_ballot()
pos = "No Record"
if ballot:
changed_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad__name=user_name, ballot=ballot)
diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py
index 32c4effa4..da4b50e7e 100644
--- a/ietf/idrfc/views_doc.py
+++ b/ietf/idrfc/views_doc.py
@@ -143,7 +143,7 @@ def document_main(request, name, rev=None):
ballot_summary = None
if doc.get_state_slug() in ("intrev", "iesgrev"):
- ballot_summary = needed_ballot_positions(doc, active_ballot_positions(doc).values())
+ ballot_summary = needed_ballot_positions(doc, doc.active_ballot_positions().values())
return render_to_response("idrfc/document_charter.html",
dict(doc=doc,
@@ -171,7 +171,7 @@ def document_main(request, name, rev=None):
ballot_summary = None
if doc.get_state_slug() in ("iesgeval"):
- ballot_summary = needed_ballot_positions(doc, active_ballot_positions(doc).values())
+ ballot_summary = needed_ballot_positions(doc, doc.active_ballot_positions().values())
return render_to_response("idrfc/document_conflict_review.html",
dict(doc=doc,
diff --git a/ietf/submit/utils.py b/ietf/submit/utils.py
index ca4b09623..479eef528 100644
--- a/ietf/submit/utils.py
+++ b/ietf/submit/utils.py
@@ -17,7 +17,6 @@ from ietf.ietfauth.decorators import has_role
from ietf.doc.models import *
from ietf.person.models import Person, Alias, Email
-from ietf.doc.utils import active_ballot_positions
from ietf.message.models import Message
# Some useful states
@@ -262,7 +261,7 @@ def announce_new_versionREDESIGN(request, submission, draft, state_change_msg):
if draft.ad:
to_email.append(draft.ad.role_email("ad").address)
- for ad, pos in active_ballot_positions(draft).iteritems():
+ for ad, pos in draft.active_ballot_positions().iteritems():
if pos and pos.pos_id == "discuss":
to_email.append(ad.role_email("ad").address)
diff --git a/ietf/templates/iesg/scribe_doc.html b/ietf/templates/iesg/scribe_doc.html
index 9ef60865a..75617579b 100644
--- a/ietf/templates/iesg/scribe_doc.html
+++ b/ietf/templates/iesg/scribe_doc.html
@@ -65,7 +65,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
{% if doc.obj.active_ballot %}
Discusses/comments [ballot]: