on master help sign in
[enh] engine customisation init
c0013edasciimoo
searx/static/css/style.css+11−4
@@ -49,7 +49,7 @@ input[type="submit"] { padding: 2px 6px; margin: 2px 4px; display: inline-block;
49
49
50input[type="checkbox"] { visibility: hidden; }
50input[type="checkbox"] { visibility: hidden; }
51
51
52−fieldset { margin: 8px; }
52+fieldset { margin: 8px; border: 1px solid #3498DB; }
53
53
54#categories { margin: 0 10px; }
54#categories { margin: 0 10px; }
55
55
@@ -57,7 +57,7 @@ fieldset { margin: 8px; }
57.checkbox_container input {
57.checkbox_container input {
58 display: none;
58 display: none;
59}
59}
60−.checkbox_container label {
60+.checkbox_container label, .engine_checkbox label {
61 cursor: pointer;
61 cursor: pointer;
62 padding: 4px 10px;
62 padding: 4px 10px;
63 margin: 0;
63 margin: 0;
@@ -77,6 +77,12 @@ fieldset { margin: 8px; }
77.search .checkbox_container label:hover { border-bottom: 4px solid #3498DB; }
77.search .checkbox_container label:hover { border-bottom: 4px solid #3498DB; }
78.search .checkbox_container input[type="checkbox"]:checked + label { border-bottom: 4px solid #2980B9; }
78.search .checkbox_container input[type="checkbox"]:checked + label { border-bottom: 4px solid #2980B9; }
79
79
80+.engine_checkbox { padding: 4px; }
81+label.allow { background: #E74C3C; color: #FFFFFF; padding: 4px 8px; display: none; }
82+label.deny { background: #2ECC71; padding: 4px 8px; display: inline; }
83+.engine_checkbox input[type="checkbox"]:checked + label:nth-child(2) + label { display: none; }
84+.engine_checkbox input[type="checkbox"]:checked + label.allow { display: inline; }
85+
80a { text-decoration: none; color: #1a11be; }
86a { text-decoration: none; color: #1a11be; }
81a:visited { color: #7b11be; }
87a:visited { color: #7b11be; }
82
88
@@ -116,8 +122,9 @@ a:visited { color: #7b11be; }
116
122
117.percentage { position: relative; width: 300px; }
123.percentage { position: relative; width: 300px; }
118.percentage div { background: #444444; }
124.percentage div { background: #444444; }
125+table { width: 100%; }
119−td { padding: 0 4px; }
126+td { padding: 0 4px; }
120−tr:hover td { background: #DDDDDD; }
127+tr:hover { background: #DDDDDD; }
121
128
122#search_wrapper { position: relative; max-width: 600px; padding: 10px; }
129#search_wrapper { position: relative; max-width: 600px; padding: 10px; }
123.center #search_wrapper { margin-left: auto; margin-right: auto; }
130.center #search_wrapper { margin-left: auto; margin-right: auto; }
searx/templates/engines.htmldeleted−27
@@ -1,27 +0,0 @@
1−{% extends 'base.html' %}
2−{% block content %}
3−<div class="row">
4− <h2>{{ _('Currently used search engines') }}</h2>
5−
6− <table style="width: 80%;">
7− <tr>
8− <th>{{ _('Engine name') }}</th>
9− <th>{{ _('Shortcut') }}</th>
10− <th>{{ _('Category') }}</th>
11− </tr>
12− {% for (categ,search_engines) in categs %}
13− {% for search_engine in search_engines %}
14−
15− {% if not search_engine.private %}
16− <tr>
17− <td>{{ search_engine.name }}</td>
18− <td>{{ shortcuts[search_engine.name] }}</td>
19− <td>{{ _(categ) }}</td>
20− </tr>
21− {% endif %}
22− {% endfor %}
23− {% endfor %}
24− </table>
25−<p class="right"><a href="/">{{ _('back') }}</a></p>
26−</div>
27−{% endblock %}
searx/templates/preferences.html+29
@@ -32,6 +32,35 @@
32 </select>
32 </select>
33 </p>
33 </p>
34 </fieldset>
34 </fieldset>
35+ <fieldset>
36+ <legend>{{ _('Currently used search engines') }}</legend>
37+
38+ <table>
39+ <tr>
40+ <th>{{ _('Engine name') }}</th>
41+ <th>{{ _('Shortcut') }}</th>
42+ <th>{{ _('Category') }}</th>
43+ <th>{{ _('Allow') }} / {{ _('Deny') }}</th>
44+ </tr>
45+ {% for (categ,search_engines) in categs %}
46+ {% for search_engine in search_engines %}
47+
48+ {% if not search_engine.private %}
49+ <tr>
50+ <td>{{ search_engine.name }}</td>
51+ <td>{{ shortcuts[search_engine.name] }}</td>
52+ <td>{{ _(categ) }}</td>
53+ <td class="engine_checkbox">
54+ <input type="checkbox" id="engine_{{ categ}}_{{ search_engine.name|replace(' ', '_') }}" name="engine_{{ search_engine.name }}"{% if search_engine.name in blocked_engines %} checked="checked"{% endif %} />
55+ <label class="allow" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Allow') }}</label>
56+ <label class="deny" for="engine_{{ categ }}_{{ search_engine.name|replace(' ', '_') }}">{{ _('Deny') }}</label>
57+ </td>
58+ </tr>
59+ {% endif %}
60+ {% endfor %}
61+ {% endfor %}
62+ </table>
63+ </fieldset>
35 <p class="small_font">{{ _('These settings are stored in your cookies, this allows us not to store this data about you.') }}
64 <p class="small_font">{{ _('These settings are stored in your cookies, this allows us not to store this data about you.') }}
36 <br />
65 <br />
37 {{ _("These cookies serve your sole convenience, we don't use these cookies to track you.") }}
66 {{ _("These cookies serve your sole convenience, we don't use these cookies to track you.") }}
searx/tests/test_webapp.py−5
@@ -124,11 +124,6 @@ class ViewsTestCase(SearxTestCase):
124 self.assertEqual(result.status_code, 200)
124 self.assertEqual(result.status_code, 200)
125 self.assertIn('<h1>About <a href="/">searx</a></h1>', result.data)
125 self.assertIn('<h1>About <a href="/">searx</a></h1>', result.data)
126
126
127− def test_engines(self):
128− result = self.app.get('/engines')
129− self.assertEqual(result.status_code, 200)
130− self.assertIn('<h2>Currently used search engines</h2>', result.data)
131−
132 def test_preferences(self):
127 def test_preferences(self):
133 result = self.app.get('/preferences')
128 result = self.app.get('/preferences')
134 self.assertEqual(result.status_code, 200)
129 self.assertEqual(result.status_code, 200)
searx/webapp.py+23−13
@@ -242,17 +242,6 @@ def about():
242 return render('about.html')
242 return render('about.html')
243
243
244
244
245−@app.route('/engines', methods=['GET'])
246−def list_engines():
247− """Render engines page.
248−
249− List of all supported engines.
250− """
251− return render('engines.html',
252− categs=categories.items(),
253− shortcuts={y: x for x, y in engine_shortcuts.items()})
254−
255−
256@app.route('/preferences', methods=['GET', 'POST'])
245@app.route('/preferences', methods=['GET', 'POST'])
257def preferences():
246def preferences():
258 """Render preferences page.
247 """Render preferences page.
@@ -264,7 +253,11 @@ def preferences():
264 and request.cookies['language'] in (x[0] for x in language_codes):
253 and request.cookies['language'] in (x[0] for x in language_codes):
265 lang = request.cookies['language']
254 lang = request.cookies['language']
266
255
256+ blocked_engines = []
257+
267− if request.method == 'POST':
258+ if request.method == 'GET':
259+ blocked_engines = request.cookies.get('blocked_engines', '').split(',')
260+ else:
268 selected_categories = []
261 selected_categories = []
269 locale = None
262 locale = None
270 for pd_name, pd in request.form.items():
263 for pd_name, pd in request.form.items():
@@ -278,10 +271,24 @@ def preferences():
278 elif pd_name == 'language' and (pd == 'all' or
271 elif pd_name == 'language' and (pd == 'all' or
279 pd in (x[0] for
272 pd in (x[0] for
280 x in language_codes)):
273 x in language_codes)):
274+ locale = pd
281 lang = pd
275 lang = pd
276+ elif pd_name.startswith('engine_'):
277+ engine_name = pd_name.replace('engine_', '', 1)
278+ if engine_name in engines:
279+ blocked_engines.append(engine_name)
282
280
283 resp = make_response(redirect('/'))
281 resp = make_response(redirect('/'))
284
282
283+ user_blocked_engines = request.cookies.get('blocked_engines', '').split(',') # noqa
284+
285+ if sorted(blocked_engines) != sorted(user_blocked_engines):
286+ # cookie max age: 4 weeks
287+ resp.set_cookie(
288+ 'blocked_engines', ','.join(blocked_engines),
289+ max_age=60 * 60 * 24 * 7 * 4
290+ )
291+
285 if locale:
292 if locale:
286 # cookie max age: 4 weeks
293 # cookie max age: 4 weeks
287 resp.set_cookie(
294 resp.set_cookie(
@@ -307,7 +314,10 @@ def preferences():
307 locales=settings['locales'],
314 locales=settings['locales'],
308 current_locale=get_locale(),
315 current_locale=get_locale(),
309 current_language=lang or 'all',
316 current_language=lang or 'all',
310− language_codes=language_codes)
317+ language_codes=language_codes,
318+ categs=categories.items(),
319+ blocked_engines=blocked_engines,
320+ shortcuts={y: x for x, y in engine_shortcuts.items()})
311
321
312
322
313@app.route('/stats', methods=['GET'])
323@app.route('/stats', methods=['GET'])