Coverage for seedboxsync/front/views/settings.py: 95%

65 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-07-26 17:46 +0000

1# 

2# Copyright (C) 2015-2026 Guillaume Kulakowski <guillaume@kulakowski.fr> 

3# 

4# For the full copyright and license information, please view the LICENSE 

5# file that was distributed with this source code. 

6# 

7"""SeedboxSync Flask vierw for settings.""" 

8 

9from collections.abc import Iterable 

10from typing import Any 

11from flask import flash, render_template, request 

12from flask.wrappers import Request 

13from flask_babel import gettext 

14from seedboxsync.core import Config, current_app as app 

15from seedboxsync.core.dao import SeedboxSync 

16from seedboxsync.front.babel import ALLOWED_LANGUAGES 

17from seedboxsync.front.utils import init_flash 

18from seedboxsync.front.views import bp 

19 

20 

21@bp.route("/settings", methods=("GET", "POST")) 

22def settings() -> str: 

23 """Manage settings: load configuration, display form, persist changes.""" 

24 init_flash() 

25 saved = False 

26 languages_list = ALLOWED_LANGUAGES 

27 

28 form = _build_form() 

29 

30 if request.method == "POST": 

31 missing = [f for f in _required_form_fields() if not request.form.get(f)] 

32 if missing: 

33 flash( 

34 gettext("Missing required fields: %(missing)s", missing=", ".join(missing)), 

35 "error", 

36 ) 

37 else: 

38 try: 

39 _save_form(request) 

40 form = _build_form() # reload cleaned values 

41 saved = True 

42 except Exception as e: 

43 app.logger.exception("Failed to save config", exc_info=e) 

44 flash(gettext("Failed to save configuration."), "error") 

45 

46 return render_template("settings.html", form=form, saved=saved, languages_list=languages_list) 

47 

48 

49# ------------------------- 

50# Helpers 

51# ------------------------- 

52def _required_form_fields() -> Iterable[str]: 

53 """ 

54 List of all requitred fields. 

55 

56 Returns: 

57 True if the value represents an enabled/true state, otherwise False. 

58 """ 

59 return [ 

60 "seedbox_host", 

61 "seedbox_port", 

62 "seedbox_login", 

63 "seedbox_password", 

64 "seedbox_protocol", 

65 "seedbox_tmp_path", 

66 "seedbox_watch_path", 

67 "seedbox_finished_path", 

68 "seedbox_part_suffix", 

69 ] 

70 

71 

72def _build_form() -> dict[str, Any]: 

73 """ 

74 Build form fields. 

75 

76 Returns: 

77 Dictionnary of fields. 

78 """ 

79 fields = {key: ((1 if value else 0) if key.endswith("_enabled") else (0 if value is False else value)) for key, value in app.seedboxsync_config.items()} 

80 fields.setdefault( 

81 "seedbox_timeout_enabled", 

82 "1" if fields.get("seedbox_timeout", "0") not in ["", "0", False] else "0", 

83 ) 

84 fields.setdefault( 

85 "seedbox_chmod_enabled", 

86 "1" if fields.get("seedbox_chmod", "0") not in ["", "0", False] else "0", 

87 ) 

88 

89 return fields 

90 

91 

92def _save_form(req: Request) -> None: 

93 """Save form data to the configuration file.""" 

94 seedbox_timeout_enabled = req.form.get("seedbox_timeout_enabled", "0") == "1" 

95 seedbox_chmod_enabled = req.form.get("seedbox_chmod_enabled", "0") == "1" 

96 fields = app.seedboxsync_config 

97 config_to_db: list[dict[str, str]] = [] 

98 config_to_update: dict[str, Any] = {} 

99 db_value: str = "0" 

100 value: str | bool = False 

101 

102 for key in fields: 

103 if key in req.form: 

104 value = str(req.form[key] or "").strip() 

105 db_value = value 

106 if key.endswith("_enabled"): 

107 value = bool(int(value)) 

108 elif key not in req.form and key.endswith("_enabled"): 

109 value = False 

110 db_value = "0" 

111 

112 app.logger.debug(f"Updated config[{Config.CONFIG_NAMESPACE}{key.upper()}] = {value}") 

113 config_to_update[f"{Config.CONFIG_NAMESPACE}{key.upper()}"] = value 

114 config_to_db.append( 

115 { 

116 "key": f"{Config.DB_CONFIG_PREFIX}{key}", 

117 "value": db_value, 

118 } 

119 ) 

120 

121 if not seedbox_timeout_enabled: 

122 app.logger.debug(f"Updated config[{Config.CONFIG_NAMESPACE}SEEDBOX_TIMEOUT] = False") 

123 config_to_update[f"{Config.CONFIG_NAMESPACE}SEEDBOX_TIMEOUT"] = False 

124 config_to_db.append( 

125 { 

126 "key": f"{Config.DB_CONFIG_PREFIX}seedbox_timeout", 

127 "value": "0", 

128 } 

129 ) 

130 

131 if not seedbox_chmod_enabled: 

132 app.logger.debug(f"Updated config[{Config.CONFIG_NAMESPACE}SEEDBOX_CHMOD] = False") 

133 config_to_update[f"{Config.CONFIG_NAMESPACE}SEEDBOX_CHMOD"] = False 

134 config_to_db.append( 

135 { 

136 "key": f"{Config.DB_CONFIG_PREFIX}seedbox_chmod", 

137 "value": "0", 

138 } 

139 ) 

140 

141 # Update config in Flask app 

142 app.config.from_mapping(config_to_update) 

143 

144 # Save in database 

145 SeedboxSync.replace_many(config_to_db).execute() # type: ignore[no-untyped-call]