1
0
mirror of https://github.com/djohnlewis/stackdump synced 2024-12-04 23:17:37 +00:00

Started implementing the search results view.

This commit is contained in:
Samuel Lai 2011-11-06 17:20:11 +11:00
parent f8a6e7c455
commit 098a4f2fa9
4 changed files with 194 additions and 10 deletions

View File

@ -52,36 +52,91 @@
padding-right: 60px;
}
.available-sites-container {
.site-list-container {
margin-top: 40px;
}
.available-sites {
.site-list {
list-style-image: none;
list-style-type: none;
margin-left: 0;
}
.available-sites li {
.site-list li {
clear: both;
margin-bottom: 16px;
}
.available-sites img {
.site-list img {
float: left;
margin-right: 7px;
}
.available-sites h6 {
.site-list h6 {
padding-top: 7px;
line-height: normal;
margin-left: 55px; /* 48px for the logo, 7px for the padding */
}
.available-sites .tagline {
.site-list .tagline {
padding-top: 3px;
}
.total-hits {
color: #999999;
margin-top: 10px;
}
.total-hits p {
font-size: 16pt;
line-height: 20pt;
}
.stat-value {
font-size: 36pt;
font-weight: bold;
}
#search-results {
list-style-image: none;
list-style-type: none;
margin-left: 0;
}
#search-results li {
clear: both;
border-top: 1px solid #CCCCCC;
}
.post-stats-vertical {
float: left;
width: 64px;
}
.post-stat {
text-align: center;
background-color: #CCCCCC;
margin-bottom: 2px;
padding: 4px 3px;
}
.post-stat p {
margin-bottom: 0;
}
.post-stat-value {
font-weight: bold;
font-size: 16pt;
}
.post-summary {
padding-left: 72px; /* 64px for post-stats-vertical + 8px for padding */
}
.post-details {
float: right;
}
#footer {
margin-top: 50px;
border-top: solid 1px #999999;

View File

@ -2,6 +2,14 @@ import sys
import os
import threading
import functools
import re
try:
# For Python < 2.6 or people using a newer version of simplejson
import simplejson as json
except ImportError:
# For Python >= 2.6
import json
from bottle import route, run, static_file, debug, abort, request, redirect
from jinja2 import Environment, PackageLoader
@ -19,6 +27,21 @@ MEDIA_ROOT = os.path.abspath(BOTTLE_ROOT + '/../../media')
thread_locals = threading.local()
# CUSTOM TEMPLATE TAGS AND FILTERS
def parse_se_tags(value):
'''\
Parses the string of tags as given in the StackExchange XML site dump. The
format is:
<feature-request><filter>
'''
# if it isn't a string, just do nothing
if not isinstance(value, basestring):
return value
return re.findall(r'<([^>]+)>', value)
# RESOURCE DECORATORS
def uses_templates(fn):
@ -39,6 +62,7 @@ def uses_templates(fn):
# template.
extensions=['jinja2.ext.autoescape']
)
thread_locals.template_env.filters['parse_se_tags'] = parse_se_tags
if not fn:
init_templates()
@ -153,6 +177,7 @@ def site_index(site_key):
@route('/search')
@uses_templates
@uses_solr
@uses_db
def search():
# TODO: scrub this first to avoid Solr injection attacks?
query = request.GET.get('q')
@ -164,11 +189,16 @@ def search():
# perform search
results = solr_conn().search(query, start=page*rows_per_page, rows=rows_per_page)
decode_json_fields(results)
context = { }
context['site_root_path'] = ''
context['sites'] = Site.select()
# TODO: scrub this first to avoid HTML injection attacks?
context['query'] = query
context['results'] = results
context['total_hits'] = results.hits
return render_template('results.html', context)
@ -194,6 +224,7 @@ def site_search(site_key):
# perform search
results = solr_conn().search(query, start=page*rows_per_page, rows=rows_per_page)
decode_json_fields(results)
# TODO: scrub this first to avoid HTML injection attacks?
context['query'] = query
@ -239,6 +270,40 @@ def get_template_settings():
return template_settings
def decode_json_fields(obj):
'''\
Looks for keys in obj that end in -json, decodes the corresponding value and
stores that in the key minus -json suffix.
If the obj is only a dict, then wrap it in a list because the we also want
to process list of dicts. If it is not a dict, it is assumed to be a list.\
'''
if obj == None:
return obj
if isinstance(obj, dict):
objs = [ obj ]
else:
objs = obj
for o in objs:
for k in o.keys():
if k.endswith('-json'):
decoded_key = k[:-len('-json')]
json_value = o[k]
if isinstance(json_value, list):
decoded_list = [ ]
for j in json_value:
decoded_list.append(json.loads(j))
o[decoded_key] = decoded_list
else: # assume it is a JSON string
o[decoded_key] = json.loads(json_value)
# remove the JSON string from the dict-object
del o[k]
# END VIEW HELPERS
# INITIALISATION

View File

@ -32,9 +32,9 @@
</div>
</div>
<div class="span4">
<div class="well available-sites-container">
<div class="well site-list-container">
<h3>Available sites</h3>
<ul class="available-sites">
<ul class="site-list">
{% for s in sites %}
<li>
<img src="{{ SETTINGS.APP_URL_ROOT }}media/logos/{{ s.key }}.png" alt="{{ s.name }} logo" />

View File

@ -5,11 +5,75 @@
{% block body %}
<div class="row">
<div class="span16">
<form id="search" method="get" action="{{ SETTINGS.APP_URL_ROOT }}search">
<input type="text" class="xlarge" name="q" value="{{ query }}" />
<input type="submit" class="btn primary" value="Search" />
</form>
<ul class="tabs">
<li class="active"><a href="#">newest</a></li>
<li><a href="#">votes</a></li>
<li><a href="#">relevance</a></li>
</ul>
</div>
</div>
<div class="row">
<div class="span12">
<ul id="search-results">
{% for r in results %}
<li>{{ r }}</li>
<li>
<div class="post-stats-vertical">
<div class="post-stat">
<p class="post-stat-value">{{ r.question.score }}</p>
<p>vote{% if r.question.score != 1 %}s{% endif %}</p>
</div>
<div class="post-stat">
<p class="post-stat-value">{{ r.answer|length }}</p>
<p>answer{% if r.answer|length != 1 %}s{% endif %}</p>
</div>
</div>
<div class="post-summary">
<h3>{{ r.question.title }}</h3>
<p>{{ r.question.body|striptags|truncate(256) }}</p>
<p class="post-details">
Asked by <strong>{{ r.question.ownerUserId }}</strong> on
<strong>{{ r.question.creationDate }}</strong>.
</p>
<div class="post-tags">
{% for t in r.question.tags|parse_se_tags %}
<span class="label">{{ t }}</span>
{% endfor %}
</div>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="span4">
<div class="total-hits">
<p>
<span class="stat-value">{{ total_hits }}</span>
</p>
<p>
posts matched your query <em>"{{ query }}"</em>.
</p>
</div>
<div class="well site-list-container">
<h3>Narrow by site</h3>
<ul class="site-list">
{% for s in sites %}
<li>
<img src="{{ SETTINGS.APP_URL_ROOT }}media/logos/{{ s.key }}.png" alt="{{ s.name }} logo" />
<h6>
<a href="{{ SETTINGS.APP_URL_ROOT }}{{ s.key }}/search?q={{ query }}">{{ s.name }}</a>
<small class="tagline">{{ s.dump_date }}</small>
</h6>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}