summaryrefslogtreecommitdiff
path: root/searx/webapp.py
diff options
context:
space:
mode:
Diffstat (limited to 'searx/webapp.py')
-rw-r--r--searx/webapp.py145
1 files changed, 118 insertions, 27 deletions
diff --git a/searx/webapp.py b/searx/webapp.py
index 89d288e73..f66466b35 100644
--- a/searx/webapp.py
+++ b/searx/webapp.py
@@ -17,6 +17,10 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
(C) 2013- by Adam Tauber, <asciimoo@gmail.com>
'''
+from gevent import monkey
+monkey.patch_all()
+
+
if __name__ == '__main__':
from sys import path
from os.path import realpath, dirname
@@ -35,19 +39,29 @@ from flask import (
from flask.ext.babel import Babel, gettext, format_date
from searx import settings, searx_dir
from searx.engines import (
- search as do_search, categories, engines, get_engines_stats,
- engine_shortcuts
+ categories, engines, get_engines_stats, engine_shortcuts
)
-from searx.utils import UnicodeWriter, highlight_content, html_to_text
+from searx.utils import (
+ UnicodeWriter, highlight_content, html_to_text, get_themes
+)
+from searx.https_rewrite import https_rules
from searx.languages import language_codes
from searx.search import Search
+from searx.query import Query
from searx.autocomplete import backends as autocomplete_backends
+static_path, templates_path, themes =\
+ get_themes(settings['themes_path']
+ if settings.get('themes_path')
+ else searx_dir)
+default_theme = settings['default_theme'] if \
+ settings.get('default_theme', None) else 'default'
+
app = Flask(
__name__,
- static_folder=os.path.join(searx_dir, 'static'),
- template_folder=os.path.join(searx_dir, 'templates')
+ static_folder=static_path,
+ template_folder=templates_path
)
app.secret_key = settings['server']['secret_key']
@@ -90,7 +104,32 @@ def get_base_url():
return hostname
-def render(template_name, **kwargs):
+def get_current_theme_name(override=None):
+ """Returns theme name.
+
+ Checks in this order:
+ 1. override
+ 2. cookies
+ 3. settings"""
+
+ if override and override in themes:
+ return override
+ theme_name = request.args.get('theme',
+ request.cookies.get('theme',
+ default_theme))
+ if theme_name not in themes:
+ theme_name = default_theme
+ return theme_name
+
+
+def url_for_theme(endpoint, override_theme=None, **values):
+ if endpoint == 'static' and values.get('filename', None):
+ theme_name = get_current_theme_name(override=override_theme)
+ values['filename'] = "{}/{}".format(theme_name, values['filename'])
+ return url_for(endpoint, **values)
+
+
+def render(template_name, override_theme=None, **kwargs):
blocked_engines = request.cookies.get('blocked_engines', '').split(',')
autocomplete = request.cookies.get('autocomplete')
@@ -113,19 +152,31 @@ def render(template_name, **kwargs):
if not 'selected_categories' in kwargs:
kwargs['selected_categories'] = []
+ for arg in request.args:
+ if arg.startswith('category_'):
+ c = arg.split('_', 1)[1]
+ if c in categories:
+ kwargs['selected_categories'].append(c)
+ if not kwargs['selected_categories']:
cookie_categories = request.cookies.get('categories', '').split(',')
for ccateg in cookie_categories:
if ccateg in categories:
kwargs['selected_categories'].append(ccateg)
- if not kwargs['selected_categories']:
- kwargs['selected_categories'] = ['general']
+ if not kwargs['selected_categories']:
+ kwargs['selected_categories'] = ['general']
if not 'autocomplete' in kwargs:
kwargs['autocomplete'] = autocomplete
kwargs['method'] = request.cookies.get('method', 'POST')
- return render_template(template_name, **kwargs)
+ # override url_for function in templates
+ kwargs['url_for'] = url_for_theme
+
+ kwargs['theme'] = get_current_theme_name(override=override_theme)
+
+ return render_template(
+ '{}/{}'.format(kwargs['theme'], template_name), **kwargs)
@app.route('/search', methods=['GET', 'POST'])
@@ -148,16 +199,23 @@ def index():
'index.html',
)
- # TODO moar refactor - do_search integration into Search class
- search.results, search.suggestions = do_search(search.query,
- request,
- search.engines,
- search.pageno,
- search.lang)
+ search.results, search.suggestions = search.search(request)
for result in search.results:
+
if not search.paging and engines[result['engine']].paging:
search.paging = True
+
+ if settings['server']['https_rewrite']\
+ and result['parsed_url'].scheme == 'http':
+
+ for http_regex, https_url in https_rules:
+ if http_regex.match(result['url']):
+ result['url'] = http_regex.sub(https_url, result['url'])
+ # TODO result['parsed_url'].scheme
+ break
+
+ # HTTPS rewrite
if search.request_data.get('format', 'html') == 'html':
if 'content' in result:
result['content'] = highlight_content(result['content'],
@@ -170,6 +228,7 @@ def index():
# removing html content and whitespace duplications
result['title'] = ' '.join(html_to_text(result['title'])
.strip().split())
+
if len(result['url']) > 74:
url_parts = result['url'][:35], result['url'][-35:]
result['pretty_url'] = u'{0}[...]{1}'.format(*url_parts)
@@ -232,7 +291,8 @@ def index():
paging=search.paging,
pageno=search.pageno,
base_url=get_base_url(),
- suggestions=search.suggestions
+ suggestions=search.suggestions,
+ theme=get_current_theme_name()
)
@@ -249,24 +309,46 @@ def autocompleter():
"""Return autocompleter results"""
request_data = {}
+ # select request method
if request.method == 'POST':
request_data = request.form
else:
request_data = request.args
- # TODO fix XSS-vulnerability
- query = request_data.get('q', '').encode('utf-8')
+ # set blocked engines
+ if request.cookies.get('blocked_engines'):
+ blocked_engines = request.cookies['blocked_engines'].split(',') # noqa
+ else:
+ blocked_engines = []
+
+ # parse query
+ query = Query(request_data.get('q', '').encode('utf-8'), blocked_engines)
+ query.parse_query()
- if not query:
+ # check if search query is set
+ if not query.getSearchQuery():
return
+ # run autocompleter
completer = autocomplete_backends.get(request.cookies.get('autocomplete'))
+ # check if valid autocompleter is selected
if not completer:
return
- results = completer(query)
+ # run autocompletion
+ raw_results = completer(query.getSearchQuery())
+
+ # parse results (write :language and !engine back to result string)
+ results = []
+ for result in raw_results:
+ result_query = query
+ result_query.changeSearchQuery(result)
+ # add parsed result
+ results.append(result_query.getFullQuery())
+
+ # return autocompleter results
if request_data.get('format') == 'x-suggestions':
return Response(json.dumps([query, results]),
mimetype='application/json')
@@ -290,7 +372,7 @@ def preferences():
if request.method == 'GET':
blocked_engines = request.cookies.get('blocked_engines', '').split(',')
- else:
+ else: # on save
selected_categories = []
locale = None
autocomplete = ''
@@ -315,6 +397,8 @@ def preferences():
engine_name = pd_name.replace('engine_', '', 1)
if engine_name in engines:
blocked_engines.append(engine_name)
+ elif pd_name == 'theme':
+ theme = pd if pd in themes else default_theme
resp = make_response(redirect(url_for('index')))
@@ -352,6 +436,9 @@ def preferences():
resp.set_cookie('method', method, max_age=cookie_max_age)
+ resp.set_cookie(
+ 'theme', theme, max_age=cookie_max_age)
+
return resp
return render('preferences.html',
locales=settings['locales'],
@@ -361,13 +448,14 @@ def preferences():
categs=categories.items(),
blocked_engines=blocked_engines,
autocomplete_backends=autocomplete_backends,
- shortcuts={y: x for x, y in engine_shortcuts.items()})
+ shortcuts={y: x for x, y in engine_shortcuts.items()},
+ themes=themes,
+ theme=get_current_theme_name())
@app.route('/stats', methods=['GET'])
def stats():
"""Render engine statistics page."""
- global categories
stats = get_engines_stats()
return render(
'stats.html',
@@ -404,15 +492,15 @@ def opensearch():
@app.route('/favicon.ico')
def favicon():
- return send_from_directory(os.path.join(app.root_path, 'static/img'),
+ return send_from_directory(os.path.join(app.root_path,
+ 'static',
+ get_current_theme_name(),
+ 'img'),
'favicon.png',
mimetype='image/vnd.microsoft.icon')
def run():
- from gevent import monkey
- monkey.patch_all()
-
app.run(
debug=settings['server']['debug'],
use_debugger=settings['server']['debug'],
@@ -420,5 +508,8 @@ def run():
)
+application = app
+
+
if __name__ == "__main__":
run()