on master help sign in
Merge pull request #2270 from kvch/disable-preference-settings

Let admins lock user preferences

commit0a44fa8bb7eca0d81f0ebdab37b9845b260473ad authorAdam Tauber <asciimoo@gmail.com> dateSun 25 Oct 2020, 18:24 (6 years ago) parent6beb84e33e139c
11 files changed+151−5
searx/preferences.py+42−3 searx/settings.yml+9 searx/settings_robot.yml+3 searx/templates/courgette/preferences.html+16 searx/templates/legacy/preferences.html+16 searx/templates/oscar/preferences.html+22 searx/templates/pix-art/preferences.html+8 searx/templates/simple/preferences.html+20 searx/webadapter.py+9−1 searx/webapp.py+5 tests/unit/test_preferences.py+1−1
searx/preferences.py+42−3
@@ -35,9 +35,10 @@ class ValidationException(Exception):
3535class Setting:
3636 """Base class of user settings"""
3737
38− def __init__(self, default_value, **kwargs):
38+ def __init__(self, default_value, locked=False, **kwargs):
3939 super().__init__()
4040 self.value = default_value
41+ self.locked = locked
4142 for key, value in kwargs.items():
4243 setattr(self, key, value)
4344
@@ -115,6 +116,9 @@ class MultipleChoiceSetting(EnumStringSetting):
115116 self.value = elements
116117
117118 def parse_form(self, data): # pylint: disable=missing-function-docstring
119+ if self.locked:
120+ return
121+
118122 self.value = []
119123 for choice in data:
120124 if choice in self.choices and choice not in self.value: # pylint: disable=no-member
@@ -149,6 +153,9 @@ class SetSetting(Setting):
149153 self.values.add(element)
150154
151155 def parse_form(self, data): # pylint: disable=missing-function-docstring
156+ if self.locked:
157+ return
158+
152159 elements = data.split(',')
153160 self.values = set(elements) # pylint: disable=attribute-defined-outside-init
154161
@@ -233,6 +240,9 @@ class SwitchableSetting(Setting):
233240 self.enabled = set(data[ENABLED].split(','))
234241
235242 def parse_form(self, items): # pylint: disable=missing-function-docstring
243+ if self.locked:
244+ return
245+
236246 items = self.transform_form_items(items)
237247 self.disabled = set() # pylint: disable=attribute-defined-outside-init
238248 self.enabled = set() # pylint: disable=attribute-defined-outside-init
@@ -317,22 +327,28 @@ class Preferences:
317327
318328 self.key_value_settings = {
319329 'categories': MultipleChoiceSetting(
320− ['general'], choices=categories + ['none']
330+ ['general'],
331+ is_locked('categories'),
332+ choices=categories + ['none']
321333 ),
322334 'language': SearchLanguageSetting(
323335 settings['search'].get('default_lang', ''),
336+ is_locked('language'),
324337 choices=list(LANGUAGE_CODES) + ['']
325338 ),
326339 'locale': EnumStringSetting(
327340 settings['ui'].get('default_locale', ''),
341+ is_locked('locale'),
328342 choices=list(settings['locales'].keys()) + ['']
329343 ),
330344 'autocomplete': EnumStringSetting(
331345 settings['search'].get('autocomplete', ''),
346+ is_locked('autocomplete'),
332347 choices=list(autocomplete.backends.keys()) + ['']
333348 ),
334349 'image_proxy': MapSetting(
335350 settings['server'].get('image_proxy', False),
351+ is_locked('image_proxy'),
336352 map={
337353 '': settings['server'].get('image_proxy', 0),
338354 '0': False,
@@ -343,10 +359,12 @@ class Preferences:
343359 ),
344360 'method': EnumStringSetting(
345361 settings['server'].get('method', 'POST'),
362+ is_locked('method'),
346363 choices=('GET', 'POST')
347364 ),
348365 'safesearch': MapSetting(
349366 settings['search'].get('safe_search', 0),
367+ is_locked('safesearch'),
350368 map={
351369 '0': 0,
352370 '1': 1,
@@ -355,10 +373,12 @@ class Preferences:
355373 ),
356374 'theme': EnumStringSetting(
357375 settings['ui'].get('default_theme', 'oscar'),
376+ is_locked('theme'),
358377 choices=themes
359378 ),
360379 'results_on_new_tab': MapSetting(
361380 settings['ui'].get('results_on_new_tab', False),
381+ is_locked('results_on_new_tab'),
362382 map={
363383 '0': False,
364384 '1': True,
@@ -367,10 +387,13 @@ class Preferences:
367387 }
368388 ),
369389 'doi_resolver': MultipleChoiceSetting(
370− ['oadoi.org'], choices=DOI_RESOLVERS
390+ ['oadoi.org'],
391+ is_locked('doi_resolver'),
392+ choices=DOI_RESOLVERS
371393 ),
372394 'oscar-style': EnumStringSetting(
373395 settings['ui'].get('theme_args', {}).get('oscar_style', 'logicodev'),
396+ is_locked('oscar-style'),
374397 choices=['', 'logicodev', 'logicodev-dark', 'pointhi']),
375398 }
376399
@@ -383,6 +406,8 @@ class Preferences:
383406 """Return preferences as URL parameters"""
384407 settings_kv = {}
385408 for k, v in self.key_value_settings.items():
409+ if v.locked:
410+ continue
386411 if isinstance(v, MultipleChoiceSetting):
387412 settings_kv[k] = ','.join(v.get_value())
388413 else:
@@ -410,6 +435,8 @@ class Preferences:
410435 """parse preferences from request (``flask.request.form``)"""
411436 for user_setting_name, user_setting in input_data.items():
412437 if user_setting_name in self.key_value_settings:
438+ if self.key_value_settings[user_setting_name].locked:
439+ continue
413440 self.key_value_settings[user_setting_name].parse(user_setting)
414441 elif user_setting_name == 'disabled_engines':
415442 self.engines.parse_cookie((input_data.get('disabled_engines', ''),
@@ -464,6 +491,8 @@ class Preferences:
464491 """Save cookie in the HTTP reponse obect
465492 """
466493 for user_setting_name, user_setting in self.key_value_settings.items():
494+ if self.key_value_settings[user_setting_name].locked:
495+ continue
467496 user_setting.save(user_setting_name, resp)
468497 self.engines.save(resp)
469498 self.plugins.save(resp)
@@ -482,3 +511,13 @@ class Preferences:
482511 break
483512
484513 return valid
514+
515+
516+def is_locked(setting_name):
517+ """Checks if a given setting name is locked by settings.yml
518+ """
519+ if 'preferences' not in settings:
520+ return False
521+ if 'lock' not in settings['preferences']:
522+ return False
523+ return setting_name in settings['preferences']['lock']
searx/settings.yml+9
@@ -33,6 +33,15 @@ ui:
3333# - it
3434# - science
3535
36+# Lock arbitrary settings on the preferences page.
37+# To find the ID of the user setting you want to lock, check
38+# the ID of the form on the page "preferences".
39+#preferences:
40+# lock:
41+# - language
42+# - autocomplete
43+# - method
44+
3645# searx supports result proxification using an external service: https://github.com/asciimoo/morty
3746# uncomment below section if you have running morty proxy
3847# the key is base64 encoded (keep the !!binary notation)
searx/settings_robot.yml+3
@@ -17,6 +17,9 @@ ui:
1717 templates_path : ""
1818 default_theme : oscar
1919
20+preferences:
21+ lock: []
22+
2023outgoing:
2124 request_timeout : 1.0 # seconds
2225 useragent_suffix : ""
searx/templates/courgette/preferences.html+16
@@ -5,10 +5,13 @@
55 <h2>{{ _('Preferences') }}</h2>
66
77 <form method="post" action="{{ url_for('preferences') }}" id="search_form">
8+ {% if 'categories' not in locked_preferences %}
89 <fieldset>
910 <legend>{{ _('Default categories') }}</legend>
1011 {% include 'courgette/categories.html' %}
1112 </fieldset>
13+ {% endif %}
14+ {% if 'language' not in locked_preferences %}
1215 <fieldset>
1316 <legend>{{ _('Search language') }}</legend>
1417 <p>
@@ -20,6 +23,8 @@
2023 </select>
2124 </p>
2225 </fieldset>
26+ {% endif %}
27+ {% if 'locale' not in locked_preferences %}
2328 <fieldset>
2429 <legend>{{ _('Interface language') }}</legend>
2530 <p>
@@ -30,6 +35,8 @@
3035 </select>
3136 </p>
3237 </fieldset>
38+ {% endif %}
39+ {% if 'autocomplete' not in locked_preferences %}
3340 <fieldset>
3441 <legend>{{ _('Autocomplete') }}</legend>
3542 <p>
@@ -41,6 +48,8 @@
4148 </select>
4249 </p>
4350 </fieldset>
51+ {% endif %}
52+ {% if 'image_proxy' not in locked_preferences %}
4453 <fieldset>
4554 <legend>{{ _('Image proxy') }}</legend>
4655 <p>
@@ -50,6 +59,8 @@
5059 </select>
5160 </p>
5261 </fieldset>
62+ {% endif %}
63+ {% if 'method' not in locked_preferences %}
5364 <fieldset>
5465 <legend>{{ _('Method') }}</legend>
5566 <p>
@@ -59,6 +70,8 @@
5970 </select>
6071 </p>
6172 </fieldset>
73+ {% endif %}
74+ {% if 'safesearch' not in locked_preferences %}
6275 <fieldset>
6376 <legend>{{ _('SafeSearch') }}</legend>
6477 <p>
@@ -69,6 +82,8 @@
6982 </select>
7083 </p>
7184 </fieldset>
85+ {% endif %}
86+ {% if 'theme' not in locked_preferences %}
7287 <fieldset>
7388 <legend>{{ _('Themes') }}</legend>
7489 <p>
@@ -92,6 +107,7 @@
92107 </select>
93108 </p>
94109 </fieldset>
110+ {% endif %}
95111 <fieldset>
96112 <legend>{{ _('Currently used search engines') }}</legend>
97113
searx/templates/legacy/preferences.html+16
@@ -10,6 +10,7 @@
1010 {% set display_tooltip = false %}
1111 {% include 'legacy/categories.html' %}
1212 </fieldset>
13+ {% if 'language' not in locked_preferences %}
1314 <fieldset>
1415 <legend>{{ _('Search language') }}</legend>
1516 <p>
@@ -21,6 +22,8 @@
2122 </select>
2223 </p>
2324 </fieldset>
25+ {% endif %}
26+ {% if 'locale' not in locked_preferences %}
2427 <fieldset>
2528 <legend>{{ _('Interface language') }}</legend>
2629 <p>
@@ -31,6 +34,8 @@
3134 </select>
3235 </p>
3336 </fieldset>
37+ {% endif %}
38+ {% if 'autocomplete' not in locked_preferences %}
3439 <fieldset>
3540 <legend>{{ _('Autocomplete') }}</legend>
3641 <p>
@@ -42,6 +47,8 @@
4247 </select>
4348 </p>
4449 </fieldset>
50+ {% endif %}
51+ {% if 'image_proxy' not in locked_preferences %}
4552 <fieldset>
4653 <legend>{{ _('Image proxy') }}</legend>
4754 <p>
@@ -51,6 +58,8 @@
5158 </select>
5259 </p>
5360 </fieldset>
61+ {% endif %}
62+ {% if 'method' not in locked_preferences %}
5463 <fieldset>
5564 <legend>{{ _('Method') }}</legend>
5665 <p>
@@ -60,6 +69,8 @@
6069 </select>
6170 </p>
6271 </fieldset>
72+ {% endif %}
73+ {% if 'safesearch' not in locked_preferences %}
6374 <fieldset>
6475 <legend>{{ _('SafeSearch') }}</legend>
6576 <p>
@@ -70,6 +81,8 @@
7081 </select>
7182 </p>
7283 </fieldset>
84+ {% endif %}
85+ {% if 'theme' not in locked_preferences %}
7386 <fieldset>
7487 <legend>{{ _('Themes') }}</legend>
7588 <p>
@@ -80,6 +93,8 @@
8093 </select>
8194 </p>
8295 </fieldset>
96+ {% endif %}
97+ {% if 'results_on_new_tab' not in locked_preferences %}
8398 <fieldset>
8499 <legend>{{ _('Results on new tabs') }}</legend>
85100 <p>
@@ -89,6 +104,7 @@
89104 </select>
90105 </p>
91106 </fieldset>
107+ {% endif %}
92108 <fieldset>
93109 <legend>{{ _('Currently used search engines') }}</legend>
94110
searx/templates/oscar/preferences.html+22
@@ -25,6 +25,7 @@
2525 <div class="tab-pane active" id="tab_general">
2626 <fieldset>
2727 <div class="container-fluid">
28+ {% if 'categories' not in locked_preferences %}
2829 <div class="row form-group">
2930 {% if rtl %}
3031 <div class="col-sm-11 col-md-10">
@@ -38,12 +39,16 @@
3839 </div>
3940 {% endif %}
4041 </div>
42+ {% endif %}
43+ {% if 'language' not in locked_preferences %}
4144 {% set language_label = _('Search language') %}
4245 {% set language_info = _('What language do you prefer for search?') %}
4346 {{ preferences_item_header(language_info, language_label, rtl, 'language') }}
4447 {% include 'oscar/languages.html' %}
4548 {{ preferences_item_footer(language_info, language_label, rtl) }}
49+ {% endif %}
4650
51+ {% if 'locale' not in locked_preferences %}
4752 {% set locale_label = _('Interface language') %}
4853 {% set locale_info = _('Change the language of the layout') %}
4954 {{ preferences_item_header(locale_info, locale_label, rtl, 'locale') }}
@@ -53,7 +58,9 @@
5358 {% endfor %}
5459 </select>
5560 {{ preferences_item_footer(locale_info, locale_label, rtl) }}
61+ {% endif %}
5662
63+ {% if 'autocomplete' not in locked_preferences %}
5764 {% set autocomplete_label = _('Autocomplete') %}
5865 {% set autocomplete_info = _('Find stuff as you type') %}
5966 {{ preferences_item_header(autocomplete_info, autocomplete_label, rtl, 'autocomplete') }}
@@ -64,7 +71,9 @@
6471 {% endfor %}
6572 </select>
6673 {{ preferences_item_footer(autocomplete_info, autocomplete_label, rtl) }}
74+ {% endif %}
6775
76+ {% if 'image_proxy' not in locked_preferences %}
6877 {% set image_proxy_label = _('Image proxy') %}
6978 {% set image_proxy_info = _('Proxying image results through searx') %}
7079 {{ preferences_item_header(image_proxy_info, image_proxy_label, rtl, 'image_proxy') }}
@@ -73,7 +82,9 @@
7382 <option value="" {% if not image_proxy %}selected="selected"{% endif %}>{{ _('Disabled')}}</option>
7483 </select>
7584 {{ preferences_item_footer(image_proxy_info, image_proxy_label, rtl) }}
85+ {% endif %}
7686
87+ {% if 'method' not in locked_preferences %}
7788 {% set method_label = _('Method') %}
7889 {% set method_info = _('Change how forms are submited, <a href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods" rel="external">learn more about request methods</a>') %}
7990 {{ preferences_item_header(method_info, method_label, rtl, 'method') }}
@@ -82,7 +93,9 @@
8293 <option value="GET" {% if method == 'GET' %}selected="selected"{% endif %}>GET</option>
8394 </select>
8495 {{ preferences_item_footer(method_info, method_label, rtl) }}
96+ {% endif %}
8597
98+ {% if 'safesearch' not in locked_preferences %}
8699 {% set safesearch_label = _('SafeSearch') %}
87100 {% set safesearch_info = _('Filter content') %}
88101 {{ preferences_item_header(safesearch_info, safesearch_label, rtl, 'safesearch') }}
@@ -92,7 +105,9 @@
92105 <option value="0" {% if safesearch == '0' %}selected="selected"{% endif %}>{{ _('None') }}</option>
93106 </select>
94107 {{ preferences_item_footer(safesearch_info, safesearch_label, rtl) }}
108+ {% endif %}
95109
110+ {% if 'theme' not in locked_preferences %}
96111 {% set theme_label = _('Themes') %}
97112 {% set theme_info = _('Change searx layout') %}
98113 {{ preferences_item_header(theme_info, theme_label, rtl, 'theme') }}
@@ -102,7 +117,9 @@
102117 {% endfor %}
103118 </select>
104119 {{ preferences_item_footer(theme_info, theme_label, rtl) }}
120+ {% endif %}
105121
122+ {% if 'oscar-style' not in locked_preferences %}
106123 {{ preferences_item_header(_('Choose style for this theme'), _('Style'), rtl, 'oscar_style') }}
107124 <select class="form-control {{ custom_select_class(rtl) }}" name="oscar-style" id="oscar_style">
108125 <option value="logicodev" >Logicodev</option>
@@ -110,7 +127,9 @@
110127 <option value="logicodev-dark" {% if preferences.get_value('oscar-style') == 'logicodev-dark' %}selected="selected"{% endif %}>Logicodev dark</option>
111128 </select>
112129 {{ preferences_item_footer(_('Choose style for this theme'), _('Style'), rtl) }}
130+ {% endif %}
113131
132+ {% if 'results_on_new_tab' not in locked_preferences %}
114133 {% set label = _('Results on new tabs') %}
115134 {% set info = _('Open result links on new browser tabs') %}
116135 {{ preferences_item_header(info, label, rtl, 'results_on_new_tab') }}
@@ -119,7 +138,9 @@
119138 <option value="0" {% if not results_on_new_tab %}selected="selected"{% endif %}>{{ _('Off')}}</option>
120139 </select>
121140 {{ preferences_item_footer(info, label, rtl) }}
141+ {% endif %}
122142
143+ {% if 'doi_resolver' not in locked_preferences %}
123144 {% set label = _('Open Access DOI resolver') %}
124145 {% set info = _('Redirect to open-access versions of publications when available (plugin required)') %}
125146 {{ preferences_item_header(info, label, rtl, 'doi_resolver') }}
@@ -131,6 +152,7 @@
131152 {% endfor %}
132153 </select>
133154 {{ preferences_item_footer(info, label, rtl) }}
155+ {% endif %}
134156
135157 {% set label = _('Engine tokens') %}
136158 {% set info = _('Access tokens for private engines') %}
searx/templates/pix-art/preferences.html+8
@@ -5,6 +5,7 @@
55 <h2>{{ _('Preferences') }}</h2>
66
77 <form method="post" action="{{ url_for('preferences') }}" id="search_form">
8+ {% if 'language' not in locked_preferences %}
89 <fieldset>
910 <legend>{{ _('Search language') }}</legend>
1011 <p>
@@ -16,6 +17,8 @@
1617 </select>
1718 </p>
1819 </fieldset>
20+ {% endif %}
21+ {% if 'locale' not in locked_preferences %}
1922 <fieldset>
2023 <legend>{{ _('Interface language') }}</legend>
2124 <p>
@@ -26,6 +29,8 @@
2629 </select>
2730 </p>
2831 </fieldset>
32+ {% endif %}
33+ {% if 'method' not in locked_preferences %}
2934 <fieldset>
3035 <legend>{{ _('Method') }}</legend>
3136 <p>
@@ -35,6 +40,8 @@
3540 </select>
3641 </p>
3742 </fieldset>
43+ {% endif %}
44+ {% if 'theme' not in locked_preferences %}
3845 <fieldset>
3946 <legend>{{ _('Themes') }}</legend>
4047 <p>
@@ -45,6 +52,7 @@
4552 </select>
4653 </p>
4754 </fieldset>
55+ {% endif %}
4856 <fieldset>
4957 <legend>{{ _('Currently used search engines') }}</legend>
5058
searx/templates/simple/preferences.html+20
@@ -30,11 +30,14 @@
3030{{ tabs_open() }}
3131
3232{{ tab_header('maintab', 'general', _('General')) }}
33+ {% if 'categories' not in locked_preferences %}
3334 <fieldset>
3435 <legend>{{ _('Default categories') }}</legend>
3536 {% set display_tooltip = false %}
3637 {% include 'simple/categories.html' %}
3738 </fieldset>
39+ {% endif %}
40+ {% if 'language' not in locked_preferences %}
3841 <fieldset>
3942 <legend>{{ _('Search language') }}</legend>
4043 <p class="value">{{- '' -}}
@@ -47,6 +50,8 @@
4750 </p>
4851 <div class="description">{{ _('What language do you prefer for search?') }}</div>
4952 </fieldset>
53+ {% endif %}
54+ {% if 'autocomplete' not in locked_preferences %}
5055 <fieldset>
5156 <legend>{{ _('Autocomplete') }}</legend>
5257 <p class="value">
@@ -59,6 +64,8 @@
5964 </p>
6065 <div class="description">{{ _('Find stuff as you type') }}</div>
6166 </fieldset>
67+ {% endif %}
68+ {% if 'safesearch' not in locked_preferences %}
6269 <fieldset>
6370 <legend>{{ _('SafeSearch') }}</legend>
6471 <p class="value">
@@ -70,7 +77,9 @@
7077 </p>
7178 <p class="description">{{ _('Filter content') }}</p>
7279 </fieldset>
80+ {% endif %}
7381 {{ plugin_preferences('general') }}
82+ {% if 'doi_resolver' not in locked_preferences %}
7483 <fieldset>
7584 <legend>{{ _('Open Access DOI resolver') }}</legend>
7685 <p class="value">
@@ -84,6 +93,7 @@
8493 </p>
8594 <div class="description"><!-- {{ _('Redirect to open-access versions of publications when available (plugin required)') }} --></div>
8695 </fieldset>
96+ {% endif %}
8797 {{ tab_footer() }}
8898
8999 {{ tab_header('maintab', 'engines', _('Engines')) }}
@@ -129,6 +139,7 @@
129139 {{ tab_footer() }}
130140
131141 {{ tab_header('maintab', 'ui', _('User interface')) }}
142+ {% if 'locale' not in locked_preferences %}
132143 <fieldset>
133144 <legend>{{ _('Interface language') }}</legend>
134145 <p class="value">
@@ -140,6 +151,8 @@
140151 </p>
141152 <div class="description">{{ _('Change the language of the layout') }}</div>
142153 </fieldset>
154+ {% endif %}
155+ {% if 'theme' not in locked_preferences %}
143156 <fieldset>
144157 <legend>{{ _('Themes') }}</legend>
145158 <p class="value">
@@ -151,6 +164,8 @@
151164 </p>
152165 <div class="description">{{ _('Change searx layout') }}</div>
153166 </fieldset>
167+ {% endif %}
168+ {% if 'results_on_new_tab' not in locked_preferences %}
154169 <fieldset>
155170 <legend>{{ _('Results on new tabs') }}</legend>
156171 <p class="value">
@@ -161,6 +176,7 @@
161176 </p>
162177 <div class="description">{{_('Open result links on new browser tabs') }}</div>
163178 </fieldset>
179+ {% endif %}
164180 {{ plugin_preferences('ui') }}
165181 {{ tab_footer() }}
166182
@@ -197,6 +213,7 @@
197213 {{ tab_footer() }}
198214
199215 {{ tab_header('maintab', 'privacy', _('Privacy')) }}
216+ {% if 'method' not in locked_preferences %}
200217 <fieldset>
201218 <legend>{{ _('Method') }}</legend>
202219 <p class="value">
@@ -207,6 +224,8 @@
207224 </p>
208225 <div class="description">{{ _('Search language') }}</div>
209226 </fieldset>
227+ {% endif %}
228+ {% if 'image_proxy' not in locked_preferences %}
210229 <fieldset>
211230 <legend>{{ _('Image proxy') }}</legend>
212231 <p class="value">
@@ -217,6 +236,7 @@
217236 </p>
218237 <div class="description">{{ _('Proxying image results through searx') }}</div>
219238 </fieldset>
239+ {% endif %}
220240 {{ plugin_preferences('privacy') }}
221241
222242 {{ tab_footer() }}
searx/webadapter.py+9−1
@@ -4,7 +4,7 @@ from searx.webutils import VALID_LANGUAGE_CODE
44from searx.query import RawTextQuery
55from searx.engines import categories, engines
66from searx.search import SearchQuery, EngineRef
7−from searx.preferences import Preferences
7+from searx.preferences import Preferences, is_locked
88
99
1010# remove duplicate queries.
@@ -48,6 +48,8 @@ def parse_pageno(form: Dict[str, str]) -> int:
4848
4949
5050def parse_lang(preferences: Preferences, form: Dict[str, str], raw_text_query: RawTextQuery) -> str:
51+ if is_locked('language'):
52+ return preferences.get_value('langueage')
5153 # get language
5254 # set specific language if set on request, query or preferences
5355 # TODO support search with multible languages
@@ -66,6 +68,9 @@ def parse_lang(preferences: Preferences, form: Dict[str, str], raw_text_query: R
6668
6769
6870def parse_safesearch(preferences: Preferences, form: Dict[str, str]) -> int:
71+ if is_locked('safesearch'):
72+ return preferences.get_value('safesearch')
73+
6974 if 'safesearch' in form:
7075 query_safesearch = form.get('safesearch')
7176 # first check safesearch
@@ -117,6 +122,9 @@ def parse_specific(raw_text_query: RawTextQuery) -> Tuple[List[EngineRef], List[
117122
118123
119124def parse_category_form(query_categories: List[str], name: str, value: str) -> None:
125+ if is_locked('categories'):
126+ return preferences.get_value('categories')
127+
120128 if name == 'categories':
121129 query_categories.extend(categ for categ in map(str.strip, value.split(',')) if categ in categories)
122130 elif name.startswith('category_'):
searx/webapp.py+5
@@ -828,6 +828,10 @@ def preferences():
828828 stats[engine_stat.get('name')]['warn_time'] = True
829829 # end of stats
830830
831+ locked_preferences = list()
832+ if 'preferences' in settings and 'lock' in settings['preferences']:
833+ locked_preferences = settings['preferences']['lock']
834+
831835 return render('preferences.html',
832836 selected_categories=get_selected_categories(request.preferences, request.form),
833837 all_categories=_get_ordered_categories(),
@@ -848,6 +852,7 @@ def preferences():
848852 theme=get_current_theme_name(),
849853 preferences_url_params=request.preferences.get_as_url_params(),
850854 base_url=get_base_url(),
855+ locked_preferences=locked_preferences,
851856 preferences=True)
852857
853858
tests/unit/test_preferences.py+1−1
@@ -141,4 +141,4 @@ class TestPreferences(SearxTestCase):
141141 pref.parse_encoded_data(url_params)
142142 self.assertEqual(
143143 vars(pref.key_value_settings['categories']),
144− {'value': ['general'], 'choices': ['general', 'none']})
144+ {'value': ['general'], 'locked': False, 'choices': ['general', 'none']})