Skip to content

Commit 87ebddd

Browse files
committed
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
1 parent 1968d7f commit 87ebddd

12 files changed

Lines changed: 101 additions & 79 deletions

File tree

ietf/doc/models.py

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -271,23 +271,9 @@ def active_ballot(self):
271271
open = self.ballot_open(ballot.ballot_type.slug) if ballot else False
272272
return ballot if open else None
273273

274-
def active_ballot_positions(self):
275-
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
276-
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
277-
res = {}
278-
279-
ballot = self.latest_event(BallotDocEvent, type="created_ballot")
280-
positions = BallotPositionDocEvent.objects.filter(doc=self, type="changed_ballot_position", ad__in=active_ads, ballot=ballot).select_related('ad', 'pos').order_by("-time", "-id")
281-
282-
for pos in positions:
283-
if pos.ad not in res:
284-
res[pos.ad] = pos
285-
286-
for ad in active_ads:
287-
if ad not in res:
288-
res[ad] = None
289-
290-
return res
274+
def most_recent_ietflc(self):
275+
"""Returns the most recent IETF LastCallDocEvent for this document"""
276+
return self.latest_event(LastCallDocEvent,type="sent_last_call")
291277

292278
def displayname_with_link(self):
293279
return '<a href="%s">%s-%s</a>' % (self.get_absolute_url(), self.name , self.rev)
@@ -532,6 +518,59 @@ class Meta:
532518
class BallotDocEvent(DocEvent):
533519
ballot_type = models.ForeignKey(BallotType)
534520

521+
def active_ad_positions(self):
522+
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
523+
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
524+
res = {}
525+
526+
if self.doc.latest_event(BallotDocEvent, type="created_ballot") == self:
527+
528+
positions = BallotPositionDocEvent.objects.filter(type="changed_ballot_position",ad__in=active_ads, ballot=self).select_related('ad', 'pos').order_by("-time", "-id")
529+
530+
for pos in positions:
531+
if pos.ad not in res:
532+
res[pos.ad] = pos
533+
534+
for ad in active_ads:
535+
if ad not in res:
536+
res[ad] = None
537+
return res
538+
539+
def all_positions(self):
540+
"""Return array holding the current and past positions per AD"""
541+
542+
positions = []
543+
seen = {}
544+
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active").distinct())
545+
for e in BallotPositionDocEvent.objects.filter(type="changed_ballot_position", ballot=self).select_related('ad', 'pos').order_by("-time", '-id'):
546+
if e.ad not in seen:
547+
e.old_ad = e.ad not in active_ads
548+
e.old_positions = []
549+
positions.append(e)
550+
seen[e.ad] = e
551+
else:
552+
latest = seen[e.ad]
553+
if latest.old_positions:
554+
prev = latest.old_positions[-1]
555+
else:
556+
prev = latest.pos
557+
558+
if e.pos != prev:
559+
latest.old_positions.append(e.pos)
560+
561+
# add any missing ADs through fake No Record events
562+
norecord = BallotPositionName.objects.get(slug="norecord")
563+
for ad in active_ads:
564+
if ad not in seen:
565+
e = BallotPositionDocEvent(type="changed_ballot_position", doc=self.doc, ad=ad)
566+
e.pos = norecord
567+
e.old_ad = False
568+
e.old_positions = []
569+
positions.append(e)
570+
571+
positions.sort(key=lambda p: (p.old_ad, p.ad.last_name()))
572+
return positions
573+
535574
class BallotPositionDocEvent(DocEvent):
536575
ballot = models.ForeignKey(BallotDocEvent, null=True, default=None) # default=None is a temporary migration period fix, should be removed when charter branch is live
537576
ad = models.ForeignKey(Person)

ietf/doc/proxy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ def active_positions(self):
552552
from ietf.person.proxy import IESGLogin as IESGLoginProxy
553553

554554
res = []
555-
for ad, pos in self.active_ballot_positions().iteritems():
555+
for ad, pos in self.active_ballot().active_ad_positions().iteritems():
556556
res.append(dict(ad=IESGLoginProxy().from_object(ad), pos=Position().from_object(pos) if pos else None))
557557

558558
res.sort(key=lambda x: x["ad"].last_name)

ietf/idrfc/templatetags/ballot_icon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def sort_key(t):
8282
else:
8383
return (1, pos.pos.order)
8484

85-
positions = list(doc.active_ballot_positions().items())
85+
positions = list(doc.active_ballot().active_ad_positions().items())
8686
positions.sort(key=sort_key)
8787

8888
cm = ""

ietf/idrfc/templatetags/ballot_icon_redesign.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def sort_key(t):
8989
else:
9090
return (1, pos.pos.order)
9191

92-
positions = list(doc.active_ballot_positions().items())
92+
positions = list(doc.active_ballot().active_ad_positions().items())
9393
positions.sort(key=sort_key)
9494

9595
cm = ""

ietf/idrfc/views_ballot.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
from ietf.message.utils import infer_message
3636
from ietf.person.models import Person
3737

