comparison gpp/forums/forms.py @ 286:72fd300685d5

For #95. You can now make posts with no text in the body if you have attachments. And now if you create a new topic with an attachment, and the POST fails (say you forgot the topic title), we will now re-attach attachments. Also fixed a bug in the smiley code that would arise if it was asked to markup an empty string.
author Brian Neal <bgneal@gmail.com>
date Sat, 23 Oct 2010 20:19:46 +0000
parents 8fd4984d5c3b
children 26fc9ac9a0eb
comparison
equal deleted inserted replaced
285:8fd4984d5c3b 286:72fd300685d5
10 from forums.attachments import AttachmentProcessor 10 from forums.attachments import AttachmentProcessor
11 11
12 12
13 class NewPostForm(forms.Form): 13 class NewPostForm(forms.Form):
14 """Form for creating a new post.""" 14 """Form for creating a new post."""
15 body = forms.CharField(label='', 15 body = forms.CharField(label='',
16 required=False,
16 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'})) 17 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'}))
17 topic_id = forms.IntegerField(widget=forms.HiddenInput) 18 topic_id = forms.IntegerField(widget=forms.HiddenInput)
18 topic = None 19 topic = None
19 20
20 class Media: 21 class Media:
21 css = { 22 css = {
22 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] + 23 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] +
23 settings.GPP_THIRD_PARTY_CSS['jquery-ui']), 24 settings.GPP_THIRD_PARTY_CSS['jquery-ui']),
24 } 25 }
25 js = (settings.GPP_THIRD_PARTY_JS['markitup'] + 26 js = (settings.GPP_THIRD_PARTY_JS['markitup'] +
26 settings.GPP_THIRD_PARTY_JS['jquery-ui'] + 27 settings.GPP_THIRD_PARTY_JS['jquery-ui'] +
27 ('js/forums.js', )) 28 ('js/forums.js', ))
28 29
29 def __init__(self, *args, **kwargs): 30 def __init__(self, *args, **kwargs):
30 super(NewPostForm, self).__init__(*args, **kwargs) 31 super(NewPostForm, self).__init__(*args, **kwargs)
31 attachments = args[0].getlist('attachment') if len(args) else [] 32 attachments = args[0].getlist('attachment') if len(args) else []
32 self.attach_proc = AttachmentProcessor(attachments) 33 self.attach_proc = AttachmentProcessor(attachments)
34
35 def clean_body(self):
36 data = self.cleaned_data['body']
37 if not data and not self.attach_proc.has_attachments():
38 raise forms.ValidationError("This field is required.")
39 return data
33 40
34 def clean_topic_id(self): 41 def clean_topic_id(self):
35 id = self.cleaned_data['topic_id'] 42 id = self.cleaned_data['topic_id']
36 try: 43 try:
37 self.topic = Topic.objects.select_related().get(pk=id) 44 self.topic = Topic.objects.select_related().get(pk=id)
38 except Topic.DoesNotExist: 45 except Topic.DoesNotExist:
39 raise forms.ValidationError('invalid topic') 46 raise forms.ValidationError('invalid topic')
40 return id 47 return id
41 48
42 def save(self, user, ip=None): 49 def save(self, user, ip=None):
43 """ 50 """
44 Creates a new post from the form data and supplied arguments. 51 Creates a new post from the form data and supplied arguments.
45 """ 52 """
56 Superusers and moderators can also create the topic as a sticky or initially 63 Superusers and moderators can also create the topic as a sticky or initially
57 locked. 64 locked.
58 """ 65 """
59 name = forms.CharField(label='Subject', max_length=255, 66 name = forms.CharField(label='Subject', max_length=255,
60 widget=forms.TextInput(attrs={'size': 64})) 67 widget=forms.TextInput(attrs={'size': 64}))
61 body = forms.CharField(label='', 68 body = forms.CharField(label='', required=False,
62 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'})) 69 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'}))
63 user = None 70 user = None
64 forum = None 71 forum = None
65 has_mod_fields = False 72 has_mod_fields = False
66 73
67 class Media: 74 class Media:
68 css = { 75 css = {
69 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] + 76 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] +
70 settings.GPP_THIRD_PARTY_CSS['jquery-ui']), 77 settings.GPP_THIRD_PARTY_CSS['jquery-ui']),
71 } 78 }
72 js = (settings.GPP_THIRD_PARTY_JS['markitup'] + 79 js = (settings.GPP_THIRD_PARTY_JS['markitup'] +
73 settings.GPP_THIRD_PARTY_JS['jquery-ui'] + 80 settings.GPP_THIRD_PARTY_JS['jquery-ui'] +
74 ('js/forums.js', )) 81 ('js/forums.js', ))
75 82
76 def __init__(self, user, forum, *args, **kwargs): 83 def __init__(self, user, forum, *args, **kwargs):
77 super(NewTopicForm, self).__init__(*args, **kwargs) 84 super(NewTopicForm, self).__init__(*args, **kwargs)
83 self.fields['locked'] = forms.BooleanField(required=False) 90 self.fields['locked'] = forms.BooleanField(required=False)
84 self.has_mod_fields = True 91 self.has_mod_fields = True
85 92
86 attachments = args[0].getlist('attachment') if len(args) else [] 93 attachments = args[0].getlist('attachment') if len(args) else []
87 self.attach_proc = AttachmentProcessor(attachments) 94 self.attach_proc = AttachmentProcessor(attachments)
95
96 # If this form is being POSTed, and the user is trying to add
97 # attachments, create hidden fields to list the Oembed ids. In
98 # case the form isn't valid, the client-side javascript will know
99 # which Oembed media to ask for when the form is displayed with
100 # errors.
101 if self.attach_proc.has_attachments():
102 pks = self.attach_proc.get_ids()
103 self.fields['attachment'] = forms.MultipleChoiceField(label='',
104 widget=forms.MultipleHiddenInput(),
105 choices=[(v, v) for v in pks])
106
107 def clean_body(self):
108 data = self.cleaned_data['body']
109 if not data and not self.attach_proc.has_attachments():
110 raise forms.ValidationError("This field is required.")
111 return data
88 112
89 def save(self, ip=None): 113 def save(self, ip=None):
90 """ 114 """
91 Creates the new Topic and first Post from the form data and supplied 115 Creates the new Topic and first Post from the form data and supplied
92 arguments. 116 arguments.
111 135
112 class PostForm(forms.ModelForm): 136 class PostForm(forms.ModelForm):
113 """ 137 """
114 Form for editing an existing post or a new, non-quick post. 138 Form for editing an existing post or a new, non-quick post.
115 """ 139 """
116 body = forms.CharField(label='', 140 body = forms.CharField(label='',
141 required=False,
117 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'})) 142 widget=forms.Textarea(attrs={'class': 'markItUp smileyTarget'}))
118 143
119 class Meta: 144 class Meta:
120 model = Post 145 model = Post
121 fields = ('body', ) 146 fields = ('body', )
123 class Media: 148 class Media:
124 css = { 149 css = {
125 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] + 150 'all': (settings.GPP_THIRD_PARTY_CSS['markitup'] +
126 settings.GPP_THIRD_PARTY_CSS['jquery-ui']), 151 settings.GPP_THIRD_PARTY_CSS['jquery-ui']),
127 } 152 }
128 js = (settings.GPP_THIRD_PARTY_JS['markitup'] + 153 js = (settings.GPP_THIRD_PARTY_JS['markitup'] +
129 settings.GPP_THIRD_PARTY_JS['jquery-ui'] + 154 settings.GPP_THIRD_PARTY_JS['jquery-ui'] +
130 ('js/forums.js', )) 155 ('js/forums.js', ))
131 156
157 def __init__(self, *args, **kwargs):
158 super(PostForm, self).__init__(*args, **kwargs)
159
160 attachments = args[0].getlist('attachment') if len(args) else []
161 self.attach_proc = AttachmentProcessor(attachments)
162
163 # If this form is being used to edit an existing post, and that post
164 # has attachments, create a hidden post_id field. The client-side
165 # AJAX will use this as a cue to retrieve the HTML for the embedded
166 # media.
167 if 'instance' in kwargs:
168 post = kwargs['instance']
169 if post.attachments.count():
170 self.fields['post_id'] = forms.CharField(label='',
171 widget=forms.HiddenInput(attrs={'value': post.id}))
172
173 def clean_body(self):
174 data = self.cleaned_data['body']
175 if not data and not self.attach_proc.has_attachments():
176 raise forms.ValidationError('This field is required.')
177 return data
178
132 179
133 class MoveTopicForm(forms.Form): 180 class MoveTopicForm(forms.Form):
134 """ 181 """
135 Form for a moderator to move a topic to a forum. 182 Form for a moderator to move a topic to a forum.
136 """ 183 """
137 forums = forms.ModelChoiceField(label='Move to forum', 184 forums = forms.ModelChoiceField(label='Move to forum',
138 queryset=Forum.objects.none()) 185 queryset=Forum.objects.none())
139 186
140 def __init__(self, user, *args, **kwargs): 187 def __init__(self, user, *args, **kwargs):
141 hide_label = kwargs.pop('hide_label', False) 188 hide_label = kwargs.pop('hide_label', False)
142 required = kwargs.pop('required', True) 189 required = kwargs.pop('required', True)
143 super(MoveTopicForm, self).__init__(*args, **kwargs) 190 super(MoveTopicForm, self).__init__(*args, **kwargs)
144 self.fields['forums'].queryset = \ 191 self.fields['forums'].queryset = \
145 Forum.objects.forums_for_user(user).order_by('name') 192 Forum.objects.forums_for_user(user).order_by('name')
146 if hide_label: 193 if hide_label:
152 """ 199 """
153 Form for a moderator to split posts from a topic to a new topic. 200 Form for a moderator to split posts from a topic to a new topic.
154 """ 201 """
155 name = forms.CharField(label='New topic title', max_length=255, 202 name = forms.CharField(label='New topic title', max_length=255,
156 widget=forms.TextInput(attrs={'size': 64})) 203 widget=forms.TextInput(attrs={'size': 64}))
157 forums = forms.ModelChoiceField(label='Forum for new topic', 204 forums = forms.ModelChoiceField(label='Forum for new topic',
158 queryset=Forum.objects.none()) 205 queryset=Forum.objects.none())
159 post_ids = [] 206 post_ids = []
160 split_at = False 207 split_at = False
161 208
162 def __init__(self, user, *args, **kwargs): 209 def __init__(self, user, *args, **kwargs):