forms.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. from django.utils.translation import ungettext, ugettext_lazy as _
  2. import floppyforms as forms
  3. from misago.apps.threadtype.posting.forms import NewThreadForm as NewThreadFormBase, EditThreadForm as EditThreadFormBase
  4. from misago.forms import Form
  5. from misago.models import ThreadPrefix
  6. from misago.validators import validate_sluggable
  7. class PollFormMixin(object):
  8. def create_poll_form(self):
  9. self.add_field('poll_question',
  10. forms.CharField(label=_("Poll Question"),
  11. required=False))
  12. self.add_field('poll_choices',
  13. forms.CharField(label=_("Poll Choices"),
  14. help_text=_("Enter options poll members will vote on, every one in new line."),
  15. required=False,
  16. widget=forms.Textarea))
  17. self.add_field('poll_max_choices',
  18. forms.IntegerField(label=_("Choices Per User"),
  19. help_text=_("Select on how many options individual user will be able to vote on."),
  20. min_value=1,
  21. initial=1))
  22. self.add_field('poll_length',
  23. forms.IntegerField(label=_("Poll Length"),
  24. help_text=_("Number of days since poll creations users will be allowed to vote in poll. Enter zero for permanent poll."),
  25. min_value=0,
  26. initial=0))
  27. self.add_field('poll_public',
  28. forms.BooleanField(label=_("Public Voting"),
  29. required=False))
  30. self.add_field('poll_changing_votes',
  31. forms.BooleanField(label=_("Allow Changing Votes"),
  32. required=False))
  33. def edit_poll_form(self):
  34. self.add_field('poll_question',
  35. forms.CharField(label=_("Poll Question"),
  36. initial=self.poll.question))
  37. self.add_field('poll_choices',
  38. forms.CharField(label=_("Add New Choices"),
  39. help_text=_("If you want, you can add new options to poll. Enter every option in new line."),
  40. required=False,
  41. widget=forms.Textarea))
  42. self.add_field('poll_max_choices',
  43. forms.IntegerField(label=_("Choices Per User"),
  44. help_text=_("Select on how many options individual user will be able to vote on."),
  45. min_value=1,
  46. initial=self.poll.max_choices))
  47. self.add_field('poll_length',
  48. forms.IntegerField(label=_("Poll Length"),
  49. help_text=_("Number of days since poll creations users will be allowed to vote in poll. Enter zero for permanent poll."),
  50. min_value=0,
  51. initial=self.poll.length))
  52. self.add_field('poll_changing_votes',
  53. forms.BooleanField(label=_("Allow Changing Votes"),
  54. required=False,
  55. initial=self.poll.vote_changing))
  56. def clean_poll_question(self):
  57. data = self.cleaned_data['poll_question'].strip()
  58. if data or self.poll:
  59. if len(data) < 3:
  60. raise forms.ValidationError(_("Poll quesiton should be at least three characters long."))
  61. if len(data) > 255:
  62. raise forms.ValidationError(_("Poll quesiton should be no longer than 250 characters."))
  63. return data
  64. def clean_poll_choices(self):
  65. self.clean_choices = []
  66. self.new_choices = []
  67. data = self.cleaned_data['poll_choices']
  68. if self.poll:
  69. self.clean_poll_edited_choices()
  70. if data:
  71. for choice in data.splitlines():
  72. choice = choice.strip()
  73. if not choice in self.clean_choices:
  74. if len(choice) < 2:
  75. raise forms.ValidationError(_("Poll choices should be at least two characters long."))
  76. if len(choice) > 250:
  77. raise forms.ValidationError(_("Poll choices should be no longer than 250 characters."))
  78. self.clean_choices.append(choice)
  79. self.new_choices.append(choice)
  80. if len(self.clean_choices) < 2:
  81. raise forms.ValidationError(_("Poll needs at least two choices."))
  82. if len(self.clean_choices) > 10:
  83. raise forms.ValidationError(_("Poll cannot have more than 10 choices."))
  84. return '\r\n'.join(self.clean_choices)
  85. def clean_poll_edited_choices(self):
  86. self.changed_choices = []
  87. self.deleted_choices = []
  88. for option in self.poll.option_set.all():
  89. new_name = self.request.POST.get('poll_current_choices[%s]' % option.pk, u'')
  90. new_name = new_name.strip()
  91. if new_name:
  92. self.clean_choices.append(new_name)
  93. if new_name != option.name:
  94. option.name = new_name
  95. self.changed_choices.append(option)
  96. else:
  97. self.deleted_choices.append(option)
  98. def clean_poll_max_choices(self):
  99. data = self.cleaned_data['poll_max_choices']
  100. if data < 1:
  101. raise forms.ValidationError(_("Voters must be allowed to make at least one choice."))
  102. if self.clean_choices and data > len(self.clean_choices):
  103. raise forms.ValidationError(_("Users cannot cast more votes than there are options."))
  104. return data
  105. def clean_poll_length(self):
  106. data = self.cleaned_data['poll_length']
  107. if data < 0:
  108. raise forms.ValidationError(_("Poll length cannot be negative."))
  109. if data > 300:
  110. raise forms.ValidationError(_("Poll length cannot be longer than 300 days."))
  111. if self.poll:
  112. org_length = self.poll.length
  113. self.poll.length = data
  114. try:
  115. if self.poll.over:
  116. raise forms.ValidationError(_("You cannot close poll that way."))
  117. finally:
  118. org_length = self.poll.length
  119. self.poll.length = org_length
  120. return data
  121. def clean_poll(self, data):
  122. try:
  123. if bool(data['poll_question']) != bool(self.clean_choices):
  124. if bool(data['poll_question']):
  125. raise forms.ValidationError(_("You have to define poll choices."))
  126. else:
  127. raise forms.ValidationError(_("You have to define poll question."))
  128. except KeyError:
  129. pass
  130. return data
  131. class ThreadPrefixMixin(object):
  132. def create_prefix_form(self):
  133. self.prefixes = ThreadPrefix.objects.forum_prefixes(self.forum)
  134. if self.prefixes:
  135. self.add_field('thread_prefix',
  136. forms.TypedChoiceField(label=_("Thread Prefix"),
  137. choices=[(0, _("No prefix"))] + [(p.pk, _(p.name)) for p in self.prefixes.values()],
  138. coerce=int, required=False, empty_value=0, initial=self.thread.prefix_id if self.thread else None))
  139. class NewThreadForm(NewThreadFormBase, PollFormMixin, ThreadPrefixMixin):
  140. def type_fields(self):
  141. self.poll = None
  142. if self.request.acl.threads.can_make_polls(self.forum):
  143. self.create_poll_form()
  144. if self.request.acl.threads.can_change_prefix(self.forum):
  145. self.create_prefix_form()
  146. def clean(self):
  147. data = super(NewThreadForm, self).clean()
  148. data = self.clean_poll(data)
  149. return data
  150. class EditThreadForm(EditThreadFormBase, PollFormMixin, ThreadPrefixMixin):
  151. def type_fields(self):
  152. self.poll = self.thread.poll
  153. if self.poll:
  154. if self.request.acl.threads.can_edit_poll(self.forum, self.poll):
  155. self.edit_poll_form()
  156. else:
  157. if self.request.acl.threads.can_make_polls(self.forum):
  158. self.create_poll_form()
  159. if self.poll and self.request.acl.threads.can_delete_poll(self.forum, self.poll):
  160. self.add_field('poll_delete',
  161. forms.BooleanField(label=_("Delete poll"),
  162. required=False))
  163. if self.request.acl.threads.can_change_prefix(self.forum):
  164. self.create_prefix_form()
  165. def clean(self):
  166. data = super(EditThreadForm, self).clean()
  167. data = self.clean_poll(data)
  168. return data
  169. class PollVoteForm(Form):
  170. def __init__(self, *args, **kwargs):
  171. self.poll = kwargs.pop('poll')
  172. super(PollVoteForm, self).__init__(*args, **kwargs)
  173. def finalize_form(self):
  174. choices = []
  175. for choice in self.poll.choices_cache:
  176. choices.append((choice['pk'], choice['name']))
  177. if self.poll.max_choices > 1:
  178. self.add_field('options',
  179. forms.TypedMultipleChoiceField(choices=choices, coerce=int, required=False,
  180. widget=forms.CheckboxSelectMultiple))
  181. else:
  182. self.add_field('options',
  183. forms.TypedChoiceField(choices=choices, coerce=int, required=False,
  184. widget=forms.RadioSelect))
  185. def clean_options(self):
  186. data = self.cleaned_data['options']
  187. try:
  188. if not data:
  189. raise forms.ValidationError(_("You have to make selection."))
  190. if len(data) > self.poll.max_choices:
  191. raise forms.ValidationError(ungettext("You cannot select more than one option.",
  192. "You cannot select more than %(limit)s options.",
  193. self.poll.max_choices) % {'limit': self.poll.max_choices})
  194. except TypeError:
  195. pass
  196. return data