38-
from ietf.doc.utils import log_state_changed
38+
from ietf.doc.utils import log_state_changed as docutil_log_state_changed
39+
from ietf.idrfc.utils import log_state_changed as idrfcutil_log_state_changed
3940

4041
BALLOT_CHOICES = (("yes", "Yes"),
4142
("noobj", "No Objection"),
@@ -431,7 +432,7 @@ def defer_ballotREDESIGN(request, name):
431432
elif doc.type_id == 'conflrev':
432433
doc.set_state(State.objects.get(type='conflrev', slug='defer'))
433434

434-
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
435+
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
435436

436437
doc.time = e.time
437438
doc.save()
@@ -481,7 +482,7 @@ def undefer_ballotREDESIGN(request, name):
481482
elif doc.type_id == 'conflrev':
482483
doc.set_state(State.objects.get(type='conflrev',slug='iesgeval'))
483484

484-
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
485+
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
485486

486487
doc.time = e.time
487488
doc.save()
@@ -557,7 +558,7 @@ def lastcalltext(request, name):
557558
if "send_last_call_request" in request.POST:
558559
doc.idinternal.change_state(IDState.objects.get(document_state_id=IDState.LAST_CALL_REQUESTED), None)
559560

560-
change = log_state_changed(request, doc, login)
561+
change = idrfcutil_log_state_changed(request, doc, login)
561562
email_owner(request, doc, doc.idinternal.job_owner, login, change)
562563
request_last_call(request, doc)
563564

@@ -646,7 +647,7 @@ def lastcalltextREDESIGN(request, name):
646647
if prev_tag:
647648
doc.tags.remove(prev_tag)
648649

649-
e = log_state_changed(request, doc, login, prev, prev_tag)
650+
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
650651

651652
doc.time = e.time
652653
doc.save()
@@ -1093,7 +1094,7 @@ def approve_ballotREDESIGN(request, name):
10931094

10941095
change_description = e.desc + " and state has been changed to %s" % doc.get_state("draft-iesg").name
10951096

1096-
e = log_state_changed(request, doc, login, prev, prev_tag)
1097+
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
10971098

10981099
doc.time = e.time
10991100
doc.save()
@@ -1153,7 +1154,7 @@ def make_last_call(request, name):
11531154
doc.idinternal.event_date = date.today()
11541155
doc.idinternal.save()
11551156

1156-
log_state_changed(request, doc, login)
1157+
idrfcutil_log_state_changed(request, doc, login)
11571158

11581159
doc.lc_sent_date = form.cleaned_data['last_call_sent_date']
11591160
doc.lc_expiration_date = form.cleaned_data['last_call_expiration_date']
@@ -1216,7 +1217,7 @@ def make_last_callREDESIGN(request, name):
12161217
if prev_tag:
12171218
doc.tags.remove(prev_tag)
12181219

1219-
e = log_state_changed(request, doc, login, prev, prev_tag)
1220+
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
12201221

12211222
doc.time = e.time
12221223
doc.save()

ietf/idrfc/views_doc.py

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def document_main(request, name, rev=None):
143143

144144
ballot_summary = None
145145
if doc.get_state_slug() in ("intrev", "iesgrev"):
146-
ballot_summary = needed_ballot_positions(doc, doc.active_ballot_positions().values())
146+
ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_positions().values())
147147

