forms.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. from django import forms
  2. from django.utils.translation import gettext_lazy as _
  3. from ...admin.forms import YesNoSwitch
  4. from ..cache import clear_settings_cache
  5. class ChangeSettingsForm(forms.Form):
  6. settings = []
  7. def __init__(self, *args, **kwargs):
  8. self.request = kwargs.pop("request")
  9. super().__init__(*args, **kwargs)
  10. def save(self, settings):
  11. self.save_settings(settings)
  12. self.clear_cache()
  13. def save_settings(self, settings):
  14. for setting in self.settings:
  15. setting_obj = settings[setting]
  16. new_value = self.cleaned_data.get(setting)
  17. if setting_obj.python_type == "image":
  18. if new_value and new_value != self.initial.get(setting):
  19. self.save_image(setting_obj, new_value)
  20. elif self.cleaned_data.get("%s_delete" % setting):
  21. self.delete_image(setting_obj)
  22. else:
  23. self.save_setting(setting_obj, new_value)
  24. def delete_image(self, setting):
  25. if setting.image:
  26. setting.image.delete()
  27. def save_image(self, setting, value):
  28. if setting.image:
  29. setting.image.delete(save=False)
  30. setting.value = value
  31. setting.save()
  32. def save_setting(self, setting, value):
  33. setting.value = value
  34. setting.save()
  35. def clear_cache(self):
  36. clear_settings_cache()
  37. class ChangeCaptchaSettingsForm(ChangeSettingsForm):
  38. settings = [
  39. "captcha_type",
  40. "recaptcha_site_key",
  41. "recaptcha_secret_key",
  42. "qa_question",
  43. "qa_help_text",
  44. "qa_answers",
  45. ]
  46. captcha_type = forms.ChoiceField(
  47. label=_("Enable CAPTCHA"),
  48. choices=[
  49. ("no", _("No CAPTCHA")),
  50. ("re", _("reCaptcha")),
  51. ("qa", _("Question and answer")),
  52. ],
  53. widget=forms.RadioSelect(),
  54. )
  55. recaptcha_site_key = forms.CharField(
  56. label=_("Site key"), max_length=100, required=False
  57. )
  58. recaptcha_secret_key = forms.CharField(
  59. label=_("Secret key"), max_length=100, required=False
  60. )
  61. qa_question = forms.CharField(
  62. label=_("Test question"), max_length=100, required=False
  63. )
  64. qa_help_text = forms.CharField(
  65. label=_("Question help text"), max_length=250, required=False
  66. )
  67. qa_answers = forms.CharField(
  68. label=_("Valid answers"),
  69. help_text=_("Enter each answer in new line. Answers are case-insensitive."),
  70. widget=forms.Textarea({"rows": 4}),
  71. max_length=250,
  72. required=False,
  73. )
  74. def clean(self):
  75. cleaned_data = super().clean()
  76. if cleaned_data.get("captcha_type") == "re":
  77. if not cleaned_data.get("recaptcha_site_key"):
  78. self.add_error(
  79. "recaptcha_site_key",
  80. _(
  81. "You need to enter site key if "
  82. "selected CAPTCHA type is reCaptcha."
  83. ),
  84. )
  85. if not cleaned_data.get("recaptcha_secret_key"):
  86. self.add_error(
  87. "recaptcha_secret_key",
  88. _(
  89. "You need to enter secret key if "
  90. "selected CAPTCHA type is reCaptcha."
  91. ),
  92. )
  93. if cleaned_data.get("captcha_type") == "qa":
  94. if not cleaned_data.get("qa_question"):
  95. self.add_error(
  96. "qa_question",
  97. _("You need to set question if selected CAPTCHA type is Q&A."),
  98. )
  99. if not cleaned_data.get("qa_answers"):
  100. self.add_error(
  101. "qa_answers",
  102. _(
  103. "You need to set question answers if "
  104. "selected CAPTCHA type is Q&A."
  105. ),
  106. )
  107. return cleaned_data
  108. class ChangeGeneralSettingsForm(ChangeSettingsForm):
  109. settings = [
  110. "forum_name",
  111. "forum_address",
  112. "index_header",
  113. "index_title",
  114. "index_meta_description",
  115. "logo",
  116. "logo_small",
  117. "logo_text",
  118. "forum_footnote",
  119. "email_footer",
  120. ]
  121. forum_name = forms.CharField(label=_("Forum name"), min_length=2, max_length=255)
  122. forum_address = forms.URLField(label=_("Forum address"), max_length=255)
  123. index_header = forms.CharField(
  124. label=_("Header text"),
  125. help_text=_("This text will replace forum name in page header."),
  126. max_length=255,
  127. required=False,
  128. )
  129. index_title = forms.CharField(label=_("Page title"), max_length=255, required=False)
  130. index_meta_description = forms.CharField(
  131. label=_("Meta Description"),
  132. help_text=_(
  133. "Short description of your forum that search and social sites may "
  134. "display next to link to your forum's index."
  135. ),
  136. max_length=255,
  137. required=False,
  138. )
  139. logo = forms.ImageField(
  140. label=_("Logo"),
  141. help_text=_("Image that will displayed in forum navbar."),
  142. required=False,
  143. )
  144. logo_delete = forms.BooleanField(label=_("Delete current logo"), required=False)
  145. logo_small = forms.ImageField(
  146. label=_("Small logo"),
  147. help_text=_(
  148. "Image that will be displayed in compact forum navbar. "
  149. "When set, it will replace icon pointing to forum index."
  150. ),
  151. required=False,
  152. )
  153. logo_small_delete = forms.BooleanField(
  154. label=_("Delete current small logo"), required=False
  155. )
  156. logo_text = forms.CharField(
  157. label=_("Text"),
  158. help_text=_(
  159. "Text displayed in forum navbar. If logo image was uploaded, text will "
  160. "be displayed right next to it. Never displayed by the compact navbar."
  161. ),
  162. max_length=255,
  163. required=False,
  164. )
  165. forum_footnote = forms.CharField(
  166. label=_("Forum footnote"),
  167. help_text=_("Short message displayed in forum footer."),
  168. max_length=300,
  169. required=False,
  170. )
  171. email_footer = forms.CharField(
  172. label=_("E-mails footer"),
  173. help_text=_(
  174. "Optional short message included at the end of e-mails sent by forum."
  175. ),
  176. max_length=255,
  177. required=False,
  178. )
  179. def __init__(self, *args, **kwargs):
  180. super().__init__(*args, **kwargs)
  181. address = self.request.build_absolute_uri("/")
  182. self["forum_address"].help_text = _(
  183. "Misago uses this setting to build links in e-mails sent to site "
  184. 'users. Address under which site is running appears to be "%(address)s".'
  185. ) % {"address": address}
  186. def clean_forum_address(self):
  187. return self.cleaned_data["forum_address"].lower()
  188. class ChangeThreadsSettingsForm(ChangeSettingsForm):
  189. settings = [
  190. "post_length_max",
  191. "post_length_min",
  192. "thread_title_length_max",
  193. "thread_title_length_min",
  194. ]
  195. post_length_max = forms.IntegerField(
  196. label=_("Maximum allowed post length"), min_value=0
  197. )
  198. post_length_min = forms.IntegerField(
  199. label=_("Minimum required post length"), min_value=1
  200. )
  201. thread_title_length_max = forms.IntegerField(
  202. label=_("Maximum allowed thread title length"), min_value=2, max_value=255
  203. )
  204. thread_title_length_min = forms.IntegerField(
  205. label=_("Minimum required thread title length"), min_value=2, max_value=255
  206. )
  207. class ChangeUsersSettingsForm(ChangeSettingsForm):
  208. settings = [
  209. "account_activation",
  210. "allow_custom_avatars",
  211. "avatar_upload_limit",
  212. "default_avatar",
  213. "default_gravatar_fallback",
  214. "signature_length_max",
  215. "subscribe_reply",
  216. "subscribe_start",
  217. "username_length_max",
  218. "username_length_min",
  219. ]
  220. account_activation = forms.ChoiceField(
  221. label=_("Require new accounts activation"),
  222. choices=[
  223. ("none", _("No activation required")),
  224. ("user", _("Activation token sent to user e-mail")),
  225. ("admin", _("Activation by administrator")),
  226. ("closed", _("Disable new registrations")),
  227. ],
  228. widget=forms.RadioSelect(),
  229. )
  230. username_length_min = forms.IntegerField(
  231. label=_("Minimum allowed username length"), min_value=2, max_value=20
  232. )
  233. username_length_max = forms.IntegerField(
  234. label=_("Maximum allowed username length"), min_value=2, max_value=20
  235. )
  236. allow_custom_avatars = YesNoSwitch(
  237. label=_("Allow custom avatar uploads"),
  238. help_text=_(
  239. "Turning this option off will forbid forum users from uploading custom "
  240. "avatars. Good for forums adressed at young users."
  241. ),
  242. )
  243. avatar_upload_limit = forms.IntegerField(
  244. label=_("Maximum size of uploaded avatar"),
  245. help_text=_("Enter maximum allowed file size (in KB) for avatar uploads."),
  246. min_value=0,
  247. )
  248. default_avatar = forms.ChoiceField(
  249. label=_("Default avatar"),
  250. choices=[
  251. ("dynamic", _("Individual")),
  252. ("gravatar", _("Gravatar")),
  253. ("gallery", _("Random avatar from gallery")),
  254. ],
  255. widget=forms.RadioSelect(),
  256. )
  257. default_gravatar_fallback = forms.ChoiceField(
  258. label=_("Fallback for default gravatar"),
  259. help_text=_(
  260. "Select which avatar to use when user has no gravatar associated with "
  261. "their e-mail address."
  262. ),
  263. choices=[
  264. ("dynamic", _("Individual")),
  265. ("gallery", _("Random avatar from gallery")),
  266. ],
  267. widget=forms.RadioSelect(),
  268. )
  269. signature_length_max = forms.IntegerField(
  270. label=_("Maximum allowed signature length"), min_value=10, max_value=5000
  271. )
  272. subscribe_start = forms.ChoiceField(
  273. label=_("Started threads"),
  274. choices=[
  275. ("no", _("Don't watch")),
  276. ("watch", _("Put on watched threads list")),
  277. (
  278. "watch_email",
  279. _("Put on watched threads list and e-mail user when somebody replies"),
  280. ),
  281. ],
  282. widget=forms.RadioSelect(),
  283. )
  284. subscribe_reply = forms.ChoiceField(
  285. label=_("Replied threads"),
  286. choices=[
  287. ("no", _("Don't watch")),
  288. ("watch", _("Put on watched threads list")),
  289. (
  290. "watch_email",
  291. _("Put on watched threads list and e-mail user when somebody replies"),
  292. ),
  293. ],
  294. widget=forms.RadioSelect(),
  295. )