forms.py 9.3 KB

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