forms.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. from django import forms
  2. from django.utils.translation import ungettext, ugettext_lazy as _
  3. from mptt.forms import TreeNodeChoiceField
  4. from misago.forms import Form
  5. from misago.forums.models import Forum
  6. from misago.utils import slugify
  7. from misago.utils.validators import validate_sluggable
  8. class ThreadNameMixin(object):
  9. def clean_thread_name(self):
  10. data = self.cleaned_data['thread_name']
  11. slug = slugify(data)
  12. if len(slug) < self.request.settings['thread_name_min']:
  13. raise forms.ValidationError(ungettext(
  14. "Thread name must contain at least one alpha-numeric character.",
  15. "Thread name must contain at least %(count)d alpha-numeric characters.",
  16. self.request.settings['thread_name_min']
  17. ) % {'count': self.request.settings['thread_name_min']})
  18. if len(data) > self.request.settings['thread_name_max']:
  19. raise forms.ValidationError(ungettext(
  20. "Thread name cannot be longer than %(count)d character.",
  21. "Thread name cannot be longer than %(count)d characters.",
  22. self.request.settings['thread_name_max']
  23. ) % {'count': self.request.settings['thread_name_max']})
  24. return data
  25. class PostForm(Form, ThreadNameMixin):
  26. post = forms.CharField(widget=forms.Textarea)
  27. def __init__(self, data=None, file=None, request=None, mode=None, *args, **kwargs):
  28. self.mode = mode
  29. super(PostForm, self).__init__(data, file, request=request, *args, **kwargs)
  30. def finalize_form(self):
  31. self.layout = [
  32. [
  33. None,
  34. [
  35. ('thread_name', {'label': _("Thread Name")}),
  36. ('edit_reason', {'label': _("Edit Reason")}),
  37. ('post', {'label': _("Post Content")}),
  38. ],
  39. ],
  40. ]
  41. if self.mode in ['edit_thread', 'edit_post']:
  42. self.fields['edit_reason'] = forms.CharField(max_length=255,required=False,help_text=_("Optional reason for changing this post."))
  43. else:
  44. del self.layout[0][1][1]
  45. if self.mode not in ['edit_thread', 'new_thread']:
  46. del self.layout[0][1][0]
  47. else:
  48. self.fields['thread_name'] = forms.CharField(
  49. max_length=self.request.settings['thread_name_max'],
  50. validators=[validate_sluggable(
  51. _("Thread name must contain at least one alpha-numeric character."),
  52. _("Thread name is too long. Try shorter name.")
  53. )])
  54. def clean_post(self):
  55. data = self.cleaned_data['post']
  56. if len(data) < self.request.settings['post_length_min']:
  57. raise forms.ValidationError(ungettext(
  58. "Post content cannot be empty.",
  59. "Post content cannot be shorter than %(count)d characters.",
  60. self.request.settings['post_length_min']
  61. ) % {'count': self.request.settings['post_length_min']})
  62. return data
  63. class SplitThreadForm(Form, ThreadNameMixin):
  64. pass
  65. class QuickReplyForm(Form):
  66. post = forms.CharField(widget=forms.Textarea)
  67. class MoveThreadsForm(Form):
  68. error_source = 'new_forum'
  69. def __init__(self, data=None, request=None, forum=None, *args, **kwargs):
  70. self.forum = forum
  71. super(MoveThreadsForm, self).__init__(data, request=request, *args, **kwargs)
  72. def finalize_form(self):
  73. self.fields['new_forum'] = TreeNodeChoiceField(queryset=Forum.tree.get(token='root').get_descendants().filter(pk__in=self.request.acl.forums.acl['can_browse']),level_indicator=u'- - ')
  74. self.layout = [
  75. [
  76. _("Thread Options"),
  77. [
  78. ('new_forum', {'label': _("Move Thread to"), 'help_text': _("Select forum you want to move threads to.")}),
  79. ],
  80. ],
  81. ]
  82. def clean_new_forum(self):
  83. new_forum = self.cleaned_data['new_forum']
  84. # Assert its forum and its not current forum
  85. if new_forum.type != 'forum':
  86. raise forms.ValidationError(_("This is not forum."))
  87. if new_forum.pk == self.forum.pk:
  88. raise forms.ValidationError(_("New forum is same as current one."))
  89. return new_forum
  90. class MergeThreadsForm(Form, ThreadNameMixin):
  91. def __init__(self, data=None, request=None, threads=[], *args, **kwargs):
  92. self.threads = threads
  93. super(MergeThreadsForm, self).__init__(data, request=request, *args, **kwargs)
  94. def finalize_form(self):
  95. self.fields['thread_name'] = forms.CharField(
  96. max_length=self.request.settings['thread_name_max'],
  97. initial=self.threads[0].name,
  98. validators=[validate_sluggable(
  99. _("Thread name must contain at least one alpha-numeric character."),
  100. _("Thread name is too long. Try shorter name.")
  101. )])
  102. self.layout = [
  103. [
  104. _("Thread Options"),
  105. [
  106. ('thread_name', {'label': _("Thread Name"), 'help_text': _("Name of new thread that will be created as result of merge.")}),
  107. ],
  108. ],
  109. [
  110. _("Merge Order"),
  111. [
  112. ],
  113. ],
  114. ]
  115. choices = []
  116. for i, thread in enumerate(self.threads):
  117. choices.append((str(i), i + 1))
  118. for i, thread in enumerate(self.threads):
  119. self.fields['thread_%s' % thread.pk] = forms.ChoiceField(choices=choices,initial=str(i))
  120. self.layout[1][1].append(('thread_%s' % thread.pk, {'label': thread.name}))
  121. def clean(self):
  122. cleaned_data = super(MergeThreadsForm, self).clean()
  123. self.merge_order = {}
  124. lookback = []
  125. for thread in self.threads:
  126. order = int(cleaned_data['thread_%s' % thread.pk])
  127. if order in lookback:
  128. raise forms.ValidationError(_("One or more threads have same position in merge order."))
  129. lookback.append(order)
  130. self.merge_order[order] = thread
  131. return cleaned_data