Removed some duplication between doc/util and doc/models by moving things into doc/models. Fixes bug #857

- Legacy-Id: 4750
This commit is contained in:
Robert Sparks 2012-08-02 21:36:36 +00:00
parent ada1e4eb56
commit fb2b9c9e6c
11 changed files with 26 additions and 56 deletions

View file

@ -259,11 +259,17 @@ class Document(DocumentInfo):
return self.latest_event(type="changed_document", desc__startswith="State changed to <b>IESG Evaluation - Defer</b>")
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 '<a href="%s">%s-%s</a>' % (self.get_absolute_url(), self.name , self.rev)

View file

@ -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)

View file

@ -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'])

View file

@ -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

View file

@ -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 = ""

View file

@ -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)

View file

@ -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,

View file

@ -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)

View file

@ -65,7 +65,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
{% if doc.obj.active_ballot %}
<br/><b>Discusses/comments</b> <a href="http://datatracker.ietf.org/idtracker/ballot/{{doc.obj.canonical_name}}/">[ballot]</a>:
<ul>
{% for p in doc.obj.active_ballot_positions %}
{% for p in doc.obj.active_ballot_positions.values %}
{% if p.pos %}
{% if p.discuss %}
<li>

View file

@ -40,7 +40,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
{% if doc.obj.active_ballot %}
<ul>
{% for p in doc.obj.active_ballot_positions %}
{% for p in doc.obj.active_ballot_positions.values %}
{% if p.pos and p.discuss %}
<li>
<a name="{{doc.obj.name}}+{{p.ad|slugify}}+discuss">{{ p.ad }}: Discuss [{{ p.discuss_time }}]</a>:

View file

@ -224,7 +224,7 @@ class CharterApproveBallotTestCase(django.test.TestCase):
charter = Document.objects.get(name=charter.name)
self.assertEquals(charter.get_state_slug(), "approved")
self.assertTrue(not ballot_open(charter, "approve"))
self.assertTrue(not charter.ballot_open("approve"))
self.assertEquals(charter.rev, "01")
self.assertTrue(os.path.exists(os.path.join(self.charter_dir, "charter-ietf-%s-%s.txt" % (group.acronym, charter.rev))))