Skip to content

Commit 4506cb4

Browse files
committed
Merged in Lars Eggert's changes to the search page, and Henrik's lefthand-menu addition
- Legacy-Id: 1255
1 parent ce26647 commit 4506cb4

68 files changed

Lines changed: 1053 additions & 768 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ietf/.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
/*.swp
21
/*.pyc
3-
/settings_local.py

ietf/idtracker/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
/*.pyc
2-
/settings_local.py

ietf/idtracker/fixtures/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/*.pyc

ietf/idtracker/forms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
class IDSearch(forms.Form):
77
search_job_owner = forms.ChoiceField(choices=(), required=False)
8-
search_group_acronym = forms.CharField(widget=forms.TextInput(attrs={'size': 6, 'maxlength': 10}), required=False)
8+
search_group_acronym = forms.CharField(widget=forms.TextInput(attrs={'size': 7, 'maxlength': 10}), required=False)
99
search_status_id = forms.ModelChoiceField(IDStatus.objects.all(), empty_label="--All", required=False)
1010
search_area_acronym = forms.ModelChoiceField(Area.objects.filter(status=Area.ACTIVE), empty_label="--All/Any", required=False)
1111
search_cur_state = forms.ModelChoiceField(IDState.objects.all(), empty_label="--All/Any", required=False)

ietf/idtracker/models.py

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright The IETF Trust 2007, All Rights Reserved
22

3+
from django.conf import settings
34
from django.db import models
45
from ietf.utils import FKAsOneToOne
56
from django.test import TestCase
@@ -117,6 +118,7 @@ class Admin:
117118
pass
118119

119120
class InternetDraft(models.Model):
121+
DAYS_TO_EXPIRE=185
120122
id_document_tag = models.AutoField(primary_key=True)
121123
title = models.CharField(maxlength=255, db_column='id_document_name')
122124
id_document_key = models.CharField(maxlength=255, editable=False)
@@ -153,9 +155,19 @@ def save(self):
153155
self.id_document_key = self.title.upper()
154156
super(InternetDraft, self).save()
155157
def displayname(self):
156-
return "%s-%s.txt" % ( self.filename, self.revision_display() )
158+
if self.status.status == "Replaced":
159+
css="replaced"
160+
else:
161+
css="active"
162+
return '<span class="' + css + '">' + self.filename + '</span>'
163+
def displayname_with_link(self):
164+
if self.status.status == "Replaced":
165+
css="replaced"
166+
else:
167+
css="active"
168+
return '<a class="' + css + '" href="%s">%s</a>' % ( self.doclink(), self.filename )
157169
def doclink(self):
158-
return "http://www.ietf.org/internet-drafts/%s" % ( self.displayname() )
170+
return "http://" + settings.TOOLS_SERVER + "/html/%s" % ( self.filename )
159171
def group_acronym(self):
160172
return self.group.acronym
161173
def __str__(self):
@@ -176,12 +188,26 @@ def doctype(self):
176188
def filename_with_link(self, text=None):
177189
if text is None:
178190
text=self.filename
179-
if self.status.status != 'Active':
180-
return text
181-
else:
182-
return '<a href="%s">%s</a>' % ( self.doclink(), text )
183-
def displayname_with_link(self):
184-
return self.filename_with_link(self.displayname())
191+
return '<a href="%s">%s</a>' % ( self.doclink(), text )
192+
def expiration(self):
193+
return self.revision_date + datetime.timedelta(self.DAYS_TO_EXPIRE)
194+
def can_expire(self):
195+
# Copying the logic from expire-ids-1 without thinking
196+
# much about it.
197+
if self.review_by_rfc_editor:
198+
return False
199+
idinternal = self.idinternal
200+
if idinternal:
201+
cur_state_id = idinternal.cur_state_id
202+
# 42 is "AD is Watching"; this matches what's in the
203+
# expire-ids-1 perl script.
204+
# A better way might be to add a column to the table
205+
# saying whether or not a document is prevented from
206+
# expiring.
207+
if cur_state_id < 42:
208+
return False
209+
return True
210+
185211
class Meta:
186212
db_table = "internet_drafts"
187213
class Admin:
@@ -364,7 +390,7 @@ def revision(self):
364390
def revision_display(self):
365391
return "RFC"
366392
def doclink(self):
367-
return "http://www.ietf.org/rfc/%s" % ( self.displayname() )
393+
return "http://" + settings.TOOLS_SERVER + "/html/%s" % ( self.displayname() )
368394
def doctype(self):
369395
return "RFC"
370396
def filename_with_link(self):
@@ -581,12 +607,17 @@ def get_author(self):
581607
if self.created_by_id and self.created_by_id != 999:
582608
return self.created_by.__str__()
583609
else:
584-
return "system"
610+
return "(System)"
585611
def get_username(self):
586612
if self.created_by_id and self.created_by_id != 999:
587613
return self.created_by.login_name
588614
else:
589-
return "system"
615+
return "(System)"
616+
def get_fullname(self):
617+
if self.created_by_id and self.created_by_id != 999:
618+
return self.created_by.first_name + " " + self.created_by.last_name
619+
else:
620+
return "(System)"
590621
def datetime(self):
591622
# this is just a straightforward combination, except that the time is
592623
# stored incorrectly in the database.
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
/*.pyc
2-
/settings_local.py

ietf/idtracker/templatetags/ietf_filters.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ def allononeline(text):
169169
"""Simply removes CRs, LFs, leading and trailing whitespace from the given string."""
170170
return text.replace("\r", "").replace("\n", "").strip()
171171

172+
@register.filter(name='allononelinew')
173+
def allononelinew(text):
174+
"""Map runs of whitespace to a single space and strip leading and trailing whitespace from the given string."""
175+
return re.sub("[\r\n\t ]+", " ", text).strip()
176+
172177
@register.filter(name='rfcspace')
173178
def rfcspace(string):
174179
"""
@@ -213,9 +218,63 @@ def inpast(date):
213218
return date < datetime.datetime.now()
214219
return True
215220

221+
@register.filter(name='truncatemore')
222+
def truncatemore(text, arg):
223+
"""Truncate the text if longer than 'words', and if truncated,
224+
add a link to the full text (given in 'link').
225+
"""
226+
from django.utils.text import truncate_words
227+
args = arg.split(",")
228+
if len(args) == 3:
229+
count, link, format = args
230+
elif len(args) == 2:
231+
format = "[<a href='%s'>more</a>]"
232+
count, link = args
233+
else:
234+
return text
235+
try:
236+
length = int(count)
237+
except ValueError: # invalid literal for int()
238+
return text # Fail silently.
239+
if not isinstance(text, basestring):
240+
text = str(text)
241+
words = text.split()
242+
if len(words) > length:
243+
words = words[:length]
244+
words.append(format % link)
245+
return ' '.join(words)
246+
247+
@register.filter(name="wrap_long_lines")
248+
def wrap_long_lines(text):
249+
"""Wraps long lines without loosing the formatting and indentation
250+
of short lines"""
251+
if type(text) != type(""):
252+
return text
253+
text = re.sub(" *\r\n", "\n", text) # get rid of DOS line endings
254+
text = re.sub(" *\r", "\n", text) # get rid of MAC line endings
255+
text = re.sub("( *\n){3,}", "\n\n", text) # get rid of excessive vertical whitespace
256+
lines = text.split("\n")
257+
filled = []
258+
wrapped = False
259+
for line in lines:
260+
if wrapped and line.strip() != "":
261+
line = filled[-1] + " " + line
262+
filled = filled[:-1]
263+
else:
264+
wrapped = False
265+
while (len(line) > 80) and (" " in line[:80]):
266+
wrapped = True
267+
breakpoint = line.rfind(" ",0,79)
268+
filled += [ line[:breakpoint] ]
269+
line = line[breakpoint+1:]
270+
filled += [ line.rstrip() ]
271+
return "\n".join(filled)
272+
216273
def _test():
217274
import doctest
218275
doctest.testmod()
219276

220277
if __name__ == "__main__":
221278
_test()
279+
280+

ietf/idtracker/views.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,24 @@ def search(request):
7676
if status != '':
7777
q_objs.append(Q(draft__status=status,rfc_flag=0))
7878
matches = IDInternal.objects.all().filter(*q_objs)
79-
matches = matches.order_by('cur_state', 'cur_sub_state', '-primary_flag')
79+
matches = matches.order_by('cur_state', 'cur_sub_state', 'ballot_id', '-primary_flag')
80+
# sort by date in reverse
81+
# first build docstate groups, within which we sort
82+
# in each docstate group, we build ballot id groups, which we sort
83+
m1 = [] # list of: docstate, list of: event date; ballot id; list of: ms for the ballot id
84+
for m in matches:
85+
if m1 and m1[-1][0] == m.docstate():
86+
if m1[-1][1] and m1[-1][1][0][1] == m.ballot_id:
87+
m1[-1][1][0][2].append(m)
88+
else:
89+
m1[-1][1].append((m.event_date, m.ballot_id, [m]))
90+
else:
91+
m1.append((m.docstate(), [(m.event_date, m.ballot_id, [m])]))
92+
matches = []
93+
for ms in m1: ms[1].sort(reverse=True)
94+
for ms in m1:
95+
for mt in ms[1]:
96+
matches.extend(mt[2])
8097
#
8198
# Now search by I-D exists, if there could be any results.
8299
# If searching by job owner, current state or substate, there
@@ -119,6 +136,7 @@ def search(request):
119136
'form': form,
120137
'matches': matches,
121138
'searching': searching,
139+
'spacing': True
122140
}, context_instance=RequestContext(request))
123141

124142
# proof of concept, orphaned for now
@@ -209,7 +227,7 @@ def view_id(request, queryset, slug, slug_field):
209227
except IDInternal.DoesNotExist:
210228
draft = get_object_or_404(InternetDraft, filename=slug)
211229
return render_to_response('idtracker/idinternal_notfound.html', {'draft': draft}, context_instance=RequestContext(request))
212-
return render_to_response('idtracker/idinternal_detail.html', {'object': object}, context_instance=RequestContext(request))
230+
return render_to_response('idtracker/idinternal_detail.html', {'object': object, 'spacing': False}, context_instance=RequestContext(request))
213231

214232
def view_rfc(request, object_id):
215233
'''A replacement for the object_detail generic view for this
@@ -223,7 +241,7 @@ def view_rfc(request, object_id):
223241
This view gets the appropriate row from IDInternal and
224242
calls the template with the necessary context.'''
225243
object = get_object_or_404(IDInternal, pk=object_id, rfc_flag=1)
226-
return render_to_response('idtracker/idinternal_detail.html', {'object': object}, context_instance=RequestContext(request))
244+
return render_to_response('idtracker/idinternal_detail.html', {'object': object, 'spacing': False}, context_instance=RequestContext(request))
227245

228246
# Wrappers around object_detail to give permalink a handle.
229247
# The named-URLs feature in django 0.97 will eliminate the

ietf/proceedings/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
/*.pyc
2-
/settings_local.py

ietf/proceedings/feeds.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import re
2+
from django.contrib.syndication.feeds import Feed
3+
from django.utils.feedgenerator import Atom1Feed
4+
from ietf.proceedings.models import WgProceedingsActivities
5+
from ietf.proceedings.models import Slide, WgAgenda, Proceeding
6+
from datetime import datetime, time
7+
from django.db import connection
8+
9+
class LatestWgProceedingsActivity(Feed):
10+
feed_type = Atom1Feed
11+
link = "/foo"
12+
description = "foobar"
13+
language = "en"
14+
feed_url = "/feed/ipr/"
15+
base_url = "http://www3.ietf.org/proceedings/"
16+
17+
def items(self):
18+
objs = []
19+
for act in WgProceedingsActivities.objects.order_by('-act_date')[:60]:
20+
obj = {}
21+
22+
m = re.match("^slide, '(.*)', was uploaded$", act.activity)
23+
if m:
24+
obj['title'] = m.group(1)
25+
obj['title'] = re.sub("[^ -~]+", "", obj['title'])
26+
slides = Slide.objects.filter(meeting=act.meeting).filter(slide_name=m.group(1)).filter(group_acronym_id=act.group_acronym_id)
27+
if len(slides) == 1:
28+
obj['link'] = self.base_url + slides[0].file_loc()
29+
30+
m = re.match("^agenda was uploaded$", act.activity)
31+
if m:
32+
obj['title'] = "agenda";
33+
agendas = WgAgenda.objects.filter(meeting=act.meeting).filter(group_acronym_id=act.group_acronym_id)
34+
if len(agendas) == 1:
35+
dir = Proceeding.objects.get(meeting_num=act.meeting).dir_name
36+
obj['link'] = self.base_url + dir + "/agenda/" + agendas[0].filename
37+
38+
if len(obj) > 0:
39+
try:
40+
act.irtf = False
41+
obj['group_acronym'] = act.acronym()
42+
except:
43+
act.irtf = True
44+
try:
45+
obj['group_acronym'] = act.acronym()
46+
except:
47+
obj['group_acronym'] = "?"
48+
obj['date'] = datetime.combine(act.act_date, time(int(act.act_time[0:2]), int(act.act_time[3:5]), int(act.act_time[6:8])))
49+
obj['author'] = str(act.act_by)
50+
objs.append(obj)
51+
52+
return objs
53+
54+
def get_object(self, bits):
55+
obj = {}
56+
obj['title'] = "This is the title";
57+
return obj
58+
59+
def title(self, obj):
60+
return "Meeting Materials Activity"
61+
62+
def item_link(self, item):
63+
if 'link' in item:
64+
return item['link']
65+
else:
66+
return ""
67+
68+
def item_pubdate(self, item):
69+
return item['date']
70+
71+
def item_author_name(self, item):
72+
return item['author']
73+
74+
def item_author_email(self, item):
75+
return None;

0 commit comments

Comments
 (0)