148148
return render_to_response("idrfc/document_charter.html",
149149
dict(doc=doc,
@@ -171,7 +171,7 @@ def document_main(request, name, rev=None):
171171

172172
ballot_summary = None
173173
if doc.get_state_slug() in ("iesgeval"):
174-
ballot_summary = needed_ballot_positions(doc, doc.active_ballot_positions().values())
174+
ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_positions().values())
175175

176176
return render_to_response("idrfc/document_conflict_review.html",
177177
dict(doc=doc,
@@ -292,36 +292,7 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
292292

293293
deferred = doc.active_defer_event()
294294

295-
# collect positions
296-
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active").distinct())
297-
298-
positions = []
299-
seen = {}
300-
for e in BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ballot=ballot).select_related('ad', 'pos').order_by("-time", '-id'):
301-
if e.ad not in seen:
302-
e.old_ad = e.ad not in active_ads
303-
e.old_positions = []
304-
positions.append(e)
305-
seen[e.ad] = e
306-
else:
307-
latest = seen[e.ad]
308-
if latest.old_positions:
309-
prev = latest.old_positions[-1]
310-
else:
311-
prev = latest.pos.name
312-
313-
if e.pos.name != prev:
314-
latest.old_positions.append(e.pos.name)
315-
316-
# add any missing ADs through fake No Record events
317-
norecord = BallotPositionName.objects.get(slug="norecord")
318-
for ad in active_ads:
319-
if ad not in seen:
320-
e = BallotPositionDocEvent(type="changed_ballot_position", doc=doc, ad=ad)
321-
e.pos = norecord
322-
e.old_ad = False
323-
e.old_positions = []
324-
positions.append(e)
295+
positions = doc.active_ballot().all_positions()
325296

326297
# put into position groups
327298
position_groups = []

ietf/idtracker/templatetags/ietf_filters.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@ def square_brackets(value):
146146
else:
147147
return "[ ]"
148148

149+
@register.filter(name='bracketpos')
150+
def bracketpos(pos,posslug):
151+
if pos.pos.slug==posslug:
152+
return "[ X ]"
153+
elif posslug in [x.slug for x in pos.old_positions]:
154+
return "[ . ]"
155+
else:
156+
return "[ ]"
157+
149158
@register.filter(name='fill')
150159
def fill(text, width):
151160
"""Wraps each paragraph in text (a string) so every line

ietf/submit/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ def announce_new_versionREDESIGN(request, submission, draft, state_change_msg):
261261
if draft.ad:
262262
to_email.append(draft.ad.role_email("ad").address)
263263

264-
for ad, pos in draft.active_ballot_positions().iteritems():
264+
for ad, pos in draft.active_ballot().active_ad_positions().iteritems():
265265
if pos and pos.pos_id == "discuss":
266266
to_email.append(ad.role_email("ad").address)
267267

ietf/templates/iesg/moderator_doc.html

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,21 @@ <h3>{{ title1 }}<br>
4040
{{ title2 }}<br>
4141
{{ title3 }} ({{ forloop.counter }} of {{ section_docs|length }})</h3>
4242

43-
<p><b>{{doc.obj.document.filename}}{% if not doc.obj.rfc_flag %}-{{doc.obj.document.revision}}{% endif %}</b><br>
44-
<i>({{ doc.obj.document.title|escape }})</i><br>
45-
<b>Intended status: {{ doc.obj.document.intended_status }}<br>
46-
Token: {{ doc.obj.token_name|escape }}<br>
47-
Last call ends: {{ doc.obj.document.lc_expiration_date|default:"(none)" }}</b></p>
48-
49-
{% if doc.obj.ballot.active %}
50-
{% filter linebreaks_crlf %}<small><pre>
51-
Yes No-Objection Discuss Abstain
52-
{% 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 }}
43+
<p><b>{{doc.obj.name}}-{{doc.obj.rev}}</b><br>
44+
<i>({{ doc.obj.title|escape }})</i><br>
45+
<b>Intended status: {{ doc.obj.intended_std_level }}<br>
46+
Token: {{ doc.obj.ad.plain_name|escape }}<br>
47+
{% if doc.obj.type.slug == "draft" %}
48+
Last call ends: {{ doc.obj.most_recent_ietflc.expires.date|default:"(none)" }}
49+
{% if doc.obj.most_recent_ietflc.expires.date|timesince_days < 3 %}!!!{% endif %}
50+
{% endif %}</b></p>
51+
52+
{% if doc.obj.active_ballot %}
53+
<small><pre>
54+
Yes No-Objection Discuss Abstain Recuse
55+
{% 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"}}
5356
{% endfor %}
54-
{% 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 }}
55-
{% endif %}{% endfor %}</pre></small>{% endfilter %}
57+
</pre></small>
5658

5759
{% if title1|startswith:"2." %}
5860
<p>____ open positions<br>
@@ -67,16 +69,16 @@ <h3>{{ title1 }}<br>
6769
{% endif %}
6870

6971
{% if title2|startswith:"3.1" or title2|startswith:"3.2" %}
70-
<p>Does anyone have an[y further] objection to this document being published as an {{ doc.obj.document.intended_status }} RFC?</p>
72+
<p>Does anyone have an[y further] objection to this document being published as an {{ doc.obj.intended_std_level }} RFC?</p>
7173
{% endif %}
7274
{% if title3|startswith:"3.3.1" or title3|startswith:"3.3.2" %}
73-
<p>Does anyone have an objection to the RFC Editor publishing this document as an {{ doc.obj.document.intended_status }} RFC?</p>
75+
<p>Does anyone have an objection to the RFC Editor publishing this document as an {{ doc.obj.intended_std_level }} RFC?</p>
7476
{% endif %}
7577
{% if title3|startswith:"3.3.3" %}
7678
<p>Who will do the review of this document?</p>
7779
{% endif %}
7880

79-
<p>Current State: {{ doc.obj.cur_state }}, sub state: {{ doc.obj.cur_sub_state|default:"(none)" }}<br>
81+
<p>Current State: {{ doc.obj.friendly_state }}<br>
8082
Next State:<br>
8183
Sub State: </p>
8284

ietf/templates/iesg/moderator_package.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ <h3>1. Administrivia<br>1.3 Approval of the Minutes of Past Telechats</h3>
8585
{{ minutes }}
8686
</pre>{% endfilter %}
8787

88-
<h3>1. Administrivia<br>1.4 List of Remaining Action Items from Last Telehat</h3>
88+
<h3>1. Administrivia<br>1.4 List of Remaining Action Items from Last Telechat</h3>
8989

9090
{% filter linebreaks_crlf %}<pre>
9191
{{ action_items }}

0 commit comments

Comments
 (0)