Skip to content

Commit b0906f0

Browse files
committed
Basic charting of new revision activity for document search results.
- Legacy-Id: 11922
1 parent 75a3895 commit b0906f0

19 files changed

Lines changed: 1497 additions & 30 deletions

File tree

debug.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
# Number of times to indent output
3737
# A list is used to force access by reference
3838
_report_indent = [4]
39-
_mark = [ timeutils.clock() ]
39+
_mark = [ timeutils.time() ]
4040

4141
def set_indent(i):
4242
_report_indent[0] = i
@@ -82,27 +82,29 @@ def wrap(fn, *params,**kwargs):
8282
return fn
8383

8484
def mark():
85-
_mark[0] = timeutils.clock()
85+
_mark[0] = timeutils.time()
8686

8787
def lap(s):
88-
tau = timeutils.clock() - _mark[0]
89-
say("> %s: %.3fs since mark" % (s, tau))
88+
clk = timeutils.time()
89+
tau = clk - _mark[0]
90+
ts = timeutils.strftime("%H:%M:%S", timeutils.localtime(clk))
91+
say("%s: %.3fs since mark: %s" % (ts, tau, s))
9092

9193
def clock(s):
9294
lap(s)
93-
_mark[0] = timeutils.clock()
95+
_mark[0] = timeutils.time()
9496

9597
def time(fn):
9698
"""Decorator to print timing information about a function call.
9799
"""
98100
def wrap(fn, *params,**kwargs):
99-
mark = timeutils.clock()
101+
mark = timeutils.time()
100102

101103
indent = ' ' * _report_indent[0]
102104
fc = "%s.%s()" % (fn.__module__, fn.__name__,)
103105

104106
ret = fn(*params,**kwargs)
105-
tau = timeutils.clock() - mark
107+
tau = timeutils.time() - mark
106108
sys.stderr.write("%s| %s | %.3fs\n" % (indent, fc, tau))
107109

108110
return ret
@@ -160,6 +162,7 @@ def say(s):
160162
if debug:
161163
indent = ' ' * (_report_indent[0])
162164
sys.stderr.write("%s%s\n" % (indent, s))
165+
sys.stderr.flush()
163166

164167
def profile(fn):
165168
def wrapper(*args, **kwargs):

ietf/bower.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"d3": "~3",
99
"font-awesome": "~4",
1010
"html5shiv": "~3",
11+
"highcharts": "~4.2",
1112
"jquery": "~1",
1213
"jquery.cookie": "~1",
1314
"jquery.tablesorter": "~2",
@@ -31,6 +32,16 @@
3132
},
3233
"respond": {
3334
"main": "dest/respond.min.js"
35+
},
36+
"highcharts": {
37+
"main": [
38+
"highcharts.js",
39+
"highcharts-more.js",
40+
"highstock.js",
41+
"highmaps.js",
42+
"modules/exporting.js",
43+
"modules/map.js"
44+
]
3445
}
3546
}
3647
}

ietf/doc/models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ def latest_event(self, *args, **filter_args):
420420
return e[0] if e else None
421421

422422
def canonical_name(self):
423+
if hasattr(self, '_canonical_name'):
424+
return self._canonical_name
423425
name = self.name
424426
if self.type_id == "draft" and self.get_state_slug() == "rfc":
425427
a = self.docalias_set.filter(name__startswith="rfc")
@@ -441,6 +443,8 @@ def display_name(self):
441443

442444

443445
def telechat_date(self, e=None):
446+
if hasattr(self, '_telechat_date'):
447+
return self._telechat_date
444448
if not e:
445449
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
446450
return e.telechat_date if e and e.telechat_date and e.telechat_date >= datetime.date.today() else None
@@ -551,6 +555,8 @@ def __unicode__(self):
551555
return unicode(self.doc.name)
552556

553557
def canonical_name(self):
558+
if hasattr(self, '_canonical_name'):
559+
return self._canonical_name
554560
return self.name
555561

556562
def latest_event(self, *args, **kwargs):

