annotate gpp/forums/forms.py @ 467:b910cc1460c8

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