diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index d2450fa62bf..e54cfd76e81 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -779,3 +779,10 @@ def is_valid_url(url): except ValidationError: return False return True + +@register.filter +def get_hash(h, key): + """ + Get a key from hash + """ + return h[key] diff --git a/ietf/doc/urls.py b/ietf/doc/urls.py index ad8ee81b214..397901aaf66 100644 --- a/ietf/doc/urls.py +++ b/ietf/doc/urls.py @@ -50,7 +50,7 @@ url(r'^$', views_search.search), url(r'^search/?$', views_search.search), url(r'^in-last-call/?$', views_search.drafts_in_last_call), - url(r'^ad/(?P[^/]+)/?$', views_search.docs_for_ad), + url(r'^ad/(?:(?P[^/]+)/)?$', views_search.docs_for_ad), url(r'^ad2/(?P[\w.-]+)/$', RedirectView.as_view(url='/doc/ad/%(name)s/', permanent=True)), url(r'^rfc-status-changes/?$', views_status_change.rfc_status_changes), url(r'^start-rfc-status-change/(?:%(name)s/)?$' % settings.URL_REGEXPS, views_status_change.start_rfc_status_change), diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py index 7265964e155..0f2494d259f 100644 --- a/ietf/doc/views_search.py +++ b/ietf/doc/views_search.py @@ -307,6 +307,32 @@ def cached_redirect(cache_key, url): return cached_redirect(cache_key, urlreverse('ietf.doc.views_search.search') + search_args) +def ad_dashboard_group_type(doc): + # Return group type for document for dashboard. + # If doc is not defined return list of all possible + # group types + if not doc: + return ('I-D', 'RFC', 'Conflict Review', 'Status Change', 'Charter') + if doc.type.slug=='draft': + if doc.get_state_slug('draft') == 'rfc': + return 'RFC' + elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg') and doc.get_state('draft-iesg').name in ('RFC Ed Queue'): + return 'RFC' + elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg') and doc.get_state('draft-iesg').name in ('Dead', 'I-D Exists', 'AD is watching'): + return None + elif doc.get_state('draft').name in ('Expired', 'Replaced'): + return None + else: + return 'I-D' + elif doc.type.slug=='conflrev': + return 'Conflict Review' + elif doc.type.slug=='statchg': + return 'Status Change' + elif doc.type.slug=='charter': + return "Charter" + else: + return "Document" + def ad_dashboard_group(doc): if doc.type.slug=='draft': @@ -395,14 +421,106 @@ def ad_dashboard_sort_key(doc): def docs_for_ad(request, name): ad = None + ads = [] responsible = Document.objects.values_list('ad', flat=True).distinct() for p in Person.objects.filter(Q(role__name__in=("pre-ad", "ad"), role__group__type="area", role__group__state="active") | Q(pk__in=responsible)).distinct(): - if name == p.full_name_as_key(): - ad = p - break + if not name: + if p in get_active_ads(): + ads.append(p) + else: + if name == p.full_name_as_key(): + ad = p + break + if not name: + doctypes = list(DocTypeName.objects.filter(used=True).exclude(slug='draft').values_list("pk", flat=True)) + + group_types = ad_dashboard_group_type(None) + + groups = {} + group_names = {} + for g in group_types: + groups[g] = {} + group_names[g] = [] + + # Prefill groups in preferred sort order + id = 0 + for g in [ + 'Publication Requested Internet-Draft', + 'Waiting for Writeup Internet-Draft', + 'AD Evaluation Internet-Draft', + 'In Last Call Internet-Draft', + 'IESG Evaluation - Defer Internet-Draft', + 'IESG Evaluation Internet-Draft', + 'Waiting for AD Go-Ahead Internet-Draft', + 'Approved-announcement to be sent Internet-Draft', + 'Approved-announcement sent Internet-Draft']: + groups['I-D'][g] = id + group_names['I-D'].append(g) + id += 1; + id = 0 + for g in ['RFC Ed Queue Internet-Draft', 'RFC']: + groups['RFC'][g] = id + group_names['RFC'].append(g) + id += 1; + id = 0 + for g in ['AD Review Conflict Review', + 'Needs Shepherd Conflict Review', + 'IESG Evaluation Conflict Review', + 'Approved Conflict Review', + 'Withdrawn Conflict Review']: + groups['Conflict Review'][g] = id + group_names['Conflict Review'].append(g) + id += 1; + id = 0 + for g in [ 'Start Chartering/Rechartering (Internal Steering Group/IAB Review) Charter', + 'Replaced Charter', + 'Approved Charter', + 'Not currently under review Charter']: + groups['Charter'][g] = id + group_names['Charter'].append(g) + id += 1; + + for ad in ads: + form = SearchForm({'by':'ad','ad': ad.id, + 'rfcs':'on', 'activedrafts':'on', + 'olddrafts':'on', + 'doctypes': doctypes}) + data = retrieve_search_results(form) + ad.dashboard = urlreverse("ietf.doc.views_search.docs_for_ad") + ad.full_name_as_key() + counts = {} + for g in group_types: + counts[g] = [] + for doc in data: + group_type = ad_dashboard_group_type(doc) + if group_type: + group = ad_dashboard_group(doc) + if group not in groups[group_type]: + groups[group_type][group] = len(groups[group_type]) + group_names[group_type].append(group) + if len(counts[group_type]) < len(groups[group_type]): + counts[group_type].extend([0] * (len(groups[group_type]) - len(counts[group_type]))) + counts[group_type][groups[group_type][group]] += 1 + ad.counts = counts + for ad in ads: + for group_type in group_types: + if len(ad.counts[group_type]) < len(groups[group_type]): + ad.counts[group_type].extend([0] * (len(groups[group_type]) - len(ad.counts[group_type]))) + # Shorten the names of groups + for gt in group_types: + for idx,g in enumerate(group_names[gt]): + for s in [' Internet-Draft', ' Charter', ' Conflict Review', ' Status Change', ' (Internal Steering Group/IAB Review) Charter']: + if g.endswith(s): + group_names[gt][idx] = g[:-len(s)] + return render(request, 'doc/ad_list.html', { + 'ads': ads, + 'group_types': group_types, + 'group_names': group_names, + 'groups': groups + }) + if not ad: raise Http404 form = SearchForm({'by':'ad','ad': ad.id, diff --git a/ietf/templates/doc/ad_list.html b/ietf/templates/doc/ad_list.html new file mode 100644 index 00000000000..f3226bb6a8e --- /dev/null +++ b/ietf/templates/doc/ad_list.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} +{# Copyright The IETF Trust 2015, All Rights Reserved #} +{% load origin static %} +{% load ietf_filters %} +{% block pagehead %} + +{% endblock %} +{% block title %}Area directors{% endblock %} +{% block content %} +{% origin %} +

Area Directors Workload

+{% for gt in group_types %} +

{{ gt }}

+ + + + + {% for g in group_names|get_hash:gt %} + + {% endfor %} + + + + {% for ad in ads %} + + + {% for c in ad.counts|get_hash:gt %} + {% if forloop.counter0 < groups|get_hash:gt|length %} + + {% endfor %} + +
Name + {{ g }}
{{ ad.name }}{{ c }} + {% endif %} + {% endfor %} +
+{% endfor %} +{% endblock %} +{% block js %} + +{% endblock %}