ietf/doc/templatetags/ietf_filters.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,3 +590,11 @@ def urlize_html(html, autoescape=False):
590590
def emailwrap(email):
591591
email = str(email)
592592
return mark_safe(email.replace('@', '<wbr>@'))
593+
594+
@register.filter()
595+
def comma_separated_list(seq, end_word="and"):
596+
if len(seq) < 2:
597+
return u"".join(seq)
598+
else:
599+
return u", ".join(seq[:-1]) + u" %s %s"%(end_word, seq[-1])
600+

ietf/doc/urls.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@
3333
from django.conf.urls import patterns, url, include
3434
from django.views.generic import RedirectView
3535

36-
from ietf.doc import views_search, views_draft, views_ballot
37-
from ietf.doc import views_status_change
38-
from ietf.doc import views_doc
36+
from ietf.doc import views_search, views_draft, views_ballot, views_status_change, views_doc
37+
from ietf.doc import views_stats
3938

4039
session_patterns = [
4140
url(r'^add$', views_doc.add_sessionpresentation),
@@ -54,6 +53,8 @@
5453
url(r'^start-rfc-status-change/(?P<name>[A-Za-z0-9._+-]*)$', views_status_change.start_rfc_status_change, name='start_rfc_status_change'),
5554
url(r'^iesg/(?P<last_call_only>[A-Za-z0-9.-]+/)?$', views_search.drafts_in_iesg_process, name="drafts_in_iesg_process"),
5655
url(r'^email-aliases/$', views_doc.email_aliases),
56+
url(r'^stats/newrevisiondocevent/?$', views_stats.doc_stats_newrevisiondocevent),
57+
url(r'^stats/data/newrevisiondocevent/?$', views_stats.doc_stats_data_newrevisiondocevent),
5758

5859
url(r'^all/$', views_search.index_all_drafts, name="index_all_drafts"),
5960
url(r'^active/$', views_search.index_active_drafts, name="index_active_drafts"),

ietf/doc/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import urllib
44
import math
55
import datetime
6+
import hashlib
7+
import json
68

79
from django.conf import settings
810
from django.db.models.query import EmptyQuerySet
@@ -583,3 +585,12 @@ def get_ancestors(doc):
583585
}
584586
history = history.values()
585587
return sorted(history, key=lambda x: x['published'])
588+
589+
590+
def get_search_cache_key(params):
591+
from ietf.doc.views_search import SearchForm
592+
fields = set(SearchForm.base_fields) - set(['sort',])
593+
kwargs = dict([ (k,v) for (k,v) in params.items() if k in fields ])
594+
key = "doc:document:search:" + hashlib.sha512(json.dumps(kwargs, sort_keys=True)).hexdigest()
595+
return key
596+

ietf/doc/views_search.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@
3030
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3131
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3232

33-
import datetime, re
33+
import re
34+
import datetime
3435

3536
from django import forms
3637
from django.conf import settings
3738
from django.core.cache import cache
3839
from django.core.exceptions import ObjectDoesNotExist
3940
from django.core.urlresolvers import reverse as urlreverse
4041
from django.db.models import Q
41-
from django.http import Http404, HttpResponseBadRequest, HttpResponse, HttpResponseRedirect
42+
from django.http import Http404, HttpResponseBadRequest, HttpResponse, HttpResponseRedirect, QueryDict
4243
from django.shortcuts import render
4344
from django.utils.cache import _generate_cache_key
4445

@@ -49,6 +50,7 @@
4950
DocEvent, LastCallDocEvent, TelechatDocEvent, IESG_SUBSTATE_TAGS )
5051
from ietf.doc.expire import expirable_draft
5152
from ietf.doc.fields import select2_id_doc_name_json
53+
from ietf.doc.utils import get_search_cache_key
5254
from ietf.group.models import Group
5355
from ietf.idindex.index import active_drafts_index_by_group
5456
from ietf.name.models import DocTagName, DocTypeName, StreamName
@@ -123,9 +125,6 @@ def clean(self):
123125
q['state'] = q['substate'] = None
124126
return q
125127

