Coverage for an_website/settings/settings.py: 92.857%
42 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-07 13:44 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-07 13:44 +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."""
16from __future__ import annotations
18import contextlib
19import types
20from base64 import b64encode
21from collections.abc import Awaitable, Mapping
23from tornado.web import HTTPError
25from ..utils.options import COLOUR_SCHEMES, Options
26from ..utils.request_handler import HTMLRequestHandler
27from ..utils.themes import THEMES
28from ..utils.utils import (
29 BUMPSCOSITY_VALUES,
30 ModuleInfo,
31 bool_to_str,
32 str_to_bool,
33)
36def get_module_info() -> ModuleInfo:
37 """Create and return the ModuleInfo for this module."""
38 return ModuleInfo(
39 handlers=((r"/einstellungen", SettingsPage),),
40 name="Einstellungen",
41 description="Stelle wichtige Sachen ein",
42 path="/einstellungen",
43 keywords=(
44 "Einstellungen",
45 "Config",
46 "Settings",
47 ),
48 aliases=("/config", "/settings"),
49 )
52class SettingsPage(HTMLRequestHandler):
53 """The request handler for the settings page."""
55 async def get(self, *, head: bool = False) -> None:
56 """Handle GET requests to the settings page."""
57 if head:
58 return
59 await self.render_settings( # nosec: B106
60 save_in_cookie=self.get_bool_argument("save_in_cookie", True),
61 show_token_input=self.get_bool_argument("auth", False),
62 token="",
63 advanced_settings=self.show_advanced_settings(),
64 )
66 async def post(self) -> None:
67 """Handle POST requests to the settings page."""
68 if not self.request.body.strip():
69 raise HTTPError(400, "No body provided")
70 advanced_settings = self.get_bool_argument("advanced_settings", False)
71 save_in_cookie: bool = self.get_bool_argument("save_in_cookie", False)
72 token = self.get_argument("access_token", "")
73 access_token: None | str = (
74 b64encode(token.encode("UTF-8")).decode("ASCII") if token else None
75 )
77 if save_in_cookie:
78 if access_token:
79 self.set_cookie("access_token", access_token)
80 self.set_cookie("advanced_settings", bool_to_str(advanced_settings))
81 for option in self.user_settings.iter_options():
82 self.set_cookie(
83 option.name,
84 option.value_to_string(
85 option.get_value(
86 self,
87 include_cookie=False,
88 include_query_argument=False,
89 )
90 ),
91 httponly=option.httponly,
92 )
94 replace_url_with = self.fix_url(
95 self.request.full_url(),
96 access_token=None,
97 advanced_settings=None,
98 save_in_cookie=None,
99 **dict.fromkeys(self.user_settings.iter_option_names()),
100 )
101 else:
102 replace_url_with = self.fix_url(
103 self.request.full_url(),
104 access_token=access_token,
105 advanced_settings=advanced_settings,
106 save_in_cookie=False,
107 **self.user_settings.as_dict_with_str_values(
108 include_cookie=False, include_query_argument=False
109 ),
110 )
112 if replace_url_with != self.request.full_url():
113 return self.redirect(replace_url_with)
115 await self.render_settings(
116 advanced_settings=advanced_settings,
117 save_in_cookie=save_in_cookie,
118 show_token_input=bool(
119 token or self.get_bool_argument("auth", False)
120 ),
121 token=token,
122 kwargs={
123 option.name: option.get_value(
124 self, include_cookie=False, include_query_argument=False
125 )
126 for option in self.user_settings.iter_options()
127 },
128 )
130 def render_settings( # pylint: disable=too-many-arguments
131 self,
132 *,
133 save_in_cookie: bool,
134 show_token_input: bool,
135 token: str,
136 advanced_settings: bool,
137 kwargs: Mapping[str, object] = types.MappingProxyType({}),
138 ) -> Awaitable[None]:
139 """Render the settings page."""
140 return self.render(
141 "pages/settings.html",
142 advanced_settings=advanced_settings,
143 ask_before_leaving_default=(
144 Options.ask_before_leaving.get_default_value(self)
145 ),
146 bumpscosity_values=BUMPSCOSITY_VALUES,
147 no_3rd_party_default=Options.no_3rd_party.get_default_value(self),
148 save_in_cookie=save_in_cookie,
149 show_token_input=show_token_input,
150 themes=THEMES,
151 colour_schemes=COLOUR_SCHEMES,
152 token=token,
153 **kwargs,
154 )
156 def show_advanced_settings(self) -> bool:
157 """Whether advanced settings should be shown."""
158 if arg := self.get_argument("advanced_settings", ""):
159 with contextlib.suppress(ValueError):
160 return str_to_bool(arg)
161 return str_to_bool(self.get_cookie("advanced_settings", ""), False)