11import datetime , itertools , json , calendar
2+ from collections import defaultdict
23
34from django .shortcuts import render
45from django .contrib .auth .decorators import login_required
56from django .core .urlresolvers import reverse as urlreverse
67from django .http import HttpResponseRedirect , HttpResponseForbidden
8+ from django .db .models import Count
9+ from django .utils .safestring import mark_safe
710
811import dateutil .relativedelta
912
1518from ietf .group .models import Role , Group
1619from ietf .person .models import Person
1720from ietf .name .models import ReviewRequestStateName , ReviewResultName
21+ from ietf .doc .models import Document
1822from ietf .ietfauth .utils import has_role
1923
2024def stats_index (request ):
2125 return render (request , "stats/index.html" )
2226
27+ def generate_query_string (query_dict , overrides ):
28+ query_part = u""
29+
30+ if query_dict or overrides :
31+ d = query_dict .copy ()
32+ for k , v in overrides .iteritems ():
33+ if type (v ) in (list , tuple ):
34+ if not v :
35+ if k in d :
36+ del d [k ]
37+ else :
38+ d .setlist (k , v )
39+ else :
40+ if v is None or v == u"" :
41+ if k in d :
42+ del d [k ]
43+ else :
44+ d [k ] = v
45+
46+ if d :
47+ query_part = u"?" + d .urlencode ()
48+
49+ return query_part
50+
51+
52+ def document_stats (request , stats_type = None , document_state = None ):
53+ def build_document_stats_url (stats_type_override = Ellipsis , document_state_override = Ellipsis , get_overrides = {}):
54+ kwargs = {
55+ "stats_type" : stats_type if stats_type_override is Ellipsis else stats_type_override ,
56+ "document_state" : document_state if document_state_override is Ellipsis else document_state_override ,
57+ }
58+
59+ return urlreverse (document_stats , kwargs = { k : v for k , v in kwargs .iteritems () if v is not None }) + generate_query_string (request .GET , get_overrides )
60+
61+ # statistics type - one of the tables or the chart
62+ possible_stats_types = [
63+ ("authors" , "Number of authors" ),
64+ # ("pages", "Pages"),
65+ # ("format", "Format"),
66+ # ("spectech", "Specification techniques"),
67+ ]
68+
69+ possible_stats_types = [ (slug , label , build_document_stats_url (stats_type_override = slug ))
70+ for slug , label in possible_stats_types ]
71+
72+ if not stats_type :
73+ return HttpResponseRedirect (build_document_stats_url (stats_type_override = possible_stats_types [0 ][0 ]))
74+
75+ possible_document_states = [
76+ ("all" , "All" ),
77+ ("rfc" , "RFCs" ),
78+ ("draft" , "Drafts (not published as RFC)" ),
79+ ]
80+
81+ possible_document_states = [ (slug , label , build_document_stats_url (document_state_override = slug ))
82+ for slug , label in possible_document_states ]
83+
84+ if not document_state :
85+ return HttpResponseRedirect (build_document_stats_url (document_state_override = possible_document_states [0 ][0 ]))
86+
87+
88+ # filter documents
89+ doc_qs = Document .objects .filter (type = "draft" )
90+
91+ if document_state == "rfc" :
92+ doc_qs = doc_qs .filter (states__type = "draft" , states__slug = "rfc" )
93+ elif document_state == "draft" :
94+ doc_qs = doc_qs .exclude (states__type = "draft" , states__slug = "rfc" )
95+
96+ chart_data = []
97+ table_data = []
98+ stats_title = ""
99+
100+ if stats_type == "authors" :
101+ stats_title = "Number of authors for each document"
102+
103+ groups = defaultdict (list )
104+
105+ for name , author_count in doc_qs .values_list ("name" ).annotate (Count ("authors" )).iterator ():
106+ groups [author_count ].append (name )
107+
108+ total_docs = sum (len (names ) for author_count , names in groups .iteritems ())
109+
110+ series_data = []
111+ for author_count , names in sorted (groups .iteritems (), key = lambda t : t [0 ]):
112+ series_data .append ((author_count , len (names ) * 100.0 / total_docs ))
113+ table_data .append ((author_count , names ))
114+
115+ chart_data .append ({
116+ "data" : series_data ,
117+ "name" : "Percentage of documents" ,
118+ })
119+
120+
121+ return render (request , "stats/document_stats.html" , {
122+ "chart_data" : mark_safe (json .dumps (chart_data )),
123+ "table_data" : table_data ,
124+ "stats_title" : stats_title ,
125+ "possible_stats_types" : possible_stats_types ,
126+ "stats_type" : stats_type ,
127+ "possible_document_states" : possible_document_states ,
128+ "document_state" : document_state ,
129+ })
130+
23131@login_required
24132def review_stats (request , stats_type = None , acronym = None ):
25133 # This view is a bit complex because we want to show a bunch of
@@ -39,29 +147,7 @@ def build_review_stats_url(stats_type_override=Ellipsis, acronym_override=Ellips
39147 if acr :
40148 kwargs ["acronym" ] = acr
41149
42- base_url = urlreverse (review_stats , kwargs = kwargs )
43- query_part = u""
44-
45- if request .GET or get_overrides :
46- d = request .GET .copy ()
47- for k , v in get_overrides .iteritems ():
48- if type (v ) in (list , tuple ):
49- if not v :
50- if k in d :
51- del d [k ]
52- else :
53- d .setlist (k , v )
54- else :
55- if v is None or v == u"" :
56- if k in d :
57- del d [k ]
58- else :
59- d [k ] = v
60-
61- if d :
62- query_part = u"?" + d .urlencode ()
63-
64- return base_url + query_part
150+ return urlreverse (review_stats , kwargs = kwargs ) + generate_query_string (request .GET , get_overrides )
65151
66152 def get_choice (get_parameter , possible_choices , multiple = False ):
67153 values = request .GET .getlist (get_parameter )
0 commit comments