126-
def wrap_value(v):
127-
return lambda: v
128-
129128
def fill_in_search_attributes(docs):
130129
# fill in some attributes for the search results to save some
131130
# hairy template code and avoid repeated SQL queries
@@ -153,13 +152,13 @@ def fill_in_search_attributes(docs):
153152
for e in TelechatDocEvent.objects.filter(doc__in=doc_ids, type="scheduled_for_telechat").order_by('-time'):
154153
if e.doc_id not in seen:
155154
d = docs_dict[e.doc_id]
156-
d.telechat_date = wrap_value(d.telechat_date(e))
155+
d._telechat_date = d.telechat_date(e)
157156
seen.add(e.doc_id)
158157

159158
# misc
160159
for d in docs:
161-
# emulate canonical name which is used by a lot of the utils
162-
d.canonical_name = wrap_value(rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name)
160+
# set up information for canonical_name() which is used by a lot of the utils
161+
d._canonical_name = rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name
163162

164163
if d.rfc_number() != None and d.latest_event_cache["published_rfc"]:
165164
d.latest_revision_date = d.latest_event_cache["published_rfc"].time
@@ -265,7 +264,7 @@ def retrieve_search_results(form, all_types=False):
265264
# radio choices
266265
by = query["by"]
267266
if by == "author":
268-
docs = docs.filter(authors__person__name__icontains=query["author"])
267+
docs = docs.filter(authors__person__alias__name__icontains=query["author"])
269268
elif by == "group":
270269
docs = docs.filter(group__acronym=query["group"])
271270
elif by == "area":
@@ -362,7 +361,7 @@ def sort_key(d):
362361
d["sort"] = h["key"]
363362
h["sort_url"] = "?" + d.urlencode()
364363

365-
return (results, meta)
364+
return (results, meta, docs)
366365

367366

368367
def get_doc_is_tracked(request, results):
@@ -392,20 +391,27 @@ def search(request):
392391
get_params['substate'] = request.GET['subState']
393392

394393
form = SearchForm(get_params)
395-
if not form.is_valid():
396-
return HttpResponseBadRequest("form not valid: %s" % form.errors)
394+
key = get_search_cache_key(get_params)
395+
info = cache.get(key)
396+
if not info:
397+
if not form.is_valid():
398+
return HttpResponseBadRequest("form not valid: %s" % form.errors)
399+
400+
info = retrieve_search_results(form)
401+
cache.set(key, info)
397402

398-
results, meta = retrieve_search_results(form)
403+
results, meta, qs = info
399404
meta['searching'] = True
400405
else:
401406
form = SearchForm()
402407
results = []
403408
meta = { 'by': None, 'advanced': False, 'searching': False }
409+
get_params = QueryDict('')
404410

405411
doc_is_tracked = get_doc_is_tracked(request, results)
406412

407413
return render(request, 'doc/search/search.html', {
408-
'form':form, 'docs':results, 'doc_is_tracked':doc_is_tracked, 'meta':meta, },
414+
'form':form, 'docs':results, 'doc_is_tracked':doc_is_tracked, 'meta':meta, 'queryargs':get_params.urlencode() },
409415
)
410416

411417
def frontpage(request):
@@ -580,7 +586,7 @@ def docs_for_ad(request, name):
580586
form = SearchForm({'by':'ad','ad': ad.id,
581587
'rfcs':'on', 'activedrafts':'on', 'olddrafts':'on',
582588
'sort': 'status'})
583-
results, meta = retrieve_search_results(form, all_types=True)
589+
results, meta, _ = retrieve_search_results(form, all_types=True)
584590
results.sort(key=ad_dashboard_sort_key)
585591
del meta["headers"][-1]
586592
#
@@ -594,7 +600,7 @@ def docs_for_ad(request, name):
594600
def drafts_in_last_call(request):
595601
lc_state = State.objects.get(type="draft-iesg", slug="lc").pk
596602
form = SearchForm({'by':'state','state': lc_state, 'rfcs':'on', 'activedrafts':'on'})
597-
results, meta = retrieve_search_results(form)
603+
results, meta, _ = retrieve_search_results(form)
598604

599605
return render(request, 'doc/drafts_in_last_call.html', {
600606
'form':form, 'docs':results, 'meta':meta

0 commit comments

Comments
 (0)