Commit 590c397e authored by okhin's avatar okhin

Merge branch 'search' into 'master'

Search

Add search functionnality through haystack and whoosh. And a search tab.

See merge request !2
parents 190cb3a7 6bfc270f
from django import forms
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from haystack.forms import SearchForm
from haystack.query import SearchQuerySet
from bt.models import Violation, COUNTRIES, RESOURCES, TYPES, MEDIA
from bt.multifile import MultiFileField
from operator import itemgetter
......@@ -35,8 +37,32 @@ class AddViolation(forms.Form):
contract_excerpt = forms.CharField(required=False, widget=AdvancedEditor(), label=_('Please copy the relevant section describing the restriction from the user contract. (optional)'))
captcha = CaptchaField(label=_("In order to protect against spam, please fill in the result of the following calculation. (note the + and the * are somewhat confusing)"))
class SearchViolation(forms.Form):
class SearchViolation(SearchForm):
country = forms.ChoiceField(required=True, choices=(('',''),)+tuple(sorted(COUNTRIES,key=itemgetter(1))), label=_("Country"), help_text=_('EU member state where the restriction is reported.'))
operator = forms.CharField(required=True, max_length=256, label=_("Operator"), help_text=_('The ISP or operator providing the Internet service.'))
contract = forms.CharField(required=True, max_length=256, label=_("Contract"), help_text=_('The specific contract at the ISP provider. (please be as specific as possible)'))
media = forms.ChoiceField(required=True, choices=(('',''),)+tuple(sorted(MEDIA,key=itemgetter(1))), label=_('Is the Internet connection over mobile or fixed line?'))
def search(self):
# By default, teh search field is q. So let's check if it's empty
if not self.cleaned_data['q']:
sqs = SearchQuerySet().all()
else:
sqs = super(SearchViolation, self).search()
if not self.is_valid():
return self.no_query_found()
if self.cleaned_data['operator']:
sqs = sqs.filter(operator=self.cleaned_data['operator'])
if self.cleaned_data['contract']:
sqs = sqs.filter(contract=self.cleaned_data['contract'])
if self.cleaned_data['media']:
sqs = sqs.filter(media=self.cleaned_data['media'])
if self.cleaned_data['country']:
sqs = sqs.filter(country=self.cleaned_data['country'])
return sqs
from haystack import indexes
from models import Operator, Violation
class ViolationIndexes(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
operator = indexes.CharField(model_attr="operator_ref")
country = indexes.CharField(model_attr="country")
contract = indexes.CharField(model_attr="contract_excerpt")
type = indexes.BooleanField(model_attr="contractual")
def get_model(self):
return Violation
......@@ -283,14 +283,8 @@ def lookup(request):
if request.method == 'GET':
form = SearchViolation(request.GET)
if form.is_valid():
v=Violation.objects.filter(
country = form.cleaned_data['country'],
operator_ref__name = form.cleaned_data['operator'],
contract = form.cleaned_data['contract'],
media = form.cleaned_data['media'],
activationid = ''
)
res=json.dumps(sorted([(x.id,x.resource_name) for x in v],reverse=True))
v=form.search()
res=json.dumps(sorted([(x.object.id,x.object.resource_name) for x in v],reverse=True))
return HttpResponse(res)
return HttpResponse('')
......
Babel==2.1.1
BabelDjango==0.2.2
BeautifulSoup==3.2.1
defusedxml==0.4.1
Django==1.8.6
django-ajax-selects==1.4.1
django-contrib-comments==1.6.1
django-haystack==2.4.1
django-registration==2.0.3
django-simple-captcha==0.4.6
django-tastypie==0.12.2
......@@ -23,3 +25,4 @@ simplejson==3.8.1
six==1.10.0
South==1.0.2
wheel==0.24.0
Whoosh==2.7.0
......@@ -140,7 +140,8 @@ INSTALLED_APPS = (
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'tastypie',
# 'south',
# Haystack for searching through results
'haystack',
)
TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth",
......@@ -201,6 +202,14 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
DEFAULT_FROM_EMAIL = 'nnmon@nnmon.lqdn.fr'
# HAYSTACK CONFIGURATION
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'),
},
}
try:
from local_settings import *
except:
......
{{ object.country }}
{{ object.operator_ref.name }}
{{ object.type }}
{{ object.media }}
{{ object.resource }} {{object.resource_name }}
{{ object.contract_excerpt }}
{{ object.editorial }}
{% extends 'base.html' %}
{% load bt %}
{% load i18n %}
{% block active_tab_home %}id="current"{% endblock %}
{% block styles %}
<link rel="stylesheet" href="{{ MEDIA_URL }}/css/map.css" type="text/css" />
{% endblock %}
{% block head %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% endblock %}
{% block scripts %}
<script type="text/javascript" src="{{ MEDIA_URL }}/js/jquery.min.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}/js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}/js/picnet.table.filter.min.js"></script>
<script type="text/javascript" src='{{ MEDIA_URL }}/js/d3.min.js'></script>
<script type="text/javascript" src='{{ MEDIA_URL }}/js/topojson.min.js'></script>
<script type="text/javascript" src='{{ MEDIA_URL }}/js/datamaps.js'></script>
<script type="text/javascript" src="{{ MEDIA_URL }}/js/map.js"></script>
<script type="text/javascript">
var data={% if countryweights %}{{countryweights|safe}}{%else%}[]{% endif %};
var country="{{country}}";
$(document).ready(function() {
$.tablesorter.addParser({
// set a unique id
id: 'stateparser',
is: function(s) {
// return false so this parser is not auto detected
return false;
},
format: function(s) {
// format your data for normalization
return s{% for s, translation in status %}.replace(/{{translation}}/,{{forloop.counter}}){% endfor %};
},
// set type, either numeric or text
type: 'numeric'
});
$("#sortedlist").tablesorter({
headers: { 8: { sorter: false },
0: { sorter: 'stateparser' }},
sortList: [[1,0],[0,0],[7,1]],
});
var options = { enableCookies: false };
$('#sortedlist').tableFilter(options);
$('.confirm_form').submit(function() {
var self=this;
var email=$(this).find('input:first').attr('value');
if( email.length>0) {
$.ajax({url: '/confirm/'+$(this).attr('id').slice(1)+'/'+email, success: function(data) { $(self).html(data); }});
} else {
$(this).find('[type=text]').focus();
}
return false;
});
$(".confirm > .button").click(function(){
$(this).parent().parent().parent().find('.info-validate').toggle();
});
$(".cancel-button").click(function(){
$(this).parent().hide();
});
});
</script>
{% endblock %}
{% block content %}
<div id="global">
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% trans "Search through cases" %}
<div id="map"> </div>
<form method="get" action=".">
<table>
{{ form.as_table }}
<tr>
<td>&nbsp;</td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
</form>
{% if query %}
<h3>Results</h3>
<table class="listing tablesorter zebra-striped" id='sortedlist'>
<thead>
<tr>
<th filter-type='ddl'>{% trans "Status" %}</th>
<th filter-type='ddl'>{% trans "country" %}</th>
<th filter-type='ddl'>{% trans "operator" %}</th>
<th filter-type='ddl'>{% trans "contract" %}</th>
<th filter-type='ddl'>{% trans "resource" %}</th>
<th filter-type='ddl'>{% trans "type" %}</th>
<th filter-type='ddl'>{% trans "fixed / wireless" %}</th>
<th filter='false'>{% trans "confirmations" %}</th>
<th filter='false'></th>
</tr>
</thead>
<tbody>
{% for result in page.object_list %}
<tr class="{%if result.object.state%}{{result.object.state}}{%else%}new{%endif%}-status">
<td><a class="cell-link" href="{{ result.object.get_absolute_url }}">{%if result.object.state%}{{result.object.state|status}}{%else%}{% trans "New" %}{%endif%}</a></td>
<td><a class="cell-link" href="{{ result.object.get_absolute_url }}">{{ result.object.country|country }}</a></td>
<td><a class="cell-link" href="{{ result.object.get_absolute_url }}">{{ result.object.operator }}</a></td>
<td><a class="cell-link" href="{{ result.object.get_absolute_url }}">{{ result.object.contract }}</a></td>
<td><a class="cell-link" href="{{ result.object.get_absolute_url }}">{{ result.object.resource_name }}</a></td>
<td><a class="cell-link" href="{{ result.object.get_absolute_url }}">{{ result.object.type|type }}</a></td>
<td><a class="cell-link" href="{{ result.object.get_absolute_url }}">{{ result.object.media|media }}</a></td>
<td>{{ result.object.confirmations }}</td>
<td>
<div class="confirm"><a class="button">{% trans "Me too!" %}</a>
<div class="info-validate float-confirm">
<form method="get" action="" id="i{{ violation.pk }}" class="confirm_form" >
<div>
<label>{% trans "In order to <strong>confirm</strong> this report, please enter your email address" %}</label>
<input type="text" name="email" />
<input type="hidden" value="{{ violation.pk }}" />
<input type="submit" value="{% trans "OK" %}" />
</div>
</form>
<input class="cancel-button" type="button" value="{% trans "Close" %}" />
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}<a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; Previous{% if page.has_previous %}</a>{% endif %}
|
{% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}Next &raquo;{% if page.has_next %}</a>{% endif %}
</div>
{% endif %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</div>
{% endblock %}
......@@ -82,6 +82,8 @@ urlpatterns = patterns('',
include(api_resource.urls)),
url(r'^api/',
include(operator_api_resource.urls)),
url(r'^search/',
include('haystack.urls')),
)
if settings.DEV_SERVER == True:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment