Simplified access to current BallotDocevent from a Document.
Added functions to BallotDocEvents to faciliate access to BallotPositionDocEvents, both for all positions, and current AD postions. Updated the moderator package to use the Documents from _agenda_data. Added a filter to assist with rendering the moderator package. Fixed a bug where different functions in idrfc/views_ballot were using log_state_changed expecting different implementations (a cleanup task should reconcile the _three_ implementations in the codebase of that function). - Legacy-Id: 4768
This commit is contained in:
parent
1968d7f150
commit
87ebddd0ba
|
@ -271,23 +271,9 @@ class Document(DocumentInfo):
|
|||
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)."""
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
|
||||
res = {}
|
||||
|
||||
ballot = self.latest_event(BallotDocEvent, type="created_ballot")
|
||||
positions = BallotPositionDocEvent.objects.filter(doc=self, 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 most_recent_ietflc(self):
|
||||
"""Returns the most recent IETF LastCallDocEvent for this document"""
|
||||
return self.latest_event(LastCallDocEvent,type="sent_last_call")
|
||||
|
||||
def displayname_with_link(self):
|
||||
return '<a href="%s">%s-%s</a>' % (self.get_absolute_url(), self.name , self.rev)
|
||||
|
@ -532,6 +518,59 @@ class BallotType(models.Model):
|
|||
class BallotDocEvent(DocEvent):
|
||||
ballot_type = models.ForeignKey(BallotType)
|
||||
|
||||
def active_ad_positions(self):
|
||||
"""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 self.doc.latest_event(BallotDocEvent, type="created_ballot") == self:
|
||||
|
||||
positions = BallotPositionDocEvent.objects.filter(type="changed_ballot_position",ad__in=active_ads, ballot=self).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 all_positions(self):
|
||||
"""Return array holding the current and past positions per AD"""
|
||||
|
||||
positions = []
|
||||
seen = {}
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active").distinct())
|
||||
for e in BallotPositionDocEvent.objects.filter(type="changed_ballot_position", ballot=self).select_related('ad', 'pos').order_by("-time", '-id'):
|
||||
if e.ad not in seen:
|
||||
e.old_ad = e.ad not in active_ads
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
seen[e.ad] = e
|
||||
else:
|
||||
latest = seen[e.ad]
|
||||
if latest.old_positions:
|
||||
prev = latest.old_positions[-1]
|
||||
else:
|
||||
prev = latest.pos
|
||||
|
||||
if e.pos != prev:
|
||||
latest.old_positions.append(e.pos)
|
||||
|
||||
# add any missing ADs through fake No Record events
|
||||
norecord = BallotPositionName.objects.get(slug="norecord")
|
||||
for ad in active_ads:
|
||||
if ad not in seen:
|
||||
e = BallotPositionDocEvent(type="changed_ballot_position", doc=self.doc, ad=ad)
|
||||
e.pos = norecord
|
||||
e.old_ad = False
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
|
||||
positions.sort(key=lambda p: (p.old_ad, p.ad.last_name()))
|
||||
return positions
|
||||
|
||||
class BallotPositionDocEvent(DocEvent):
|
||||
ballot = models.ForeignKey(BallotDocEvent, null=True, default=None) # default=None is a temporary migration period fix, should be removed when charter branch is live
|
||||
ad = models.ForeignKey(Person)
|
||||
|
|
|
@ -552,7 +552,7 @@ class InternetDraft(Document):
|
|||
from ietf.person.proxy import IESGLogin as IESGLoginProxy
|
||||
|
||||
res = []
|
||||
for ad, pos in self.active_ballot_positions().iteritems():
|
||||
for ad, pos in self.active_ballot().active_ad_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)
|
||||
|
|
|
@ -82,7 +82,7 @@ def render_ballot_icon(user, doc):
|
|||
else:
|
||||
return (1, pos.pos.order)
|
||||
|
||||
positions = list(doc.active_ballot_positions().items())
|
||||
positions = list(doc.active_ballot().active_ad_positions().items())
|
||||
positions.sort(key=sort_key)
|
||||
|
||||
cm = ""
|
||||
|
|
|
@ -89,7 +89,7 @@ def render_ballot_icon(user, doc):
|
|||
else:
|
||||
return (1, pos.pos.order)
|
||||
|
||||
positions = list(doc.active_ballot_positions().items())
|
||||
positions = list(doc.active_ballot().active_ad_positions().items())
|
||||
positions.sort(key=sort_key)
|
||||
|
||||
cm = ""
|
||||
|
|
|
@ -35,7 +35,8 @@ from ietf.name.models import BallotPositionName
|
|||
from ietf.message.utils import infer_message
|
||||
from ietf.person.models import Person
|
||||
|
||||
from ietf.doc.utils import log_state_changed
|
||||
from ietf.doc.utils import log_state_changed as docutil_log_state_changed
|
||||
from ietf.idrfc.utils import log_state_changed as idrfcutil_log_state_changed
|
||||
|
||||
BALLOT_CHOICES = (("yes", "Yes"),
|
||||
("noobj", "No Objection"),
|
||||
|
@ -431,7 +432,7 @@ def defer_ballotREDESIGN(request, name):
|
|||
elif doc.type_id == 'conflrev':
|
||||
doc.set_state(State.objects.get(type='conflrev', slug='defer'))
|
||||
|
||||
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -481,7 +482,7 @@ def undefer_ballotREDESIGN(request, name):
|
|||
elif doc.type_id == 'conflrev':
|
||||
doc.set_state(State.objects.get(type='conflrev',slug='iesgeval'))
|
||||
|
||||
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -557,7 +558,7 @@ def lastcalltext(request, name):
|
|||
if "send_last_call_request" in request.POST:
|
||||
doc.idinternal.change_state(IDState.objects.get(document_state_id=IDState.LAST_CALL_REQUESTED), None)
|
||||
|
||||
change = log_state_changed(request, doc, login)
|
||||
change = idrfcutil_log_state_changed(request, doc, login)
|
||||
email_owner(request, doc, doc.idinternal.job_owner, login, change)
|
||||
request_last_call(request, doc)
|
||||
|
||||
|
@ -646,7 +647,7 @@ def lastcalltextREDESIGN(request, name):
|
|||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
||||
e = log_state_changed(request, doc, login, prev, prev_tag)
|
||||
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -1093,7 +1094,7 @@ def approve_ballotREDESIGN(request, name):
|
|||
|
||||
change_description = e.desc + " and state has been changed to %s" % doc.get_state("draft-iesg").name
|
||||
|
||||
e = log_state_changed(request, doc, login, prev, prev_tag)
|
||||
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -1153,7 +1154,7 @@ def make_last_call(request, name):
|
|||
doc.idinternal.event_date = date.today()
|
||||
doc.idinternal.save()
|
||||
|
||||
log_state_changed(request, doc, login)
|
||||
idrfcutil_log_state_changed(request, doc, login)
|
||||
|
||||
doc.lc_sent_date = form.cleaned_data['last_call_sent_date']
|
||||
doc.lc_expiration_date = form.cleaned_data['last_call_expiration_date']
|
||||
|
@ -1216,7 +1217,7 @@ def make_last_callREDESIGN(request, name):
|
|||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
||||
e = log_state_changed(request, doc, login, prev, prev_tag)
|
||||
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
|
|
@ -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, doc.active_ballot_positions().values())
|
||||
ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_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, doc.active_ballot_positions().values())
|
||||
ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_positions().values())
|
||||
|
||||
return render_to_response("idrfc/document_conflict_review.html",
|
||||
dict(doc=doc,
|
||||
|
@ -292,36 +292,7 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
|
|||
|
||||
deferred = doc.active_defer_event()
|
||||
|
||||
# collect positions
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active").distinct())
|
||||
|
||||
positions = []
|
||||
seen = {}
|
||||
for e in BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ballot=ballot).select_related('ad', 'pos').order_by("-time", '-id'):
|
||||
if e.ad not in seen:
|
||||
e.old_ad = e.ad not in active_ads
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
seen[e.ad] = e
|
||||
else:
|
||||
latest = seen[e.ad]
|
||||
if latest.old_positions:
|
||||
prev = latest.old_positions[-1]
|
||||
else:
|
||||
prev = latest.pos.name
|
||||
|
||||
if e.pos.name != prev:
|
||||
latest.old_positions.append(e.pos.name)
|
||||
|
||||
# add any missing ADs through fake No Record events
|
||||
norecord = BallotPositionName.objects.get(slug="norecord")
|
||||
for ad in active_ads:
|
||||
if ad not in seen:
|
||||
e = BallotPositionDocEvent(type="changed_ballot_position", doc=doc, ad=ad)
|
||||
e.pos = norecord
|
||||
e.old_ad = False
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
positions = doc.active_ballot().all_positions()
|
||||
|
||||
# put into position groups
|
||||
position_groups = []
|
||||
|
|
|
@ -146,6 +146,15 @@ def square_brackets(value):
|
|||
else:
|
||||
return "[ ]"
|
||||
|
||||
@register.filter(name='bracketpos')
|
||||
def bracketpos(pos,posslug):
|
||||
if pos.pos.slug==posslug:
|
||||
return "[ X ]"
|
||||
elif posslug in [x.slug for x in pos.old_positions]:
|
||||
return "[ . ]"
|
||||
else:
|
||||
return "[ ]"
|
||||
|
||||
@register.filter(name='fill')
|
||||
def fill(text, width):
|
||||
"""Wraps each paragraph in text (a string) so every line
|
||||
|
|
|
@ -261,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 draft.active_ballot_positions().iteritems():
|
||||
for ad, pos in draft.active_ballot().active_ad_positions().iteritems():
|
||||
if pos and pos.pos_id == "discuss":
|
||||
to_email.append(ad.role_email("ad").address)
|
||||
|
||||
|
|
|
@ -40,19 +40,21 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
|
|||
{{ title2 }}<br>
|
||||
{{ title3 }} ({{ forloop.counter }} of {{ section_docs|length }})</h3>
|
||||
|
||||
<p><b>{{doc.obj.document.filename}}{% if not doc.obj.rfc_flag %}-{{doc.obj.document.revision}}{% endif %}</b><br>
|
||||
<i>({{ doc.obj.document.title|escape }})</i><br>
|
||||
<b>Intended status: {{ doc.obj.document.intended_status }}<br>
|
||||
Token: {{ doc.obj.token_name|escape }}<br>
|
||||
Last call ends: {{ doc.obj.document.lc_expiration_date|default:"(none)" }}</b></p>
|
||||
<p><b>{{doc.obj.name}}-{{doc.obj.rev}}</b><br>
|
||||
<i>({{ doc.obj.title|escape }})</i><br>
|
||||
<b>Intended status: {{ doc.obj.intended_std_level }}<br>
|
||||
Token: {{ doc.obj.ad.plain_name|escape }}<br>
|
||||
{% if doc.obj.type.slug == "draft" %}
|
||||
Last call ends: {{ doc.obj.most_recent_ietflc.expires.date|default:"(none)" }}
|
||||
{% if doc.obj.most_recent_ietflc.expires.date|timesince_days < 3 %}!!!{% endif %}
|
||||
{% endif %}</b></p>
|
||||
|
||||
{% if doc.obj.ballot.active %}
|
||||
{% filter linebreaks_crlf %}<small><pre>
|
||||
Yes No-Objection Discuss Abstain
|
||||
{% for curpos in doc.obj.ballot.active_positions %}{{ curpos.ad|ljust:"20" }} {{ curpos.pos.yes|bracket }} {{ curpos.pos.noobj|bracket }} {{ curpos.pos.discuss|bracket }} {{ curpos.pos.abstain_ind|bracket }}
|
||||
{% if doc.obj.active_ballot %}
|
||||
<small><pre>
|
||||
Yes No-Objection Discuss Abstain Recuse
|
||||
{% for pos in doc.obj.active_ballot.all_positions %}{% if pos.old_ad %}{{pos.ad.plain_name|bracket|ljust:"22"}}{%else%}{{pos.ad.plain_name|ljust:"22"}}{%endif%} {{pos|bracketpos:"yes"}} {{pos|bracketpos:"noobj"}} {{pos|bracketpos:"discuss"}} {{pos|bracketpos:"abstain"}} {{pos|bracketpos:"recuse"}}
|
||||
{% endfor %}
|
||||
{% for position in doc.obj.ballot.positions.all|dictsort:"ad.last_name" %}{% if not position.ad.is_current_ad %}{{ position.ad|ljust:"20" }} {{ position.yes|bracket }} {{ position.noobj|bracket }} {{ position.discuss|bracket }} {{ position.abstain_ind|bracket }}
|
||||
{% endif %}{% endfor %}</pre></small>{% endfilter %}
|
||||
</pre></small>
|
||||
|
||||
{% if title1|startswith:"2." %}
|
||||
<p>____ open positions<br>
|
||||
|
@ -67,16 +69,16 @@ Last call ends: {{ doc.obj.document.lc_expiration_date|default:"(none)" }}</b></
|
|||
{% endif %}
|
||||
|
||||
{% if title2|startswith:"3.1" or title2|startswith:"3.2" %}
|
||||
<p>Does anyone have an[y further] objection to this document being published as an {{ doc.obj.document.intended_status }} RFC?</p>
|
||||
<p>Does anyone have an[y further] objection to this document being published as an {{ doc.obj.intended_std_level }} RFC?</p>
|
||||
{% endif %}
|
||||
{% if title3|startswith:"3.3.1" or title3|startswith:"3.3.2" %}
|
||||
<p>Does anyone have an objection to the RFC Editor publishing this document as an {{ doc.obj.document.intended_status }} RFC?</p>
|
||||
<p>Does anyone have an objection to the RFC Editor publishing this document as an {{ doc.obj.intended_std_level }} RFC?</p>
|
||||
{% endif %}
|
||||
{% if title3|startswith:"3.3.3" %}
|
||||
<p>Who will do the review of this document?</p>
|
||||
{% endif %}
|
||||
|
||||
<p>Current State: {{ doc.obj.cur_state }}, sub state: {{ doc.obj.cur_sub_state|default:"(none)" }}<br>
|
||||
<p>Current State: {{ doc.obj.friendly_state }}<br>
|
||||
Next State:<br>
|
||||
Sub State: </p>
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ teleconference. The Secretariat will post them in the public archive.</p>
|
|||
{{ minutes }}
|
||||
</pre>{% endfilter %}
|
||||
|
||||
<h3>1. Administrivia<br>1.4 List of Remaining Action Items from Last Telehat</h3>
|
||||
<h3>1. Administrivia<br>1.4 List of Remaining Action Items from Last Telechat</h3>
|
||||
|
||||
{% filter linebreaks_crlf %}<pre>
|
||||
{{ action_items }}
|
||||
|
|
|
@ -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.values %}
|
||||
{% for p in doc.obj.active_ballot.active_ad_positions.values %}
|
||||
{% if p.pos %}
|
||||
{% if p.discuss %}
|
||||
<li>
|
||||
|
|
|
@ -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.values %}
|
||||
{% for p in doc.obj.active_ballot.active_ad_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>:
|
||||
|
|
Loading…
Reference in a new issue