Browse Source

[mod] preferences.py: add and use BooleanSetting for checkbox preferences

Bnyro 1 year ago
parent
commit
1428385d1c
1 changed files with 52 additions and 57 deletions
  1. 52 57
      searx/preferences.py

+ 52 - 57
searx/preferences.py

@@ -9,6 +9,7 @@ from base64 import urlsafe_b64encode, urlsafe_b64decode
 from zlib import compress, decompress
 from zlib import compress, decompress
 from urllib.parse import parse_qs, urlencode
 from urllib.parse import parse_qs, urlencode
 from typing import Iterable, Dict, List, Optional
 from typing import Iterable, Dict, List, Optional
+from collections import OrderedDict
 
 
 import flask
 import flask
 import babel
 import babel
@@ -24,6 +25,18 @@ from searx.engines import DEFAULT_CATEGORY
 COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5  # 5 years
 COOKIE_MAX_AGE = 60 * 60 * 24 * 365 * 5  # 5 years
 DOI_RESOLVERS = list(settings['doi_resolvers'])
 DOI_RESOLVERS = list(settings['doi_resolvers'])
 
 
+MAP_STR2BOOL: Dict[str, bool] = OrderedDict(
+    [
+        ('0', False),
+        ('1', True),
+        ('on', True),
+        ('off', False),
+        ('True', True),
+        ('False', False),
+        ('none', False),
+    ]
+)
+
 
 
 class ValidationException(Exception):
 class ValidationException(Exception):
 
 
@@ -199,6 +212,26 @@ class MapSetting(Setting):
             resp.set_cookie(name, self.key, max_age=COOKIE_MAX_AGE)
             resp.set_cookie(name, self.key, max_age=COOKIE_MAX_AGE)
 
 
 
 
+class BooleanSetting(Setting):
+    """Setting of a boolean value that has to be translated in order to be storable"""
+
+    def normalized_str(self, val):
+        for v_str, v_obj in MAP_STR2BOOL.items():
+            if val == v_obj:
+                return v_str
+        raise ValueError("Invalid value: %s (%s) is not a boolean!" % (repr(val), type(val)))
+
+    def parse(self, data: str):
+        """Parse and validate ``data`` and store the result at ``self.value``"""
+        self.value = MAP_STR2BOOL[data]
+        self.key = self.normalized_str(self.value)  # pylint: disable=attribute-defined-outside-init
+
+    def save(self, name: str, resp: flask.Response):
+        """Save cookie ``name`` in the HTTP response object"""
+        if hasattr(self, 'key'):
+            resp.set_cookie(name, self.key, max_age=COOKIE_MAX_AGE)
+
+
 class BooleanChoices:
 class BooleanChoices:
     """Maps strings to booleans that are either true or false."""
     """Maps strings to booleans that are either true or false."""
 
 
@@ -375,17 +408,9 @@ class Preferences:
                 locked=is_locked('autocomplete'),
                 locked=is_locked('autocomplete'),
                 choices=list(autocomplete.backends.keys()) + ['']
                 choices=list(autocomplete.backends.keys()) + ['']
             ),
             ),
-            'image_proxy': MapSetting(
+            'image_proxy': BooleanSetting(
                 settings['server']['image_proxy'],
                 settings['server']['image_proxy'],
-                locked=is_locked('image_proxy'),
-                map={
-                    '': settings['server']['image_proxy'],
-                    '0': False,
-                    '1': True,
-                    'True': True,
-                    'False': False,
-                    'on': True
-                }
+                locked=is_locked('image_proxy')
             ),
             ),
             'method': EnumStringSetting(
             'method': EnumStringSetting(
                 settings['server']['method'],
                 settings['server']['method'],
@@ -406,16 +431,9 @@ class Preferences:
                 locked=is_locked('theme'),
                 locked=is_locked('theme'),
                 choices=themes
                 choices=themes
             ),
             ),
-            'results_on_new_tab': MapSetting(
+            'results_on_new_tab': BooleanSetting(
                 settings['ui']['results_on_new_tab'],
                 settings['ui']['results_on_new_tab'],
-                locked=is_locked('results_on_new_tab'),
-                map={
-                    '0': False,
-                    '1': True,
-                    'False': False,
-                    'True': True,
-                    'on': True
-                }
+                locked=is_locked('results_on_new_tab')
             ),
             ),
             'doi_resolver': MultipleChoiceSetting(
             'doi_resolver': MultipleChoiceSetting(
                 [settings['default_doi_resolver'], ],
                 [settings['default_doi_resolver'], ],
@@ -427,51 +445,21 @@ class Preferences:
                 locked=is_locked('simple_style'),
                 locked=is_locked('simple_style'),
                 choices=['', 'auto', 'light', 'dark']
                 choices=['', 'auto', 'light', 'dark']
             ),
             ),
-            'center_alignment': MapSetting(
+            'center_alignment': BooleanSetting(
                 settings['ui']['center_alignment'],
                 settings['ui']['center_alignment'],
-                locked=is_locked('center_alignment'),
-                map={
-                    '0': False,
-                    '1': True,
-                    'False': False,
-                    'True': True,
-                    'on': True
-                }
+                locked=is_locked('center_alignment')
             ),
             ),
-            'advanced_search': MapSetting(
+            'advanced_search': BooleanSetting(
                 settings['ui']['advanced_search'],
                 settings['ui']['advanced_search'],
-                locked=is_locked('advanced_search'),
-                map={
-                    '0': False,
-                    '1': True,
-                    'False': False,
-                    'True': True,
-                    'on': True,
-                }
+                locked=is_locked('advanced_search')
             ),
             ),
-            'query_in_title': MapSetting(
+            'query_in_title': BooleanSetting(
                 settings['ui']['query_in_title'],
                 settings['ui']['query_in_title'],
-                locked=is_locked('query_in_title'),
-                map={
-                    '': settings['ui']['query_in_title'],
-                    '0': False,
-                    '1': True,
-                    'True': True,
-                    'False': False,
-                    'on': True
-                }
+                locked=is_locked('query_in_title')
             ),
             ),
-            'infinite_scroll': MapSetting(
+            'infinite_scroll': BooleanSetting(
                 settings['ui']['infinite_scroll'],
                 settings['ui']['infinite_scroll'],
-                locked=is_locked('infinite_scroll'),
-                map={
-                    '': settings['ui']['infinite_scroll'],
-                    '0': False,
-                    '1': True,
-                    'True': True,
-                    'False': False,
-                    'on': True
-                }
+                locked=is_locked('infinite_scroll')
             ),
             ),
             # fmt: on
             # fmt: on
         }
         }
@@ -534,6 +522,13 @@ class Preferences:
         disabled_engines = []
         disabled_engines = []
         enabled_categories = []
         enabled_categories = []
         disabled_plugins = []
         disabled_plugins = []
+
+        # boolean preferences are not sent by the form if they're false,
+        # so we have to add them as false manually if they're not sent (then they would be true)
+        for key, setting in self.key_value_settings.items():
+            if key not in input_data.keys() and isinstance(setting, BooleanSetting):
+                input_data[key] = 'False'
+
         for user_setting_name, user_setting in input_data.items():
         for user_setting_name, user_setting in input_data.items():
             if user_setting_name in self.key_value_settings:
             if user_setting_name in self.key_value_settings:
                 self.key_value_settings[user_setting_name].parse(user_setting)
                 self.key_value_settings[user_setting_name].parse(user_setting)