Skip to content

Commit 197bc07

Browse files
committed
Refactor search-related utilities slightly to make them more
independent of the search form, to enable them to be reused in the community lists. Also clean up the related code a bit, use SearchForm to handle other document types, and fix missing ids in the HTML so that one can click the "by" labels to hit the corresponding radio button. - Legacy-Id: 10729
1 parent d67a96b commit 197bc07

6 files changed

Lines changed: 224 additions & 217 deletions

File tree

ietf/doc/utils_search.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
from ietf.doc.models import Document, DocAlias, RelatedDocument, DocEvent, TelechatDocEvent
2+
from ietf.doc.expire import expirable_draft
3+
from ietf.community.utils import augment_docs_with_tracking_info
4+
5+
def wrap_value(v):
6+
return lambda: v
7+
8+
def fill_in_document_table_attributes(docs):
9+
# fill in some attributes for the document table results to save
10+
# some hairy template code and avoid repeated SQL queries
11+
12+
docs_dict = dict((d.pk, d) for d in docs)
13+
doc_ids = docs_dict.keys()
14+
15+
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=doc_ids).values_list("document_id", "name"))
16+
17+
# latest event cache
18+
event_types = ("published_rfc",
19+
"changed_ballot_position",
20+
"started_iesg_process",
21+
"new_revision")
22+
for d in docs:
23+
d.latest_event_cache = dict()
24+
for e in event_types:
25+
d.latest_event_cache[e] = None
26+
27+
for e in DocEvent.objects.filter(doc__in=doc_ids, type__in=event_types).order_by('time'):
28+
docs_dict[e.doc_id].latest_event_cache[e.type] = e
29+
30+
# telechat date, can't do this with above query as we need to get TelechatDocEvents out
31+
seen = set()
32+
for e in TelechatDocEvent.objects.filter(doc__in=doc_ids, type="scheduled_for_telechat").order_by('-time'):
33+
if e.doc_id not in seen:
34+
d = docs_dict[e.doc_id]
35+
d.telechat_date = wrap_value(d.telechat_date(e))
36+
seen.add(e.doc_id)
37+
38+
# misc
39+
for d in docs:
40+
# emulate canonical name which is used by a lot of the utils
41+
d.canonical_name = wrap_value(rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name)
42+
43+
if d.rfc_number() != None and d.latest_event_cache["published_rfc"]:
44+
d.latest_revision_date = d.latest_event_cache["published_rfc"].time
45+
elif d.latest_event_cache["new_revision"]:
46+
d.latest_revision_date = d.latest_event_cache["new_revision"].time
47+
else:
48+
d.latest_revision_date = d.time
49+
50+
if d.type_id == "draft":
51+
if d.get_state_slug() == "rfc":
52+
d.search_heading = "RFC"
53+
elif d.get_state_slug() in ("ietf-rm", "auth-rm"):
54+
d.search_heading = "Withdrawn Internet-Draft"
55+
else:
56+
d.search_heading = "%s Internet-Draft" % d.get_state()
57+
else:
58+
d.search_heading = "%s" % (d.type,);
59+
60+
d.expirable = expirable_draft(d)
61+
62+
if d.get_state_slug() != "rfc":
63+
d.milestones = d.groupmilestone_set.filter(state="active").order_by("time").select_related("group")
64+
65+
66+
67+
# RFCs
68+
69+
# errata
70+
erratas = set(Document.objects.filter(tags="errata", name__in=rfc_aliases.keys()).distinct().values_list("name", flat=True))
71+
for d in docs:
72+
d.has_errata = d.name in erratas
73+
74+
# obsoleted/updated by
75+
for a in rfc_aliases:
76+
d = docs_dict[a]
77+
d.obsoleted_by_list = []
78+
d.updated_by_list = []
79+
80+
xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(),
81+
relationship__in=("obs", "updates")).select_related('target__document_id')
82+
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
83+
document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name'))
84+
for rel in xed_by:
85+
d = docs_dict[rel.target.document_id]
86+
if rel.relationship_id == "obs":
87+
l = d.obsoleted_by_list
88+
elif rel.relationship_id == "updates":
89+
l = d.updated_by_list
90+
l.append(rel_rfc_aliases[rel.source_id].upper())
91+
l.sort()
92+
93+
94+
def prepare_document_table(request, docs, query=None, max_results=500):
95+
"""Take a queryset of documents and a QueryDict with sorting info
96+
and return list of documents with attributes filled in for
97+
displaying a full table of information about the documents, plus
98+
dict with information about the columns."""
99+
100+
if not isinstance(docs, list):
101+
# evaluate and fill in attribute results immediately to decrease
102+
# the number of queries
103+
docs = docs.select_related("ad", "ad__person", "std_level", "intended_std_level", "group", "stream")
104+
docs = docs.prefetch_related("states__type", "tags")
105+
106+
docs = list(docs[:max_results])
107+
108+
fill_in_document_table_attributes(docs)
109+
augment_docs_with_tracking_info(docs, request.user)
110+
111+
meta = {}
112+
113+
sort_key = query and query.get('sort')
114+
115+
# sort
116+
def sort_key(d):
117+
res = []
118+
119+
rfc_num = d.rfc_number()
120+
121+
122+
if d.type_id == "draft":
123+
res.append(["Active", "Expired", "Replaced", "Withdrawn", "RFC"].index(d.search_heading.split()[0]))
124+
else:
125+
res.append(d.type_id);
126+
res.append("-");
127+
res.append(d.get_state_slug());
128+
res.append("-");
129+
130+
if sort_key == "title":
131+
res.append(d.title)
132+
elif sort_key == "date":
133+
res.append(str(d.latest_revision_date))
134+
elif sort_key == "status":
135+
if rfc_num != None:
136+
res.append(int(rfc_num))
137+
else:
138+
res.append(d.get_state().order if d.get_state() else None)
139+
elif sort_key == "ipr":
140+
res.append(len(d.ipr()))
141+
elif sort_key == "ad":
142+
if rfc_num != None:
143+
res.append(int(rfc_num))
144+
elif d.get_state_slug() == "active":
145+
if d.get_state("draft-iesg"):
146+
res.append(d.get_state("draft-iesg").order)
147+
else:
148+
res.append(0)
149+
else:
150+
if rfc_num != None:
151+
res.append(int(rfc_num))
152+
else:
153+
res.append(d.canonical_name())
154+
155+
return res
156+
157+
docs.sort(key=sort_key)
158+
159+
# fill in a meta dict with some information for rendering the table
160+
if len(docs) == max_results:
161+
meta['max'] = max_results
162+
163+
meta['headers'] = [{'title': 'Document', 'key':'document'},
164+
{'title': 'Title', 'key':'title'},
165+
{'title': 'Date', 'key':'date'},
166+
{'title': 'Status', 'key':'status'},
167+
{'title': 'IPR', 'key':'ipr'},
168+
{'title': 'AD / Shepherd', 'key':'ad'}]
169+
170+
if query and hasattr(query, "urlencode"): # fed a Django QueryDict
171+
d = query.copy()
172+
for h in meta['headers']:
173+
d["sort"] = h["key"]
174+
h["sort_url"] = "?" + d.urlencode()
175+
if h['key'] == sort_key:
176+
h['sorted'] = True
177+
178+
return (docs, meta)
179+
180+

0 commit comments

Comments
 (0)