annotate forums/forms.py @ 969:69c72ed469d3

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