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]: