Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 66 additions & 45 deletions ietf/doc/views_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
import copy
import operator

from collections import defaultdict
from functools import reduce

from django import forms
from django.conf import settings
from django.core.cache import cache, caches
Expand Down Expand Up @@ -360,32 +362,52 @@ def cached_redirect(cache_key, url):
return cached_redirect(cache_key, urlreverse('ietf.doc.views_search.search') + search_args)


def state_name(doc_type, state, shorten=True):
name = ""
# Note doc_type rfc here is _not_ necessarily Document.type - for some callers
# it is a type derived from draft... The ad_workload view needs more rework so that
# the code isn't having to shadow-box so much.
if doc_type == "rfc":
if state == "rfc":
name = "RFC"
if name == "":
s = State.objects.filter(type="rfc",slug=state).first()
if s:
name = s.name
if name == "":
name = State.objects.get(type__in=["draft", "draft-iesg"], slug=state).name
elif doc_type == "draft" and state not in ["rfc", "expired"]:
name = State.objects.get(type__in=["draft", "draft-iesg"], slug=state).name
elif doc_type == "draft" and state == "rfc":
name = "RFC"
elif doc_type == "conflrev" and state.startswith("appr"):
name = "Approved"
else:
name = State.objects.get(type=doc_type, slug=state).name
def get_state_name_calculator():
"""Get a function to calculate state names

Queries the database once when called, then uses cached look-up table for name calculations.
"""
# state_lut always has at least rfc, draft, and draft-iesg keys
state_lut = defaultdict(dict, **{"rfc": {}, "draft":{}, "draft-iesg": {}})
for state in State.objects.filter(used=True):
state_lut[state.type_id][state.slug] = state.name
state_lut = dict(state_lut) # convert to dict to freeze key changes

def _get_state_name(doc_type, state_slug):
"""Get display name for a doc type / state slug

Note doc_type rfc here is _not_ necessarily Document.type - for some callers
it is a type derived from draft... The ad_workload view needs more rework so that
the code isn't having to shadow-box so much.
"""
if doc_type == "rfc":
if state_slug == "rfc":
return "RFC"
elif state_slug in state_lut["rfc"]:
return state_lut["rfc"][state_slug]
else:
return state_lut["draft"].get(
state_slug,
state_lut["draft-iesg"][state_slug],
)
elif doc_type == "draft" and state_slug not in ["rfc", "expired"]:
return state_lut["draft"].get(
state_slug,
state_lut["draft-iesg"][state_slug],
)
elif doc_type == "draft" and state_slug == "rfc":
return "RFC"
elif doc_type == "conflrev" and state_slug.startswith("appr"):
return "Approved"
else:
return state_lut[doc_type][state_slug]

# return the function as a closure
return _get_state_name

if not shorten:
return name

def shorten_state_name(name):
"""Get abbreviated display name for a state"""
for pat, sub in [
(r" \(Internal Steering Group/IAB Review\)", ""),
("Writeup", "Write-up"),
Expand All @@ -412,31 +434,27 @@ def state_name(doc_type, state, shorten=True):
(r"\(Message to Community, Selected by Secretariat\)", ""),
]:
name = re.sub(pat, sub, name)

return name.strip()


STATE_SLUGS = {
dt: {state_name(dt, ds, shorten=False): ds for ds in AD_WORKLOAD[dt]} # type: ignore
for dt in AD_WORKLOAD
}


def state_to_doc_type(state):
for dt in STATE_SLUGS:
if state in STATE_SLUGS[dt]:
return dt
return None


IESG_STATES = State.objects.filter(type="draft-iesg").values_list("name", flat=True)


def date_to_bucket(date, now, num_buckets):
return num_buckets - int((now.date() - date.date()).total_seconds() / 60 / 60 / 24)


def ad_workload(request):
_calculate_state_name = get_state_name_calculator()
IESG_STATES = State.objects.filter(type="draft-iesg").values_list("name", flat=True)
STATE_SLUGS = {
dt: {_calculate_state_name(dt, ds): ds for ds in AD_WORKLOAD[dt]} # type: ignore
for dt in AD_WORKLOAD.keys()
}

def _state_to_doc_type(state):
for dt in STATE_SLUGS:
if state in STATE_SLUGS[dt]:
return dt
return None

# number of days (= buckets) to show in the graphs
days = 120 if has_role(request.user, ["Area Director", "Secretariat"]) else 1
now = timezone.now()
Expand Down Expand Up @@ -483,7 +501,7 @@ def ad_workload(request):
to_state = None
if dt == "charter":
if e.type == "closed_ballot":
to_state = state_name(dt, state, shorten=False)
to_state = _calculate_state_name(dt, state)
elif e.desc.endswith("has been replaced"):
# stop tracking
last = e.time
Expand Down Expand Up @@ -512,7 +530,7 @@ def ad_workload(request):
to_state = "RFC"

if dt == "rfc":
new_dt = state_to_doc_type(to_state)
new_dt = _state_to_doc_type(to_state)
if new_dt is not None and new_dt != dt:
dt = new_dt

Expand Down Expand Up @@ -549,7 +567,9 @@ def ad_workload(request):
metadata = [
{
"type": (dt, doc_type_name(dt)),
"states": [(state, state_name(dt, state)) for state in ad.buckets[dt]],
"states": [
(state, shorten_state_name(_calculate_state_name(dt, state))) for state in ad.buckets[dt]
],
"ads": ads,
}
for dt in AD_WORKLOAD
Expand Down Expand Up @@ -616,9 +636,10 @@ def sort_key(doc):
)
]

_calculate_state_name = get_state_name_calculator()
for d in results:
dt = d.type.slug
d.search_heading = state_name(dt, doc_state(d), shorten=False)
d.search_heading = _calculate_state_name(dt, doc_state(d))
if d.search_heading != "RFC":
d.search_heading += f" {doc_type_name(dt)}"

Expand Down