Coverage for an_website / settings / settings.py: 92.683%
41 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-24 17:35 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-24 17:35 +0000
1# This program is free software: you can redistribute it and/or modify
2# it under the terms of the GNU Affero General Public License as
3# published by the Free Software Foundation, either version 3 of the
4# License, or (at your option) any later version.
5#
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9# GNU Affero General Public License for more details.
10#
11# You should have received a copy of the GNU Affero General Public License
12# along with this program. If not, see <https://www.gnu.org/licenses/>.
14"""The settings page used to change settings."""
16import contextlib
17import types
18from base64 import b64encode
19from collections.abc import Awaitable, Mapping
21from tornado.web import HTTPError
23from ..utils.options import COLOUR_SCHEMES, Options
24from ..utils.request_handler import HTMLRequestHandler
25from ..utils.themes import THEMES
26from ..utils.utils import (
27 BUMPSCOSITY_VALUES,
28 ModuleInfo,
29 bool_to_str,
30 str_to_bool,
31)
34def get_module_info() -> ModuleInfo:
35 """Create and return the ModuleInfo for this module."""
36 return ModuleInfo(
37 handlers=((r"/einstellungen", SettingsPage),),
38 name="Einstellungen",
39 description="Stelle wichtige Sachen ein",
40 path="/einstellungen",
41 keywords=(
42 "Einstellungen",
43 "Config",
44 "Settings",
45 ),
46 aliases=("/config", "/settings"),
47 )
50class SettingsPage(HTMLRequestHandler):
51 """The request handler for the settings page."""
53 async def get(self, *, head: bool = False) -> None:
54 """Handle GET requests to the settings page."""
55 if head:
56 return
57 await self.render_settings( # nosec: B106
58 save_in_cookie=self.get_bool_argument("save_in_cookie", True),
59 show_token_input=self.get_bool_argument("auth", False),
60 token="",
61 advanced_settings=self.show_advanced_settings(),
62 )
64 async def post(self) -> None:
65 """Handle POST requests to the settings page."""
66 if not self.request.body.strip():
67 raise HTTPError(400, "No body provided")
68 advanced_settings = self.get_bool_argument("advanced_settings", False)
69 save_in_cookie: bool = self.get_bool_argument("save_in_cookie", False)
70 token = self.get_argument("access_token", "")
71 access_token: None | str = (
72 b64encode(token.encode("UTF-8")).decode("ASCII") if token else None
73 )
75 if save_in_cookie:
76 if access_token:
77 self.set_cookie("access_token", access_token)
78 self.set_cookie("advanced_settings", bool_to_str(advanced_settings))
79 for option in self.user_settings.iter_options():
80 self.set_cookie(
81 option.name,
82 option.value_to_string(
83 option.get_value(
84 self,
85 include_cookie=False,
86 include_query_argument=False,
87 )
88 ),
89 httponly=option.httponly,
90 )
92 replace_url_with = self.fix_url(
93 self.request.full_url(),
94 include_protocol_and_host=True,
95 query_args={
96 "access_token": None, # nosec B105:hardcoded_password_string
97 "advanced_settings": None,
98 "save_in_cookie": None,
99 **dict.fromkeys(self.user_settings.iter_option_names()),
100 },
101 )
102 else:
103 replace_url_with = self.fix_url(
104 self.request.full_url(),
105 include_protocol_and_host=True,
106 query_args={
107 "access_token": access_token,
108 "advanced_settings": advanced_settings,
109 "save_in_cookie": False,
110 **self.user_settings.as_dict_with_str_values(
111 include_cookie=False, include_query_argument=False
112 ),
113 },
114 )
116 if replace_url_with != self.request.full_url():
117 return self.redirect(replace_url_with)
119 await self.render_settings(
120 advanced_settings=advanced_settings,
121 save_in_cookie=save_in_cookie,
122 show_token_input=bool(
123 token or self.get_bool_argument("auth", False)
124 ),
125 token=token,
126 kwargs={
127 option.name: option.get_value(
128 self, include_cookie=False, include_query_argument=False
129 )
130 for option in self.user_settings.iter_options()
131 },
132 )
134 def render_settings( # pylint: disable=too-many-arguments
135 self,
136 *,
137 save_in_cookie: bool,
138 show_token_input: bool,
139 token: str,
140 advanced_settings: bool,
141 kwargs: Mapping[str, object] = types.MappingProxyType({}),
142 ) -> Awaitable[None]:
143 """Render the settings page."""
144 return self.render(
145 "pages/settings.html",
146 advanced_settings=advanced_settings,
147 ask_before_leaving_default=(
148 Options.ask_before_leaving.get_default_value(self)
149 ),
150 bumpscosity_values=BUMPSCOSITY_VALUES,
151 no_3rd_party_default=Options.no_3rd_party.get_default_value(self),
152 save_in_cookie=save_in_cookie,
153 show_token_input=show_token_input,
154 themes=THEMES,
155 colour_schemes=COLOUR_SCHEMES,
156 token=token,
157 **kwargs,
158 )
160 def show_advanced_settings(self) -> bool:
161 """Whether advanced settings should be shown."""
162 if arg := self.get_argument("advanced_settings", ""):
163 with contextlib.suppress(ValueError):
164 return str_to_bool(arg)
165 return str_to_bool(self.get_cookie("advanced_settings", ""), False)