77
88import dateutil .relativedelta
99
10- from ietf .review .utils import extract_review_request_data , aggregate_review_request_stats , ReviewRequestData
10+ from ietf .review .utils import (extract_review_request_data ,
11+ aggregate_raw_review_request_stats ,
12+ ReviewRequestData ,
13+ compute_review_request_stats ,
14+ sum_raw_review_request_aggregations )
1115from ietf .group .models import Role , Group
1216from ietf .person .models import Person
1317from ietf .name .models import ReviewRequestStateName , ReviewResultName
@@ -59,12 +63,17 @@ def build_review_stats_url(stats_type_override=Ellipsis, acronym_override=Ellips
5963
6064 return base_url + query_part
6165
62- def get_from_selection (get_parameter , possible_choices ):
63- val = request .GET .get (get_parameter )
64- for slug , label , url in possible_choices :
65- if slug == val :
66- return slug
67- return None
66+ def get_choice (get_parameter , possible_choices , multiple = False ):
67+ values = request .GET .getlist (get_parameter )
68+ found = [t [0 ] for t in possible_choices if t [0 ] in values ]
69+
70+ if multiple :
71+ return found
72+ else :
73+ if found :
74+ return found [0 ]
75+ else :
76+ return None
6877
6978 # which overview - team or reviewer
7079 if acronym :
@@ -96,7 +105,7 @@ def get_from_selection(get_parameter, possible_choices):
96105
97106 possible_count_choices = [ (slug , label , build_review_stats_url (get_overrides = { "count" : slug })) for slug , label in possible_count_choices ]
98107
99- count = get_from_selection ("count" , possible_count_choices ) or ""
108+ count = get_choice ("count" , possible_count_choices ) or ""
100109
101110 # time range
102111 def parse_date (s ):
@@ -175,31 +184,41 @@ def parse_date(s):
175184 group_by_objs = { r .pk : r for r in query_reviewers }
176185 group_by_index = ReviewRequestData ._fields .index ("reviewer" )
177186
178- # now aggregate the data
187+ # now filter and aggregate the data
179188 possible_teams = possible_completion_types = possible_results = possible_states = None
180- selected_team = selected_completion_type = selected_result = selected_state = None
189+ selected_teams = selected_completion_type = selected_result = selected_state = None
181190
182191 if stats_type == "time" :
183- possible_teams = [(t .acronym , t .acronym , build_review_stats_url (get_overrides = { "team" : t .acronym })) for t in teams ]
184- selected_team = get_from_selection ("team" , possible_teams )
185- query_teams = [t for t in query_teams if t .acronym == selected_team ]
192+ possible_teams = [(t .acronym , t .acronym ) for t in teams ]
193+ selected_teams = get_choice ("team" , possible_teams , multiple = True )
186194
187- extracted_data = extract_review_request_data (query_teams , query_reviewers , from_time , to_time , ordering = [level ])
195+ def add_if_exists_else_subtract (element , l ):
196+ if element in l :
197+ return [x for x in l if x != element ]
198+ else :
199+ return l + [element ]
200+
201+ possible_teams = [(slug , label , build_review_stats_url (get_overrides = {
202+ "team" : add_if_exists_else_subtract (slug , selected_teams )
203+ })) for slug , label in possible_teams ]
204+ query_teams = [t for t in query_teams if t .acronym in selected_teams ]
205+
206+ extracted_data = extract_review_request_data (query_teams , query_reviewers , from_time , to_time )
188207
189- if stats_type == "time" :
190208 req_time_index = ReviewRequestData ._fields .index ("req_time" )
191209
192210 def time_key_fn (t ):
193211 d = t [req_time_index ].date ()
194- #d -= datetime.timedelta(days=d.weekday())
195- d -= datetime .timedelta (days = d .day )
196- return ( t [ group_by_index ], d )
212+ #d -= datetime.timedelta(days=d.weekday()) # weekly
213+ d -= datetime .timedelta (days = d .day ) # monthly
214+ return d
197215
198216 found_results = set ()
199217 found_states = set ()
200218 aggrs = []
201- for (group_pk , d ), request_data_items in itertools .groupby (extracted_data , key = time_key_fn ):
202- aggr = aggregate_review_request_stats (request_data_items , count = count )
219+ for d , request_data_items in itertools .groupby (extracted_data , key = time_key_fn ):
220+ raw_aggr = aggregate_raw_review_request_stats (request_data_items , count = count )
221+ aggr = compute_review_request_stats (raw_aggr )
203222
204223 aggrs .append ((d , aggr ))
205224
@@ -225,21 +244,21 @@ def time_key_fn(t):
225244 for slug , label in possible_completion_types
226245 ]
227246
228- selected_completion_type = get_from_selection ("completion" , possible_completion_types )
247+ selected_completion_type = get_choice ("completion" , possible_completion_types )
229248
230249 possible_results = [
231250 (r .slug , r .name , build_review_stats_url (get_overrides = { "completion" : None , "result" : r .slug , "state" : None }))
232251 for r in results
233252 ]
234253
235- selected_result = get_from_selection ("result" , possible_results )
254+ selected_result = get_choice ("result" , possible_results )
236255
237256 possible_states = [
238257 (s .slug , s .name , build_review_stats_url (get_overrides = { "completion" : None , "result" : None , "state" : s .slug }))
239258 for s in states
240259 ]
241260
242- selected_state = get_from_selection ("state" , possible_states )
261+ selected_state = get_choice ("state" , possible_states )
243262
244263 if not selected_completion_type and not selected_result and not selected_state :
245264 selected_completion_type = "completed_in_time"
@@ -261,13 +280,18 @@ def time_key_fn(t):
261280 }])
262281
263282 else : # tabular data
283+ extracted_data = extract_review_request_data (query_teams , query_reviewers , from_time , to_time , ordering = [level ])
264284
265285 data = []
266286
267287 found_results = set ()
268288 found_states = set ()
289+ raw_aggrs = []
269290 for group_pk , request_data_items in itertools .groupby (extracted_data , key = lambda t : t [group_by_index ]):
270- aggr = aggregate_review_request_stats (request_data_items , count = count )
291+ raw_aggr = aggregate_raw_review_request_stats (request_data_items , count = count )
292+ raw_aggrs .append (raw_aggr )
293+
294+ aggr = compute_review_request_stats (raw_aggr )
271295
272296 # skip zero-valued rows
273297 if aggr ["open" ] == 0 and aggr ["completed" ] == 0 and aggr ["not_completed" ] == 0 :
@@ -282,6 +306,12 @@ def time_key_fn(t):
282306
283307 data .append (aggr )
284308
309+ # add totals row
310+ if len (raw_aggrs ) > 1 :
311+ totals = compute_review_request_stats (sum_raw_review_request_aggregations (raw_aggrs ))
312+ totals ["obj" ] = "Totals"
313+ data .append (totals )
314+
285315 results = ReviewResultName .objects .filter (slug__in = found_results )
286316 states = ReviewRequestStateName .objects .filter (slug__in = found_states )
287317
@@ -313,7 +343,7 @@ def time_key_fn(t):
313343
314344 # time options
315345 "possible_teams" : possible_teams ,
316- "selected_team " : selected_team ,
346+ "selected_teams " : selected_teams ,
317347 "possible_completion_types" : possible_completion_types ,
318348 "selected_completion_type" : selected_completion_type ,
319349 "possible_results" : possible_results ,
0 commit comments