Skip to content

Commit b5ce6e3

Browse files
committed
Extensive updates of idtracker.
ballot sets are now (hopefully) treated properly, except for the row coloring. They're also included in the "view_id" view. Search is re-done, it turns out that using draft__<anything> means that RFCs won't be matched, so build lists of possibly-matching RFCs and I-Ds and pass them through. This applies to filename, group and rfc number. - Legacy-Id: 190
1 parent 0f64cde commit b5ce6e3

8 files changed

Lines changed: 160 additions & 133 deletions

File tree

ietf/idtracker/models.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,7 @@ def __str__(self):
156156
def idstate(self):
157157
idinternal = self.idinternal
158158
if idinternal:
159-
if idinternal.cur_sub_state:
160-
return "%s :: %s" % ( idinternal.cur_state, idinternal.cur_sub_state )
161-
else:
162-
return idinternal.cur_state
159+
return idinternal.docstate()
163160
else:
164161
return "I-D Exists"
165162
def revision_display(self):
@@ -200,13 +197,7 @@ def save(self):
200197
super(PersonOrOrgInfo, self).save()
201198
def __str__(self):
202199
if self.first_name == '' and self.last_name == '':
203-
try:
204-
postal = self.postaladdress_set.get(address_priority=1)
205-
except PostalAddress.DoesNotExist:
206-
return "PersonOrOrgInfo with no name, no postal address!"
207-
except AssertionError:
208-
return "PersonOrOrgInfo with multiple priority-1 addresses!"
209-
return "%s" % ( postal.affiliated_company or postal.department or "???" )
200+
return self.affiliation()
210201
return "%s %s" % ( self.first_name or "<nofirst>", self.last_name or "<nolast>")
211202
def email(self, priority=1, type='INET'):
212203
name = str(self)
@@ -216,13 +207,13 @@ def email(self, priority=1, type='INET'):
216207
email = ''
217208
return (name, email)
218209
# Added by Sunny Lee to display person's affiliation - 5/26/2007
219-
def affiliation(self, priority=1, type='INET'):
210+
def affiliation(self, priority=1):
220211
try:
221-
postal = self.postaladdress_set.get(address_priority=1)
212+
postal = self.postaladdress_set.get(address_priority=priority)
222213
except PostalAddress.DoesNotExist:
223-
return "PersonOrOrgInfo with no name, no postal address!"
214+
return "PersonOrOrgInfo with no postal address!"
224215
except AssertionError:
225-
return "PersonOrOrgInfo with multiple priority-1 addresses!"
216+
return "PersonOrOrgInfo with multiple priority-%d addresses!" % priority
226217
return "%s" % ( postal.affiliated_company or postal.department or "???" )
227218
class Meta:
228219
db_table = 'person_or_org_info'
@@ -331,7 +322,11 @@ def save(self):
331322
self.rfc_name_key = self.title.upper()
332323
super(Rfc, self).save()
333324
def displayname(self):
334-
return "rfc%d.txt" % ( self.rfc_number )
325+
return "%s.txt" % ( self.filename() )
326+
def filename(self):
327+
return "rfc%d" % ( self.rfc_number )
328+
def revision(self):
329+
return "RFC"
335330
def doclink(self):
336331
return "http://www.ietf.org/rfc/%s" % ( self.displayname() )
337332
class Meta:
@@ -405,6 +400,10 @@ class IDInternal(models.Model):
405400
field is defined as a FK to InternetDrafts. One side effect
406401
of this is that select_related() will only work with
407402
rfc_flag=0.
403+
404+
When searching where matches may be either I-Ds or RFCs,
405+
you cannot use draft__ as that will cause an INNER JOIN
406+
which will limit the responses to I-Ds.
408407
"""
409408
draft = models.ForeignKey(InternetDraft, primary_key=True, unique=True, db_column='id_document_tag')
410409
rfc_flag = models.IntegerField(null=True)
@@ -457,8 +456,15 @@ def comments(self):
457456
return self.documentcomment_set.all().filter(rfc_flag=self.rfc_flag).order_by('-comment_date','-comment_time')
458457
def ballot_set(self):
459458
return IDInternal.objects.filter(ballot=self.ballot_id)
459+
def ballot_primary(self):
460+
return IDInternal.objects.filter(ballot=self.ballot_id,primary_flag=1)
460461
def ballot_others(self):
461462
return IDInternal.objects.filter(models.Q(primary_flag=0)|models.Q(primary_flag__isnull=True), ballot=self.ballot_id)
463+
def docstate(self):
464+
if self.cur_sub_state_id > 0:
465+
return "%s :: %s" % ( self.cur_state, self.cur_sub_state )
466+
else:
467+
return self.cur_state
462468
class Meta:
463469
db_table = 'id_internal'
464470
verbose_name = 'IDTracker Draft'

ietf/idtracker/urls.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@
2929
urlpatterns += patterns('django.views.generic.list_detail',
3030
(r'^rfc(?P<object_id>\d+)/$', 'object_detail', rfc_dict),
3131
(r'^(?P<object_id>\d+)/$', 'object_detail', id_dict),
32-
(r'^(?P<slug>[^/]+)/$', 'object_detail', dict(id_dict, slug_field='draft__filename')),
33-
(r'^comment/(?P<object_id>\d+)/$', 'object_detail', comment_dict),
34-
(r'^ballot/(?P<object_id>\d+)/$', 'object_detail', ballot_dict),
3532
)
3633
urlpatterns += patterns('',
34+
(r'^(?P<slug>[^/]+)/$', views.view_id, dict(id_dict, slug_field='draft__filename')),
35+
(r'^comment/(?P<object_id>\d+)/$', views.view_comment, comment_dict),
36+
(r'^ballot/(?P<object_id>\d+)/$', views.view_ballot, ballot_dict),
3737
(r'^(?P<slug>[^/]+)/comment/(?P<object_id>\d+)/$', views.comment, comment_dict),
3838
(r'^states/(?P<state>\d+)/$', views.state_desc),
3939
(r'^states/substate/(?P<state>\d+)/$', views.state_desc, { 'is_substate': 1 }),
40-
(r'^(?P<id>\d+)/edit/$', views.edit_idinternal),
40+
#(r'^(?P<id>\d+)/edit/$', views.edit_idinternal),
4141
(r'^$', views.search),
4242
)

ietf/idtracker/views.py

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from django.shortcuts import get_object_or_404, render_to_response
66
from django.db.models import Q
77
from django.views.generic.list_detail import object_detail, object_list
8-
from ietf.idtracker.models import InternetDraft, IDInternal, IDState, IDSubState
8+
from ietf.idtracker.models import InternetDraft, IDInternal, IDState, IDSubState, Rfc
99
from ietf.idtracker.forms import EmailFeedback
1010
from ietf.utils.mail import send_mail_text
1111

@@ -22,54 +22,56 @@ def myfields(f):
2222
return f.formfield()
2323

2424
def search(request):
25+
# todo: check if these field names work for backwards
26+
# compatability
2527
InternetDraftForm = forms.models.form_for_model(InternetDraft, formfield_callback=myfields)
26-
idform = InternetDraftForm(request.POST)
28+
idform = InternetDraftForm(request.REQUEST)
2729
InternalForm = forms.models.form_for_model(IDInternal, formfield_callback=myfields)
28-
form = InternalForm(request.POST)
29-
t = loader.get_template('idtracker/idtracker_search.html')
30+
form = InternalForm(request.REQUEST)
3031
# if there's a post, do the search and supply results to the template
31-
if request.method == 'POST':
32-
qdict = { 'filename': 'draft__filename__contains',
33-
'job_owner': 'job_owner',
34-
'group': 'draft__group__acronym',
35-
'cur_state': 'cur_state',
36-
'cur_sub_state': 'cur_sub_state',
37-
'rfc_number': 'draft__rfc_number',
38-
'area_acronym': 'area_acronym',
39-
'note': 'note__contains',
40-
}
41-
q_objs = [Q(**{qdict[k]: request.POST[k]})
42-
for k in qdict.keys()
43-
if request.POST[k] != '']
44-
matches = IDInternal.objects.all().filter(*q_objs)
45-
# matches = IDInternal.objects.all()
46-
# if request.POST['filename']:
47-
# matches = matches.filter(draft__filename__contains=request.POST["filename"])
48-
# if request.POST['job_owner']:
49-
# matches = matches.filter(job_owner=request.POST['job_owner'])
50-
# if request.POST['group']:
51-
# matches = matches.filter(draft__group__acronym=request.POST['group_acronym'])
52-
# if request.POST['cur_state']:
53-
# matches = matches.filter(cur_state=request.POST['cur_state'])
54-
# if request.POST['cur_sub_state']:
55-
# matches = matches.filter(cur_sub_state=request.POST['cur_sub_state'])
56-
# if request.POST['rfc_number']:
57-
# matches = matches.filter(draft__rfc_number=request.POST['rfc_number'])
58-
# if request.POST['area_acronym']:
59-
# matches = matches.filter(area_acronym=request.POST['area_acronym'])
60-
# if request.POST['note']:
61-
# matches = matches.filter(note__contains=request.POST['note'])
32+
searching = False
33+
# filename, rfc_number, group searches are seperate because
34+
# they can't be represented as simple searches in the data model.
35+
qdict = {
36+
'job_owner': 'job_owner',
37+
'cur_state': 'cur_state',
38+
'cur_sub_state': 'cur_sub_state',
39+
'area_acronym': 'area_acronym',
40+
'note': 'note__icontains',
41+
}
42+
q_objs = []
43+
for k in qdict.keys() + ['group', 'rfc_number', 'filename']:
44+
if request.REQUEST.has_key(k):
45+
searching = True
46+
if request.REQUEST[k] != '' and qdict.has_key(k):
47+
q_objs.append(Q(**{qdict[k]: request.REQUEST[k]}))
48+
if searching:
49+
group = request.REQUEST.get('group', '')
50+
if group != '':
51+
rfclist = [rfc.rfc_number for rfc in Rfc.objects.all().filter(group_acronym=group)]
52+
draftlist = [draft.id_document_tag for draft in InternetDraft.objects.all().filter(group__acronym=group)]
53+
q_objs.append(Q(draft__in=draftlist)&Q(rfc_flag=0)|Q(draft__in=rfclist)&Q(rfc_flag=1))
54+
rfc_number = request.REQUEST.get('rfc_number', '')
55+
if rfc_number != '':
56+
draftlist = [draft.id_document_tag for draft in InternetDraft.objects.all().filter(rfc_number=rfc_number)]
57+
q_objs.append(Q(draft__in=draftlist)&Q(rfc_flag=0)|Q(draft=rfc_number)&Q(rfc_flag=1))
58+
filename = request.REQUEST.get('filename', '')
59+
if filename != '':
60+
draftlist = [draft.id_document_tag for draft in InternetDraft.objects.all().filter(filename__icontains=filename)]
61+
q_objs.append(Q(draft__in=draftlist,rfc_flag=0))
62+
matches = IDInternal.objects.all().filter(*q_objs).filter(primary_flag=1)
6263
matches = matches.order_by('cur_state', 'cur_sub_state_id')
6364
else:
6465
matches = None
6566

66-
c = RequestContext(request, {
67+
return render_to_response('idtracker/idtracker_search.html', {
6768
'form': form,
6869
'idform': idform,
6970
'matches': matches,
70-
})
71-
return HttpResponse(t.render(c))
71+
'searching': searching,
72+
}, context_instance=RequestContext(request))
7273

74+
# proof of concept, orphaned for now
7375
def edit_idinternal(request, id=None):
7476
#draft = InternetDraft.objects.get(pk=id)
7577
draft = get_object_or_404(InternetDraft.objects, pk=id)
@@ -89,14 +91,11 @@ def edit_idinternal(request, id=None):
8991
else:
9092
form = None
9193

92-
t = loader.get_template('idtracker/idtracker_edit.html')
93-
94-
c = RequestContext(request, {
94+
return render_to_response('idtracker/idtracker_edit.html', {
9595
'form': form,
9696
'idform': idform,
9797
'draft': draft,
98-
})
99-
return HttpResponse(t.render(c))
98+
}, context_instance=RequestContext(request))
10099

101100
def state_desc(request, state, is_substate=0):
102101
if int(state) == 100:
@@ -142,3 +141,15 @@ def status(request):
142141
def last_call(request):
143142
queryset = IDInternal.objects.filter(primary_flag=1).filter(cur_state__state__in=('In Last Call', 'Waiting for Writeup', 'Waiting for AD Go-Ahead')).order_by('cur_state', 'status_date', 'ballot_id')
144143
return object_list(request, template_name="idtracker/status_of_items.html", queryset=queryset, extra_context={'title': 'Documents in Last Call'})
144+
145+
# Wrappers around object_detail to give permalink a handle.
146+
# The named-URLs feature in django 0.97 will eliminate the
147+
# need for these.
148+
def view_id(*args, **kwargs):
149+
return object_detail(*args, **kwargs)
150+
151+
def view_comment(*args, **kwargs):
152+
return object_detail(*args, **kwargs)
153+
154+
def view_ballot(*args, **kwargs):
155+
return object_detail(*args, **kwargs)

ietf/templates/idtracker/base.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@
2222
{% block idcontent %}
2323
{% endblock %}
2424

25+
<hr/>
26+
<a href="http://www.djangoproject.com/"><img src="http://media.djangoproject.com/img/badges/djangomade124x25.gif" border="0" alt="Made with Django." title="Made with Django." /></a>
27+
<HR>
28+
<p>
29+
Did you find a bug? <a href="{% url ietf.idtracker.views.send_email %}?cat=bugs" >Let us know</a>.
30+
<p>
31+
<a href="{% url ietf.idtracker.views.send_email %}?cat=discuss" >Any question or suggestion</a>?
32+
<p>
33+
<i>This page produced by the <A HREF="mailto:iesg-secretary@ietf.org">IETF Secretariat</a>
34+
for the <A HREF="mailto:iesg@ietf.org">IESG</A></i>
35+
<p>
36+
37+
2538
{% include "debug.html" %}
2639

2740
</body>

ietf/templates/idtracker/idinternal_detail.html

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
<div class="largefont">
1313
Detail Info
1414
</div>
15-
{% if object.ballot_set|length_is:"1" %}
16-
{% else %}
15+
{% if object.ballot_others %}
1716
<div align="right">
1817
<a href="#action">Action List</a>
1918
</div>
@@ -55,13 +54,16 @@
5554
</td>
5655

5756
<td>
58-
{# what's the "if" here #}
5957
<div class="largefont3">
60-
<a href="../ballot/{{ object.ballot_id }}">IESG evaluation record</a>
58+
{% if object.ballot.ballot_issued %}
59+
<a href="{% url ietf.idtracker.views.view_ballot object.ballot_id %}">IESG evaluation record</a>
6160
[<a href="/idtracker/evaluation_process/">What
6261
they mean</a>]
6362
[<a href="/idtracker/ballot_key/">How they are
6463
recorded</a>]
64+
{% else %}
65+
No IESG evaluation record
66+
{% endif %}
6567
</div>
6668
</td>
6769
</tr>
@@ -187,7 +189,7 @@
187189
<table cellpadding="1" cellspacing="1" border="0">
188190
<tr>
189191
<td>
190-
<form action="/idtracker/" method="GET">
192+
<form action="{% url ietf.idtracker.views.search %}" method="GET">
191193
<input type="submit" value=
192194
"Main Menu">
193195
</form>
@@ -201,17 +203,19 @@
201203
</tr>
202204
</table>
203205

204-
{% if object.ballot_set|length_is:"1" %}
205-
{% else %}
206+
{% if object.ballot_others %}
206207
<a name="action"></a>
207208
<table border="1" bgcolor="black">
208209
<tr><td><font color="white"><h3>Actions</h3></font>
210+
{# this "regroup" is to get the data structure into the shape
211+
# that search_result_table wants - it doesn't do anything real. #}
212+
{% regroup object.ballot_primary by docstate as grouped %}
213+
{% include "idtracker/search_result_table.html" %}
209214
</td>
210215
</tr>
211216
</table>
212217
{% endif %}
213218

214-
215219
<h3>Comment Log</h3>
216220

217221
<table cellpadding="1" cellspacing="1" border="0">
@@ -235,18 +239,22 @@ <h3>Comment Log</h3>
235239
<b>*{{ comment.get_ballot_display }}*</b>]</font>
236240
{% endif %} {{ comment.comment_text|format_textarea|truncatewords_html:"25" }}</td>
237241

238-
<td>
239-
<form action="comment/{{ comment.id }}" method="GET">
242+
<!-- this form element technically belongs inside the <td>
243+
but that actually changes the visible spacing in most
244+
browsers, so we let layout concerns make us write
245+
invalid HTML. -->
246+
<form action="comment/{{ comment.id }}" method="GET">
247+
<td>
240248
<input type="submit" value="View Detail">
241-
</form>
242-
</td>
249+
</td>
250+
</form>
243251
</tr>
244252
{% endfor %}
245253
</table>
246254
<br>
247255

248256

249-
<form action="/idtracker/" method="GET">
257+
<form action="{% url ietf.idtracker.views.search %}" method="GET">
250258
<input type="submit" value="Main Menu">
251259
<input type="button" name="back_button" value="BACK"
252260
onclick="history.go(-1);return true">

0 commit comments

Comments
 (0)