comparison forums/forms.py @ 581:ee87ea74d46b

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