bgneal@83
|
1 """
|
bgneal@83
|
2 Forms for the forums application.
|
bgneal@83
|
3 """
|
bgneal@83
|
4 from django import forms
|
bgneal@95
|
5 from django.conf import settings
|
bgneal@83
|
6
|
bgneal@110
|
7 from forums.models import Forum
|
bgneal@83
|
8 from forums.models import Topic
|
bgneal@83
|
9 from forums.models import Post
|
bgneal@285
|
10 from forums.attachments import AttachmentProcessor
|
bgneal@83
|
11
|
bgneal@83
|
12
|
bgneal@106
|
13 class NewPostForm(forms.Form):
|
bgneal@86
|
14 """Form for creating a new post."""
|
bgneal@286
|
15 body = forms.CharField(label='',
|
bgneal@286
|
16 required=False,
|
bgneal@135
|
17 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'}))
|
bgneal@89
|
18 topic_id = forms.IntegerField(widget=forms.HiddenInput)
|
bgneal@89
|
19 topic = None
|
bgneal@83
|
20
|
bgneal@89
|
21 class Media:
|
bgneal@95
|
22 css = {
|
bgneal@123
|
23 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] +
|
bgneal@123
|
24 settings.GPP_THIRD_PARTY_CSS['jquery-ui']),
|
bgneal@95
|
25 }
|
bgneal@286
|
26 js = (settings.GPP_THIRD_PARTY_JS['markitup'] +
|
bgneal@123
|
27 settings.GPP_THIRD_PARTY_JS['jquery-ui'] +
|
bgneal@123
|
28 ('js/forums.js', ))
|
bgneal@89
|
29
|
bgneal@285
|
30 def __init__(self, *args, **kwargs):
|
bgneal@285
|
31 super(NewPostForm, self).__init__(*args, **kwargs)
|
bgneal@285
|
32 attachments = args[0].getlist('attachment') if len(args) else []
|
bgneal@285
|
33 self.attach_proc = AttachmentProcessor(attachments)
|
bgneal@285
|
34
|
bgneal@286
|
35 def clean_body(self):
|
bgneal@286
|
36 data = self.cleaned_data['body']
|
bgneal@286
|
37 if not data and not self.attach_proc.has_attachments():
|
bgneal@286
|
38 raise forms.ValidationError("This field is required.")
|
bgneal@286
|
39 return data
|
bgneal@286
|
40
|
bgneal@89
|
41 def clean_topic_id(self):
|
bgneal@89
|
42 id = self.cleaned_data['topic_id']
|
bgneal@89
|
43 try:
|
bgneal@102
|
44 self.topic = Topic.objects.select_related().get(pk=id)
|
bgneal@89
|
45 except Topic.DoesNotExist:
|
bgneal@89
|
46 raise forms.ValidationError('invalid topic')
|
bgneal@286
|
47 return id
|
bgneal@89
|
48
|
bgneal@89
|
49 def save(self, user, ip=None):
|
bgneal@86
|
50 """
|
bgneal@86
|
51 Creates a new post from the form data and supplied arguments.
|
bgneal@86
|
52 """
|
bgneal@89
|
53 post = Post(topic=self.topic, user=user, body=self.cleaned_data['body'],
|
bgneal@89
|
54 user_ip=ip)
|
bgneal@86
|
55 post.save()
|
bgneal@285
|
56 self.attach_proc.save_attachments(post)
|
bgneal@89
|
57 return post
|
bgneal@83
|
58
|
bgneal@83
|
59
|
bgneal@83
|
60 class NewTopicForm(forms.Form):
|
bgneal@102
|
61 """
|
bgneal@102
|
62 Form for creating a new topic and 1st post to that topic.
|
bgneal@102
|
63 Superusers and moderators can also create the topic as a sticky or initially
|
bgneal@102
|
64 locked.
|
bgneal@102
|
65 """
|
bgneal@95
|
66 name = forms.CharField(label='Subject', max_length=255,
|
bgneal@95
|
67 widget=forms.TextInput(attrs={'size': 64}))
|
bgneal@286
|
68 body = forms.CharField(label='', required=False,
|
bgneal@135
|
69 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'}))
|
bgneal@102
|
70 user = None
|
bgneal@102
|
71 forum = None
|
bgneal@102
|
72 has_mod_fields = False
|
bgneal@83
|
73
|
bgneal@95
|
74 class Media:
|
bgneal@95
|
75 css = {
|
bgneal@123
|
76 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] +
|
bgneal@123
|
77 settings.GPP_THIRD_PARTY_CSS['jquery-ui']),
|
bgneal@95
|
78 }
|
bgneal@286
|
79 js = (settings.GPP_THIRD_PARTY_JS['markitup'] +
|
bgneal@123
|
80 settings.GPP_THIRD_PARTY_JS['jquery-ui'] +
|
bgneal@123
|
81 ('js/forums.js', ))
|
bgneal@95
|
82
|
bgneal@102
|
83 def __init__(self, user, forum, *args, **kwargs):
|
bgneal@102
|
84 super(NewTopicForm, self).__init__(*args, **kwargs)
|
bgneal@102
|
85 self.user = user
|
bgneal@102
|
86 self.forum = forum
|
bgneal@102
|
87
|
bgneal@102
|
88 if user.is_superuser or user in forum.moderators.all():
|
bgneal@102
|
89 self.fields['sticky'] = forms.BooleanField(required=False)
|
bgneal@102
|
90 self.fields['locked'] = forms.BooleanField(required=False)
|
bgneal@102
|
91 self.has_mod_fields = True
|
bgneal@102
|
92
|
bgneal@285
|
93 attachments = args[0].getlist('attachment') if len(args) else []
|
bgneal@285
|
94 self.attach_proc = AttachmentProcessor(attachments)
|
bgneal@285
|
95
|
bgneal@286
|
96 # If this form is being POSTed, and the user is trying to add
|
bgneal@286
|
97 # attachments, create hidden fields to list the Oembed ids. In
|
bgneal@286
|
98 # case the form isn't valid, the client-side javascript will know
|
bgneal@286
|
99 # which Oembed media to ask for when the form is displayed with
|
bgneal@286
|
100 # errors.
|
bgneal@286
|
101 if self.attach_proc.has_attachments():
|
bgneal@286
|
102 pks = self.attach_proc.get_ids()
|
bgneal@286
|
103 self.fields['attachment'] = forms.MultipleChoiceField(label='',
|
bgneal@286
|
104 widget=forms.MultipleHiddenInput(),
|
bgneal@286
|
105 choices=[(v, v) for v in pks])
|
bgneal@286
|
106
|
bgneal@286
|
107 def clean_body(self):
|
bgneal@286
|
108 data = self.cleaned_data['body']
|
bgneal@286
|
109 if not data and not self.attach_proc.has_attachments():
|
bgneal@286
|
110 raise forms.ValidationError("This field is required.")
|
bgneal@286
|
111 return data
|
bgneal@286
|
112
|
bgneal@102
|
113 def save(self, ip=None):
|
bgneal@83
|
114 """
|
bgneal@83
|
115 Creates the new Topic and first Post from the form data and supplied
|
bgneal@86
|
116 arguments.
|
bgneal@83
|
117 """
|
bgneal@102
|
118 topic = Topic(forum=self.forum,
|
bgneal@83
|
119 name=self.cleaned_data['name'],
|
bgneal@102
|
120 user=self.user,
|
bgneal@102
|
121 sticky=self.has_mod_fields and self.cleaned_data['sticky'],
|
bgneal@102
|
122 locked=self.has_mod_fields and self.cleaned_data['locked'])
|
bgneal@83
|
123 topic.save()
|
bgneal@83
|
124
|
bgneal@83
|
125 post = Post(topic=topic,
|
bgneal@102
|
126 user=self.user,
|
bgneal@83
|
127 body=self.cleaned_data['body'],
|
bgneal@83
|
128 user_ip=ip)
|
bgneal@83
|
129 post.save()
|
bgneal@285
|
130
|
bgneal@285
|
131 self.attach_proc.save_attachments(post)
|
bgneal@285
|
132
|
bgneal@83
|
133 return topic
|
bgneal@106
|
134
|
bgneal@106
|
135
|
bgneal@106
|
136 class PostForm(forms.ModelForm):
|
bgneal@106
|
137 """
|
bgneal@108
|
138 Form for editing an existing post or a new, non-quick post.
|
bgneal@106
|
139 """
|
bgneal@286
|
140 body = forms.CharField(label='',
|
bgneal@286
|
141 required=False,
|
bgneal@135
|
142 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'}))
|
bgneal@106
|
143
|
bgneal@106
|
144 class Meta:
|
bgneal@106
|
145 model = Post
|
bgneal@106
|
146 fields = ('body', )
|
bgneal@106
|
147
|
bgneal@106
|
148 class Media:
|
bgneal@106
|
149 css = {
|
bgneal@123
|
150 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] +
|
bgneal@123
|
151 settings.GPP_THIRD_PARTY_CSS['jquery-ui']),
|
bgneal@106
|
152 }
|
bgneal@286
|
153 js = (settings.GPP_THIRD_PARTY_JS['markitup'] +
|
bgneal@123
|
154 settings.GPP_THIRD_PARTY_JS['jquery-ui'] +
|
bgneal@123
|
155 ('js/forums.js', ))
|
bgneal@110
|
156
|
bgneal@286
|
157 def __init__(self, *args, **kwargs):
|
bgneal@286
|
158 super(PostForm, self).__init__(*args, **kwargs)
|
bgneal@286
|
159
|
bgneal@286
|
160 attachments = args[0].getlist('attachment') if len(args) else []
|
bgneal@286
|
161 self.attach_proc = AttachmentProcessor(attachments)
|
bgneal@286
|
162
|
bgneal@286
|
163 # If this form is being used to edit an existing post, and that post
|
bgneal@286
|
164 # has attachments, create a hidden post_id field. The client-side
|
bgneal@286
|
165 # AJAX will use this as a cue to retrieve the HTML for the embedded
|
bgneal@286
|
166 # media.
|
bgneal@286
|
167 if 'instance' in kwargs:
|
bgneal@286
|
168 post = kwargs['instance']
|
bgneal@286
|
169 if post.attachments.count():
|
bgneal@286
|
170 self.fields['post_id'] = forms.CharField(label='',
|
bgneal@286
|
171 widget=forms.HiddenInput(attrs={'value': post.id}))
|
bgneal@286
|
172
|
bgneal@286
|
173 def clean_body(self):
|
bgneal@286
|
174 data = self.cleaned_data['body']
|
bgneal@286
|
175 if not data and not self.attach_proc.has_attachments():
|
bgneal@286
|
176 raise forms.ValidationError('This field is required.')
|
bgneal@286
|
177 return data
|
bgneal@286
|
178
|
bgneal@110
|
179
|
bgneal@110
|
180 class MoveTopicForm(forms.Form):
|
bgneal@111
|
181 """
|
bgneal@111
|
182 Form for a moderator to move a topic to a forum.
|
bgneal@111
|
183 """
|
bgneal@286
|
184 forums = forms.ModelChoiceField(label='Move to forum',
|
bgneal@111
|
185 queryset=Forum.objects.none())
|
bgneal@110
|
186
|
bgneal@111
|
187 def __init__(self, user, *args, **kwargs):
|
bgneal@286
|
188 hide_label = kwargs.pop('hide_label', False)
|
bgneal@111
|
189 required = kwargs.pop('required', True)
|
bgneal@111
|
190 super(MoveTopicForm, self).__init__(*args, **kwargs)
|
bgneal@111
|
191 self.fields['forums'].queryset = \
|
bgneal@111
|
192 Forum.objects.forums_for_user(user).order_by('name')
|
bgneal@111
|
193 if hide_label:
|
bgneal@111
|
194 self.fields['forums'].label = ''
|
bgneal@111
|
195 self.fields['forums'].required = required
|
bgneal@110
|
196
|
bgneal@115
|
197
|
bgneal@115
|
198 class SplitTopicForm(forms.Form):
|
bgneal@115
|
199 """
|
bgneal@115
|
200 Form for a moderator to split posts from a topic to a new topic.
|
bgneal@115
|
201 """
|
bgneal@115
|
202 name = forms.CharField(label='New topic title', max_length=255,
|
bgneal@115
|
203 widget=forms.TextInput(attrs={'size': 64}))
|
bgneal@286
|
204 forums = forms.ModelChoiceField(label='Forum for new topic',
|
bgneal@115
|
205 queryset=Forum.objects.none())
|
bgneal@115
|
206 post_ids = []
|
bgneal@115
|
207 split_at = False
|
bgneal@115
|
208
|
bgneal@115
|
209 def __init__(self, user, *args, **kwargs):
|
bgneal@115
|
210 super(SplitTopicForm, self).__init__(*args, **kwargs)
|
bgneal@115
|
211 self.fields['forums'].queryset = \
|
bgneal@115
|
212 Forum.objects.forums_for_user(user).order_by('name')
|
bgneal@115
|
213
|
bgneal@115
|
214 def clean(self):
|
bgneal@115
|
215 self.post_ids = self.data.getlist('post_ids')
|
bgneal@115
|
216 if len(self.post_ids) == 0:
|
bgneal@115
|
217 raise forms.ValidationError('Please select some posts')
|
bgneal@115
|
218
|
bgneal@115
|
219 self.split_at = 'split-at' in self.data
|
bgneal@115
|
220 if self.split_at and len(self.post_ids) > 1:
|
bgneal@115
|
221 raise forms.ValidationError('Please select only one post to split the topic at')
|
bgneal@115
|
222
|
bgneal@115
|
223 return self.cleaned_data
|