Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[enh] add settings option to enable/disable search formats #99

Merged
merged 2 commits into from
May 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions searx/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ search:
default_lang : "" # Default search language - leave blank to detect from browser information or use codes from 'languages.py'
ban_time_on_fail : 5 # ban time in seconds after engine errors
max_ban_time_on_fail : 120 # max ban time in seconds after engine errors
formats: [html, csv, json, rss] # remove format to deny access, use lower case.

server:
port : 8888
Expand Down
6 changes: 5 additions & 1 deletion searx/templates/oscar/results.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,22 @@ <h4 class="panel-title">{{ _('Links') }}</h4>{{- "" -}}
<input id="search_url" type="url" class="form-control select-all-on-click cursor-text" name="search_url" value="{{ search_url() }}" readonly>{{- "" -}}
</div>{{- "" -}}
</form>
{% if search_formats %}
<label>{{ _('Download results') }}</label>
<div class="clearfix"></div>
{% for output_type in ('csv', 'json', 'rss') %}
{% for output_type in search_formats %}
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="form-inline pull-{% if rtl %}right{% else %}left{% endif %} result_download">
{{- search_form_attrs(pageno) -}}
<input type="hidden" name="format" value="{{ output_type }}">{{- "" -}}
<button type="submit" class="btn btn-default">{{ output_type }}</button>{{- "" -}}
</form>
{% endfor %}
<div class="clearfix"></div>
{% if 'rss' in search_formats %}
<br /><label><a href="{{ search_url() }}&amp;format=rss">{{ _('RSS subscription') }}</a></label>
{% endif %}
<div class="clearfix"></div>
{% endif %}
</div>
</div>
</div><!-- /#sidebar_results -->
Expand Down
4 changes: 3 additions & 1 deletion searx/templates/simple/results.html
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ <h4 class="title">{{ _('Search URL') }} :</h4>
<div class="selectable_url"><pre>{{ url_for('search', _external=True) }}?q={{ q|urlencode }}&amp;language={{ current_language }}&amp;time_range={{ time_range }}&amp;safesearch={{ safesearch }}{% if pageno > 1 %}&amp;pageno={{ pageno }}{% endif %}{% if selected_categories %}&amp;categories={{ selected_categories|join(",") | replace(' ','+') }}{% endif %}{% if timeout_limit %}&amp;timeout_limit={{ timeout_limit|urlencode }}{% endif %}</pre></div>
</div>
<div id="apis">
{% if search_formats %}
<h4 class="title">{{ _('Download results') }}</h4>
{% for output_type in ('csv', 'json', 'rss') %}
{% for output_type in search_formats %}
<div class="left">
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
<input type="hidden" name="q" value="{{ q|e }}">
Expand All @@ -103,6 +104,7 @@ <h4 class="title">{{ _('Download results') }}</h4>
</form>
</div>
{% endfor %}
{% endif %}
</div>
</div>

Expand Down
53 changes: 53 additions & 0 deletions searx/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from random import choice
from html.parser import HTMLParser
from urllib.parse import urljoin, urlparse
from collections.abc import Mapping

from lxml import html
from lxml.etree import ElementBase, XPath, XPathError, XPathSyntaxError, _ElementStringResult, _ElementUnicodeResult
Expand Down Expand Up @@ -500,6 +501,58 @@ def get_engine_from_settings(name):
return {}


NOT_EXISTS = object()
"""Singleton used by :py:obj:`get_value` if a key does not exists."""


def get_value(dictionary, *keys, default=NOT_EXISTS):
"""Return the value from a *deep* mapping type (e.g. the ``settings`` object
from yaml). If the path to the *key* does not exists a :py:obj:`NOT_EXISTS`
is returned (non ``KeyError`` exception is raised).

.. code: python

>>> from searx import settings
>>> from searx.utils import get_value, NOT_EXISTS
>>> get_value(settings, 'checker', 'additional_tests', 'rosebud', 'result_container')
['not_empty', ['one_title_contains', 'citizen kane']]

>>> get_value(settings, 'search', 'xxx') is NOT_EXISTS
True
>>> get_value(settings, 'search', 'formats')
['html', 'csv', 'json', 'rss']

The list returned from the ``search.format`` key is not a mapping type, you
can't traverse along non-mapping types. If you try it, you will get a
:py:ref:`NOT_EXISTS`:

.. code: python

>>> get_value(settings, 'search', 'format', 'csv') is NOT_EXISTS
True
>>> get_value(settings, 'search', 'formats')[1]
'csv'

For convenience you can replace :py:ref:`NOT_EXISTS` by a default value of
your choice:

.. code: python

if 'csv' in get_value(settings, 'search', 'formats', default=[]):
print("csv format is denied")

"""

obj = dictionary
for k in keys:
if not isinstance(obj, Mapping):
raise TypeError("expected mapping type, got %s" % type(obj))
obj = obj.get(k, default)
if obj is default:
return obj
return obj


def get_xpath(xpath_spec):
"""Return cached compiled XPath

Expand Down
15 changes: 14 additions & 1 deletion searx/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.serving import WSGIRequestHandler

import flask

from flask import (
Flask,
request,
Expand Down Expand Up @@ -86,6 +88,7 @@
gen_useragent,
dict_subset,
match_language,
get_value,
)
from searx.version import VERSION_STRING
from searx.query import RawTextQuery
Expand Down Expand Up @@ -161,6 +164,8 @@ def new_thread_init(self, *args, **kwargs):
for (dirpath, dirnames, filenames) in os.walk(theme_img_path):
global_favicons[indice].extend(filenames)

OUTPUT_FORMATS = ['html', 'csv', 'json', 'rss']

STATS_SORT_PARAMETERS = {
'name': (False, 'name', ''),
'score': (True, 'score', 0),
Expand Down Expand Up @@ -511,6 +516,11 @@ def render(template_name, override_theme=None, **kwargs):

kwargs['preferences'] = request.preferences

kwargs['search_formats'] = [
x for x in get_value(
settings, 'search', 'formats', default=OUTPUT_FORMATS)
if x != 'html']

kwargs['brand'] = brand

kwargs['translations'] = json.dumps(get_translations(), separators=(',', ':'))
Expand Down Expand Up @@ -683,9 +693,12 @@ def search():

# output_format
output_format = request.form.get('format', 'html')
if output_format not in ['html', 'csv', 'json', 'rss']:
if output_format not in OUTPUT_FORMATS:
output_format = 'html'

if output_format not in get_value(settings, 'search', 'formats', default=OUTPUT_FORMATS):
flask.abort(403)
return42 marked this conversation as resolved.
Show resolved Hide resolved

# check if there is query (not None and not an empty string)
if not request.form.get('q'):
if output_format == 'html':
Expand Down
1 change: 1 addition & 0 deletions utils/templates/etc/searx/use_default_settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ search:
safe_search : 0 # Filter results. 0: None, 1: Moderate, 2: Strict
autocomplete : "" # Existing autocomplete backends: "dbpedia", "duckduckgo", "google", "startpage", "swisscows", "qwant", "wikipedia" - leave blank to turn it off by default
default_lang : "" # Default search language - leave blank to detect from browser information or use codes from 'languages.py'
formats: [html, csv, json, rss]

server:
port : 8888
Expand Down