Coverage for an_website/settings/settings.py: 92.857%

42 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-16 19:56 +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/>. 

13 

14"""The settings page used to change settings.""" 

15 

16from __future__ import annotations 

17 

18import contextlib 

19import types 

20from base64 import b64encode 

21from collections.abc import Awaitable, Mapping 

22 

23from tornado.web import HTTPError 

24 

25from ..utils.options import 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) 

34 

35 

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 ) 

50 

51 

52class SettingsPage(HTMLRequestHandler): 

53 """The request handler for the settings page.""" 

54 

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 ) 

65 

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 ) 

76 

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 ) 

92 

93 replace_url_with = self.fix_url( 

94 self.request.full_url(), 

95 access_token=None, 

96 advanced_settings=None, 

97 save_in_cookie=None, 

98 **dict.fromkeys(self.user_settings.iter_option_names()), 

99 ) 

100 else: 

101 replace_url_with = self.fix_url( 

102 self.request.full_url(), 

103 access_token=access_token, 

104 advanced_settings=advanced_settings, 

105 save_in_cookie=False, 

106 **self.user_settings.as_dict_with_str_values( 

107 include_cookie=False, include_query_argument=False 

108 ), 

109 ) 

110 

111 if replace_url_with != self.request.full_url(): 

112 return self.redirect(replace_url_with) 

113 

114 await self.render_settings( 

115 advanced_settings=advanced_settings, 

116 save_in_cookie=save_in_cookie, 

117 show_token_input=bool( 

118 token or self.get_bool_argument("auth", False) 

119 ), 

120 token=token, 

121 kwargs={ 

122 option.name: option.get_value( 

123 self, include_cookie=False, include_query_argument=False 

124 ) 

125 for option in self.user_settings.iter_options() 

126 }, 

127 ) 

128 

129 def render_settings( # pylint: disable=too-many-arguments 

130 self, 

131 *, 

132 save_in_cookie: bool, 

133 show_token_input: bool, 

134 token: str, 

135 advanced_settings: bool, 

136 kwargs: Mapping[str, object] = types.MappingProxyType({}), 

137 ) -> Awaitable[None]: 

138 """Render the settings page.""" 

139 return self.render( 

140 "pages/settings.html", 

141 advanced_settings=advanced_settings, 

142 ask_before_leaving_default=( 

143 Options.ask_before_leaving.get_default_value(self) 

144 ), 

145 bumpscosity_values=BUMPSCOSITY_VALUES, 

146 no_3rd_party_default=Options.no_3rd_party.get_default_value(self), 

147 save_in_cookie=save_in_cookie, 

148 show_token_input=show_token_input, 

149 themes=THEMES, 

150 token=token, 

151 **kwargs, 

152 ) 

153 

154 def show_advanced_settings(self) -> bool: 

155 """Whether advanced settings should be shown.""" 

156 if arg := self.get_argument("advanced_settings", ""): 

157 with contextlib.suppress(ValueError): 

158 return str_to_bool(arg) 

159 return str_to_bool(self.get_cookie("advanced_settings", ""), False)