datatracker/ietf/wgcharter/views_search.py
2012-01-24 17:17:24 +00:00

297 lines
12 KiB
Python

# Copyright The IETF Trust 2011, All Rights Reserved
import re, os
import datetime
from django import forms
from django.shortcuts import render_to_response, redirect
from django.db.models import Q
from django.template import RequestContext
from django.views.decorators.cache import cache_page
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponsePermanentRedirect
from django.conf import settings
from django.utils import simplejson
from ietf.doc.models import Document, State
from ietf.name.models import GroupStateName
from ietf.group.models import Group
from ietf.person.models import Person, Email
from ietf.doc.utils import augment_with_telechat_date
class SearchForm(forms.Form):
nameacronym = forms.CharField(required=False)
inprocess = forms.BooleanField(required=False,initial=True)
active = forms.BooleanField(required=False,initial=False)
concluded = forms.BooleanField(required=False, initial=False)
by = forms.ChoiceField(choices=[(x,x) for x in ('acronym','state','ad','area','anyfield', 'eacronym')], required=False, initial='wg', label='Foobar')
state = forms.ModelChoiceField(GroupStateName.objects.all(), label="WG state", empty_label="any state", required=False)
charter_state = forms.ModelChoiceField(State.objects.filter(type="charter"), label="Charter state", empty_label="any state", required=False)
ad = forms.ChoiceField(choices=(), required=False)
area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), empty_label="any area", required=False)
anyfield= forms.CharField(required=False)
eacronym = forms.CharField(required=False)
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
responsible = Document.objects.values_list('ad', flat=True).distinct()
active_ads = list(Person.objects.filter(email__role__name="ad",
email__role__group__type="area",
email__role__group__state="active").distinct())
inactive_ads = list(Person.objects.filter(pk__in=responsible)
.exclude(pk__in=[x.pk for x in active_ads]))
extract_last_name = lambda x: x.name_parts()[3]
active_ads.sort(key=extract_last_name)
inactive_ads.sort(key=extract_last_name)
self.fields['ad'].choices = c = [('', 'any AD')] + [(ad.pk, ad.plain_name()) for ad in active_ads] + [('', '------------------')] + [(ad.pk, ad.name) for ad in inactive_ads]
def clean_nameacronym(self):
value = self.cleaned_data.get('nameacronym','')
return value
def clean(self):
q = self.cleaned_data
# Reset query['by'] if needed
for k in ('ad', 'area', 'anyfield', 'eacronym'):
if (q['by'] == k) and not q[k]:
q['by'] = None
if (q['by'] == 'state') and not (q.get('state') or q.get('charter_state')):
q['by'] = None
# Reset other fields
for k in ('ad', 'area', 'anyfield', 'eacronym'):
if q['by'] != k:
self.data[k] = ""
q[k] = ""
if q['by'] != 'state':
self.data['state'] = ""
self.data['charter_state'] = ""
q['state'] = ""
q['charter_state'] = ""
return q
def search_query(query_original, sort_by=None):
query = dict(query_original.items())
# Non-ASCII strings don't match anything; this check
# is currently needed to avoid complaints from MySQL.
for k in ['nameacronym','anyfield','eacronym']:
try:
tmp = str(query.get(k, ''))
except:
query[k] = '*NOSUCH*'
# Search
MAX = 500
maxReached = False
q_obj = Q(type__slug="wg", state__slug__in=("proposed", "active", "conclude"))
s_obj = Q()
if query["inprocess"]:
s_obj |= Q(charter__states__type="charter", charter__states__slug__in=("infrev", "intrev", "extrev", "iesgrev")) & Q(state__slug__in=("proposed", "active"))
if query["active"]:
s_obj |= Q(charter__states__type="charter", charter__states__slug="approved") & Q(state__slug="active")
if query["concluded"]:
s_obj |= Q(state__slug="conclude") | Q(charter__states__type="charter", charter__states__slug="notrev")
results = Group.objects.filter(q_obj & s_obj).select_related("charter")
prefix = ""
q_objs = []
# name
if query["nameacronym"]:
results = results.filter(Q(name__icontains=query["nameacronym"]) | Q(acronym__icontains=query["nameacronym"]))
# radio choices
by = query["by"]
if by == "state":
q_objs = []
if query['state']:
q_objs.append(Q(state=query['state']))
if query['charter_state']:
q_objs.append(Q(charter__states__type="charter", charter__states__slug=query['charter_state']))
results = results.filter(*q_objs)
elif by == "ad":
results = results.filter(ad=query["ad"])
elif by == "area":
results = results.filter(parent=query["area"])
elif by == "anyfield":
q_obj = Q()
q_obj |= Q(state__name__icontains=query['anyfield'])
q_obj |= Q(charter__states__type="charter", charter__states__name__icontains=query['anyfield'])
q_obj |= Q(ad__name__icontains=query['anyfield'])
q_obj |= Q(parent__name__icontains=query['anyfield'])
q_obj |= Q(history_set__acronym__icontains=query['anyfield'])
results = list(results.filter(q_obj))
# Search charter texts
m = re.compile(query['anyfield'], re.IGNORECASE)
if query['nameacronym']:
file_set = Group.objects.filter(type="wg", name__icontains=query["nameacronym"])
else:
file_set = Group.objects.filter(type="wg")
for g in file_set:
charter = g.charter
if charter:
try:
file = open(os.path.join(charter.get_file_path(), charter.name+"-"+charter.rev+".txt"))
for line in file:
if m.search(line):
results.append(g)
break
except IOError:
pass # Pass silently for files not found
elif by == "eacronym":
results = results.filter(history_set__acronym__icontains=query["eacronym"]).distinct()
results = list(results[:MAX])
if len(results) == MAX:
maxReached = True
# sort
def sort_key(g):
res = []
if sort_by == "acronym":
res.append(g.acronym)
elif sort_by == "name":
res.append(g.name)
elif sort_by == "date":
res.append(str(g.time or datetime.date(1990, 1, 1)))
elif sort_by == "status":
if g.charter:
s = g.charter.get_state()
if s:
res.append(s.order)
# Sort secondary by group state
res.append(g.state.name)
return res
results.sort(key=sort_key)
meta = {}
if maxReached:
meta['max'] = MAX
if query['by']:
meta['advanced'] = True
augment_with_telechat_date([r.charter for r in results])
return (results,meta)
def generate_query_string(request, ignore_list):
"""Recreates the parameter string from the given request, and
returns it as a string.
Any parameter names present in ignore_list shall not be put
in the result string.
"""
params = []
for i in request.GET:
if not i in ignore_list:
params.append(i + "=" + request.GET[i])
return "?" + "&".join(params)
def search_results(request):
if len(request.REQUEST.items()) == 0:
return search_main(request)
form = SearchForm(dict(request.REQUEST.items()))
if not form.is_valid():
return HttpResponseBadRequest("form not valid?", mimetype="text/plain")
sort_by = None
if "sortBy" in request.GET:
sort_by = request.GET["sortBy"]
(results,meta) = search_query(form.cleaned_data, sort_by)
meta['searching'] = True
meta['by'] = form.cleaned_data['by']
meta['rqps'] = generate_query_string(request, ['sortBy'])
# With a later Django we can do this from the template (incude with tag)
# Pass the headers and their sort key names
meta['hdrs'] = [{'htitle': 'Acronym', 'htype':'acronym'},
{'htitle': 'Name', 'htype':'name'},
{'htitle': 'Date', 'htype':'date'},
{'htitle': 'Status', 'htype':'status', 'colspan':'2'},
]
if 'ajax' in request.REQUEST and request.REQUEST['ajax']:
return render_to_response('wgcharter/search_results.html', {'recs':results, 'meta':meta}, context_instance=RequestContext(request))
elif len(results) == 1:
wg = results[0]
return redirect('wg_view', name=wg.acronym)
else:
return render_to_response('wgcharter/search_main.html', {'form':form, 'recs':results,'meta':meta}, context_instance=RequestContext(request))
def search_main(request):
form = SearchForm()
return render_to_response('wgcharter/search_main.html', {'form':form}, context_instance=RequestContext(request))
def by_area(request, name):
area_id = None
area_name = None
for a in Group.objects.filter(type="area"):
if name == a.acronym:
area_id = a.id
area_name = a.name
break
if not area_id:
raise Http404
form = SearchForm({'inprocess': True, 'active': True, 'concluded': True, 'by':'area','area':area_id})
if not form.is_valid():
raise ValueError("form did not validate")
(results,meta) = search_query(form.cleaned_data)
meta['searching'] = True
meta['by'] = form.cleaned_data['by']
meta['rqps'] = generate_query_string(request, ['sortBy'])
# With a later Django we can do this from the template (incude with tag)
# Pass the headers and their sort key names
meta['hdrs'] = [{'htitle': 'Acronym', 'htype':'acronym'},
{'htitle': 'Name', 'htype':'name'},
{'htitle': 'Date', 'htype':'date'},
{'htitle': 'Status', 'htype':'status', 'colspan':'2'},
]
fresults = []
for r in results:
if r.state_id == "proposed" and r.charter.get_state_slug() == "notrev":
if r.charter.latest_event(desc__icontains="abandoned"):
if r.charter.latest_event(desc__icontains="abandoned").time > datetime.datetime.now() - datetime.timedelta(days=31):
# Abandoned recently
fresults.append(r)
else:
if not r.state_id == "conclude":
fresults.append(r)
fresults.sort(key=lambda g: str(g.time or datetime.date(1990, 1, 1)), reverse=True)
return render_to_response('wgcharter/by_area.html', {'form':form, 'recs':fresults,'meta':meta, 'area_name':area_name}, context_instance=RequestContext(request))
def in_process(request):
results = Group.objects.filter(type="wg",
charter__states__slug__in=['infrev', 'intrev', 'extrev', 'iesgrev'],
charter__states__type="charter").order_by('-time').select_related("charter")
augment_with_telechat_date([r.charter for r in results])
meta = {}
meta['searching'] = True
meta['by'] = 'state'
meta['rqps'] = generate_query_string(request, ['sortBy'])
# With a later Django we can do this from the template (incude with tag)
# Pass the headers and their sort key names
meta['hdrs'] = [{'htitle': 'Acronym', 'htype':'acronym'},
{'htitle': 'Name', 'htype':'name'},
{'htitle': 'Date', 'htype':'date'},
{'htitle': 'Status', 'htype':'status', 'colspan':'2'},
]
return render_to_response('wgcharter/in_process.html', {'recs':results,'meta':meta}, context_instance=RequestContext(request))
def json_emails(l):
result = []
for p in l:
result.append({"id": p.address + "", "name": p.person.plain_name() + " <" + p.address + ">"})
return simplejson.dumps(result)
def search_person(request):
if request.method == 'GET':
emails = Email.objects.filter(person__name__istartswith=request.GET.get('q','')).order_by('person__name')
return HttpResponse(json_emails(emails), mimetype='application/json')