[mod] add a Preferences.client property to store client prefs

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser 2023-01-30 18:40:22 +01:00
parent 5a3f99ee1a
commit c03b0ea650
2 changed files with 67 additions and 13 deletions

View File

@ -8,9 +8,10 @@
from base64 import urlsafe_b64encode, urlsafe_b64decode 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 from typing import Iterable, Dict, List, Optional
import flask import flask
import babel
from searx import settings, autocomplete from searx import settings, autocomplete
from searx.enginelib import Engine from searx.enginelib import Engine
@ -287,10 +288,65 @@ class PluginsSetting(BooleanChoices):
return [item[len('plugin_') :] for item in items] return [item[len('plugin_') :] for item in items]
class ClientPref:
"""Container to assemble client prefferences and settings."""
# hint: searx.webapp.get_client_settings should be moved into this class
locale: babel.Locale
"""Locale prefered by the client."""
def __init__(self, locale: Optional[babel.Locale] = None):
self.locale = locale
@property
def locale_tag(self):
if self.locale is None:
return None
tag = self.locale.language
if self.locale.territory:
tag += '-' + self.locale.territory
return tag
@classmethod
def from_http_request(cls, http_request: flask.Request):
"""Build ClientPref object from HTTP request.
- `Accept-Language used for locale setting
<https://www.w3.org/International/questions/qa-accept-lang-locales.en>`__
"""
al_header = http_request.headers.get("Accept-Language")
if not al_header:
return cls(locale=None)
pairs = []
for l in al_header.split(','):
# fmt: off
lang, qvalue = [_.strip() for _ in (l.split(';') + ['q=1',])[:2]]
# fmt: on
try:
qvalue = float(qvalue.split('=')[-1])
locale = babel.Locale.parse(lang, sep='-')
except (ValueError, babel.core.UnknownLocaleError):
continue
pairs.append((locale, qvalue))
pairs.sort(reverse=True, key=lambda x: x[1])
return cls(locale=pairs[0][0])
class Preferences: class Preferences:
"""Validates and saves preferences to cookies""" """Validates and saves preferences to cookies"""
def __init__(self, themes: List[str], categories: List[str], engines: Dict[str, Engine], plugins: Iterable[Plugin]): def __init__(
self,
themes: List[str],
categories: List[str],
engines: Dict[str, Engine],
plugins: Iterable[Plugin],
client: Optional[ClientPref] = None,
):
super().__init__() super().__init__()
self.key_value_settings: Dict[str, Setting] = { self.key_value_settings: Dict[str, Setting] = {
@ -414,6 +470,7 @@ class Preferences:
self.engines = EnginesSetting('engines', engines=engines.values()) self.engines = EnginesSetting('engines', engines=engines.values())
self.plugins = PluginsSetting('plugins', plugins=plugins) self.plugins = PluginsSetting('plugins', plugins=plugins)
self.tokens = SetSetting('tokens') self.tokens = SetSetting('tokens')
self.client = client or ClientPref()
self.unknown_params: Dict[str, str] = {} self.unknown_params: Dict[str, str] = {}
def get_as_url_params(self): def get_as_url_params(self):

View File

@ -96,6 +96,7 @@ from searx.plugins import Plugin, plugins, initialize as plugin_initialize
from searx.plugins.oa_doi_rewrite import get_doi_resolver from searx.plugins.oa_doi_rewrite import get_doi_resolver
from searx.preferences import ( from searx.preferences import (
Preferences, Preferences,
ClientPref,
ValidationException, ValidationException,
) )
from searx.answerers import ( from searx.answerers import (
@ -221,16 +222,9 @@ babel = Babel(app, locale_selector=get_locale)
def _get_browser_language(req, lang_list): def _get_browser_language(req, lang_list):
for lang in req.headers.get("Accept-Language", "en").split(","): client = ClientPref.from_http_request(req)
if ';' in lang: locale = match_locale(client.locale_tag, lang_list, fallback='en')
lang = lang.split(';')[0]
if '-' in lang:
lang_parts = lang.split('-')
lang = "{}-{}".format(lang_parts[0], lang_parts[-1].upper())
locale = match_locale(lang, lang_list, fallback=None)
if locale is not None:
return locale return locale
return 'en'
def _get_locale_rfc5646(locale): def _get_locale_rfc5646(locale):
@ -512,7 +506,10 @@ def pre_request():
request.timings = [] # pylint: disable=assigning-non-slot request.timings = [] # pylint: disable=assigning-non-slot
request.errors = [] # pylint: disable=assigning-non-slot request.errors = [] # pylint: disable=assigning-non-slot
preferences = Preferences(themes, list(categories.keys()), engines, plugins) # pylint: disable=redefined-outer-name client_pref = ClientPref.from_http_request(request)
# pylint: disable=redefined-outer-name
preferences = Preferences(themes, list(categories.keys()), engines, plugins, client_pref)
user_agent = request.headers.get('User-Agent', '').lower() user_agent = request.headers.get('User-Agent', '').lower()
if 'webkit' in user_agent and 'android' in user_agent: if 'webkit' in user_agent and 'android' in user_agent:
preferences.key_value_settings['method'].value = 'GET' preferences.key_value_settings['method'].value = 'GET'