add poll feature ref as squash commit see also http://support.djangobb.org/topic/333/ (This is a combination of 9 commits.)

This commit is contained in:
JensDiemer 2012-08-10 11:12:52 +03:00
parent 725fecaedf
commit c67ed01f3b
13 changed files with 668 additions and 147 deletions
.gitignore
djangobb_forum

13
.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
*.py[co]
*.egg-info
.pydevproject
.project
.settings
*.db
*.json
*.log
*~
local_settings.py
.env
build/
dist/

View file

@ -6,7 +6,7 @@ from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from djangobb_forum.models import Category, Forum, Topic, Post, Profile, Reputation, \ from djangobb_forum.models import Category, Forum, Topic, Post, Profile, Reputation, \
Report, Ban, Attachment Report, Ban, Attachment, Poll, PollChoice
class BaseModelAdmin(admin.ModelAdmin): class BaseModelAdmin(admin.ModelAdmin):
@ -71,9 +71,21 @@ class AttachmentAdmin(BaseModelAdmin):
list_filter = ("content_type",) list_filter = ("content_type",)
admin.site.unregister(User) class PollChoiceInline(admin.TabularInline):
model = PollChoice
extra = 3
class PollAdmin(admin.ModelAdmin):
list_display = ("question", "active",)
list_display_links = ("question",)
list_editable = ("active",)
list_filter = ("active",)
inlines = [PollChoiceInline]
admin.site.unregister(User)
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
admin.site.register(Category, CategoryAdmin) admin.site.register(Category, CategoryAdmin)
admin.site.register(Forum, ForumAdmin) admin.site.register(Forum, ForumAdmin)
admin.site.register(Topic, TopicAdmin) admin.site.register(Topic, TopicAdmin)
@ -83,4 +95,5 @@ admin.site.register(Reputation, ReputationAdmin)
admin.site.register(Report, ReportAdmin) admin.site.register(Report, ReportAdmin)
admin.site.register(Ban, BanAdmin) admin.site.register(Ban, BanAdmin)
admin.site.register(Attachment, AttachmentAdmin) admin.site.register(Attachment, AttachmentAdmin)
admin.site.register(Poll, PollAdmin)

View file

@ -1,14 +1,16 @@
# -*- coding: utf-8 -*- # coding: utf-8
import os.path import os.path
from datetime import datetime from datetime import datetime, timedelta
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models.expressions import F
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from djangobb_forum.models import Topic, Post, Profile, Reputation, Report, \ from djangobb_forum.models import Topic, Post, Profile, Reputation, Report, \
Attachment Attachment, Poll, PollChoice
from djangobb_forum import settings as forum_settings from djangobb_forum import settings as forum_settings
from djangobb_forum.util import convert_text_to_html, set_language from djangobb_forum.util import convert_text_to_html, set_language
@ -44,6 +46,8 @@ SEARCH_IN_CHOICES = (
class AddPostForm(forms.ModelForm): class AddPostForm(forms.ModelForm):
FORM_NAME = "AddPostForm" # used in view and template submit button
name = forms.CharField(label=_('Subject'), max_length=255, name = forms.CharField(label=_('Subject'), max_length=255,
widget=forms.TextInput(attrs={'size':'115'})) widget=forms.TextInput(attrs={'size':'115'}))
attachment = forms.FileField(label=_('Attachment'), required=False) attachment = forms.FileField(label=_('Attachment'), required=False)
@ -232,7 +236,7 @@ class PersonalityProfileForm(forms.ModelForm):
class Meta: class Meta:
model = Profile model = Profile
fields = ['show_avatar', 'signature'] fields = ['show_avatar', 'signature']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
extra_args = kwargs.pop('extra_args', {}) extra_args = kwargs.pop('extra_args', {})
self.profile = kwargs['instance'] self.profile = kwargs['instance']
@ -265,7 +269,7 @@ class PrivacyProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
extra_args = kwargs.pop('extra_args', {}) extra_args = kwargs.pop('extra_args', {})
super(PrivacyProfileForm, self).__init__(*args, **kwargs) super(PrivacyProfileForm, self).__init__(*args, **kwargs)
self.fields['privacy_permission'].widget = forms.RadioSelect( self.fields['privacy_permission'].widget = forms.RadioSelect(
choices=self.fields['privacy_permission'].choices choices=self.fields['privacy_permission'].choices
) )
@ -293,27 +297,27 @@ class UserSearchForm(forms.Form):
sort_by = self.cleaned_data['sort_by'] sort_by = self.cleaned_data['sort_by']
sort_dir = self.cleaned_data['sort_dir'] sort_dir = self.cleaned_data['sort_dir']
qs = qs.filter(username__contains=username, forum_profile__post_count__gte=forum_settings.POST_USER_SEARCH) qs = qs.filter(username__contains=username, forum_profile__post_count__gte=forum_settings.POST_USER_SEARCH)
if sort_by=='username': if sort_by == 'username':
if sort_dir=='ASC': if sort_dir == 'ASC':
return qs.order_by('username') return qs.order_by('username')
elif sort_dir=='DESC': elif sort_dir == 'DESC':
return qs.order_by('-username') return qs.order_by('-username')
elif sort_by=='registered': elif sort_by == 'registered':
if sort_dir=='ASC': if sort_dir == 'ASC':
return qs.order_by('date_joined') return qs.order_by('date_joined')
elif sort_dir=='DESC': elif sort_dir == 'DESC':
return qs.order_by('-date_joined') return qs.order_by('-date_joined')
elif sort_by=='num_posts': elif sort_by == 'num_posts':
if sort_dir=='ASC': if sort_dir == 'ASC':
return qs.order_by('forum_profile__post_count') return qs.order_by('forum_profile__post_count')
elif sort_dir=='DESC': elif sort_dir == 'DESC':
return qs.order_by('-forum_profile__post_count') return qs.order_by('-forum_profile__post_count')
else: else:
return qs return qs
class PostSearchForm(forms.Form): class PostSearchForm(forms.Form):
keywords = forms.CharField(required=False, label=_('Keyword search'), keywords = forms.CharField(required=False, label=_('Keyword search'),
widget=forms.TextInput(attrs={'size':'40', 'maxlength':'100'})) widget=forms.TextInput(attrs={'size':'40', 'maxlength':'100'}))
author = forms.CharField(required=False, label=_('Author search'), author = forms.CharField(required=False, label=_('Author search'),
widget=forms.TextInput(attrs={'size':'25', 'maxlength':'25'})) widget=forms.TextInput(attrs={'size':'25', 'maxlength':'25'}))
@ -357,7 +361,7 @@ class ReputationForm(forms.ModelForm):
pass pass
else: else:
raise forms.ValidationError(_('You already voted for this post')) raise forms.ValidationError(_('You already voted for this post'))
# check if this post really belong to `from_user` # check if this post really belong to `from_user`
if not Post.objects.filter(pk=self.cleaned_data['post'].id, user=self.to_user).exists(): if not Post.objects.filter(pk=self.cleaned_data['post'].id, user=self.to_user).exists():
raise forms.ValidationError(_('This post does\'t belong to this user')) raise forms.ValidationError(_('This post does\'t belong to this user'))
@ -376,7 +380,7 @@ class ReputationForm(forms.ModelForm):
class MailToForm(forms.Form): class MailToForm(forms.Form):
subject = forms.CharField(label=_('Subject'), subject = forms.CharField(label=_('Subject'),
widget=forms.TextInput(attrs={'size':'75', 'maxlength':'70', 'class':'longinput'})) widget=forms.TextInput(attrs={'size':'75', 'maxlength':'70', 'class':'longinput'}))
body = forms.CharField(required=False, label=_('Message'), body = forms.CharField(required=False, label=_('Message'),
widget=forms.Textarea(attrs={'rows':'10', 'cols':'75'})) widget=forms.Textarea(attrs={'rows':'10', 'cols':'75'}))
@ -401,3 +405,83 @@ class ReportForm(forms.ModelForm):
if commit: if commit:
report.save() report.save()
return report return report
class VotePollForm(forms.Form):
"""
Dynamic form for the poll.
"""
FORM_NAME = "VotePollForm" # used in view and template submit button
choice = forms.MultipleChoiceField()
def __init__(self, poll, *args, **kwargs):
self.poll = poll
super(VotePollForm, self).__init__(*args, **kwargs)
choices = self.poll.choices.all().values_list("id", "choice")
if self.poll.choice_count == 1:
self.fields["choice"] = forms.ChoiceField(
choices=choices, widget=forms.RadioSelect
)
else:
self.fields["choice"] = forms.MultipleChoiceField(
choices=choices, widget=forms.CheckboxSelectMultiple
)
def clean_choice(self):
ids = self.cleaned_data["choice"]
count = len(ids)
if count > self.poll.choice_count:
raise forms.ValidationError(
_(u'You have selected too many choices! (Only %i allowed.)') % self.poll.choice_count
)
return ids
class PollForm(forms.ModelForm):
answers = forms.CharField(min_length=2, widget=forms.Textarea,
help_text=_("Write each answer on a new line.")
)
days = forms.IntegerField(required=False, min_value=1,
help_text=_("Number of days for this poll to run. Leave empty for never ending poll.")
)
class Meta:
model = Poll
fields = ['question', 'choice_count']
def create_poll(self):
"""
return True if one field filled with data -> the user wants to create a poll
"""
return any(self.data.get(key) for key in ('question', 'answers', 'days'))
def clean_answers(self):
# validate if there is more than whitespaces ;)
raw_answers = self.cleaned_data["answers"]
answers = [answer.strip() for answer in raw_answers.splitlines() if answer.strip()]
if len(answers) == 0:
raise forms.ValidationError(_(u"There is no valid answer!"))
# validate length of all answers
is_max_length = max([len(answer) for answer in answers])
should_max_length = PollChoice._meta.get_field("choice").max_length
if is_max_length > should_max_length:
raise forms.ValidationError(_(u"One of this answers are too long!"))
return answers
def save(self, post):
"""
Create poll and all answers in PollChoice model.
"""
poll = super(PollForm, self).save(commit=False)
poll.topic = post.topic
days = self.cleaned_data["days"]
if days:
now = datetime.now()
poll.deactivate_date = now + timedelta(days=days)
poll.save()
answers = self.cleaned_data["answers"]
for answer in answers:
PollChoice.objects.create(poll=poll, choice=answer)

View file

@ -0,0 +1,226 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'PollChoice'
db.create_table('djangobb_forum_pollchoice', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('poll', self.gf('django.db.models.fields.related.ForeignKey')(related_name='choices', to=orm['djangobb_forum.Poll'])),
('choice', self.gf('django.db.models.fields.CharField')(max_length=200)),
('votes', self.gf('django.db.models.fields.IntegerField')(default=0)),
))
db.send_create_signal('djangobb_forum', ['PollChoice'])
# Adding model 'Poll'
db.create_table('djangobb_forum_poll', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('topic', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['djangobb_forum.Topic'])),
('question', self.gf('django.db.models.fields.CharField')(max_length=200)),
('choice_count', self.gf('django.db.models.fields.PositiveSmallIntegerField')(default=1)),
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
('deactivate_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
))
db.send_create_signal('djangobb_forum', ['Poll'])
# Adding M2M table for field users on 'Poll'
db.create_table('djangobb_forum_poll_users', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('poll', models.ForeignKey(orm['djangobb_forum.poll'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('djangobb_forum_poll_users', ['poll_id', 'user_id'])
def backwards(self, orm):
# Deleting model 'PollChoice'
db.delete_table('djangobb_forum_pollchoice')
# Deleting model 'Poll'
db.delete_table('djangobb_forum_poll')
# Removing M2M table for field users on 'Poll'
db.delete_table('djangobb_forum_poll_users')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'djangobb_forum.attachment': {
'Meta': {'object_name': 'Attachment'},
'content_type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'hash': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '40', 'db_index': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.TextField', [], {}),
'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'attachments'", 'to': "orm['djangobb_forum.Post']"}),
'size': ('django.db.models.fields.IntegerField', [], {})
},
'djangobb_forum.ban': {
'Meta': {'object_name': 'Ban'},
'ban_end': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'ban_start': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'reason': ('django.db.models.fields.TextField', [], {}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'ban_users'", 'unique': 'True', 'to': "orm['auth.User']"})
},
'djangobb_forum.category': {
'Meta': {'ordering': "['position']", 'object_name': 'Category'},
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
'position': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'})
},
'djangobb_forum.forum': {
'Meta': {'ordering': "['position']", 'object_name': 'Forum'},
'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'forums'", 'to': "orm['djangobb_forum.Category']"}),
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_forum_post'", 'null': 'True', 'to': "orm['djangobb_forum.Post']"}),
'moderators': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
'position': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
'post_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
'topic_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
},
'djangobb_forum.poll': {
'Meta': {'object_name': 'Poll'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'choice_count': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '1'}),
'deactivate_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'question': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'topic': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangobb_forum.Topic']"}),
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
'djangobb_forum.pollchoice': {
'Meta': {'object_name': 'PollChoice'},
'choice': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'poll': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['djangobb_forum.Poll']"}),
'votes': ('django.db.models.fields.IntegerField', [], {'default': '0'})
},
'djangobb_forum.post': {
'Meta': {'ordering': "['created']", 'object_name': 'Post'},
'body': ('django.db.models.fields.TextField', [], {}),
'body_html': ('django.db.models.fields.TextField', [], {}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'markup': ('django.db.models.fields.CharField', [], {'default': "'bbcode'", 'max_length': '15'}),
'topic': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['djangobb_forum.Topic']"}),
'updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'updated_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
'user_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'})
},
'djangobb_forum.posttracking': {
'Meta': {'object_name': 'PostTracking'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_read': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'topics': ('djangobb_forum.fields.JSONField', [], {'null': 'True'}),
'user': ('djangobb_forum.fields.AutoOneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'djangobb_forum.profile': {
'Meta': {'object_name': 'Profile'},
'aim': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
'auto_subscribe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'avatar': ('djangobb_forum.fields.ExtendedImageField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
'icq': ('django.db.models.fields.CharField', [], {'max_length': '12', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'jabber': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '5'}),
'location': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'markup': ('django.db.models.fields.CharField', [], {'default': "'bbcode'", 'max_length': '15'}),
'msn': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'}),
'post_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
'privacy_permission': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
'show_avatar': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'show_signatures': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'show_smilies': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'signature': ('django.db.models.fields.TextField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'signature_html': ('django.db.models.fields.TextField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
'site': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'theme': ('django.db.models.fields.CharField', [], {'default': "'default'", 'max_length': '80'}),
'time_zone': ('django.db.models.fields.FloatField', [], {'default': '3.0'}),
'user': ('djangobb_forum.fields.AutoOneToOneField', [], {'related_name': "'forum_profile'", 'unique': 'True', 'to': "orm['auth.User']"}),
'yahoo': ('django.db.models.fields.CharField', [], {'max_length': '80', 'blank': 'True'})
},
'djangobb_forum.report': {
'Meta': {'object_name': 'Report'},
'created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangobb_forum.Post']"}),
'reason': ('django.db.models.fields.TextField', [], {'default': "''", 'max_length': "'1000'", 'blank': 'True'}),
'reported_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reported_by'", 'to': "orm['auth.User']"}),
'zapped': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'zapped_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'zapped_by'", 'null': 'True', 'to': "orm['auth.User']"})
},
'djangobb_forum.reputation': {
'Meta': {'unique_together': "(('from_user', 'post'),)", 'object_name': 'Reputation'},
'from_user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputations_from'", 'to': "orm['auth.User']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post'", 'to': "orm['djangobb_forum.Post']"}),
'reason': ('django.db.models.fields.TextField', [], {'max_length': '1000'}),
'sign': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'to_user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reputations_to'", 'to': "orm['auth.User']"})
},
'djangobb_forum.topic': {
'Meta': {'ordering': "['-updated']", 'object_name': 'Topic'},
'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'forum': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'topics'", 'to': "orm['djangobb_forum.Forum']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'last_post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_topic_post'", 'null': 'True', 'to': "orm['djangobb_forum.Post']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'post_count': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'}),
'sticky': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'subscribers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'subscriptions'", 'blank': 'True', 'to': "orm['auth.User']"}),
'updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
'views': ('django.db.models.fields.IntegerField', [], {'default': '0', 'blank': 'True'})
}
}
complete_apps = ['djangobb_forum']

View file

@ -1,13 +1,15 @@
from datetime import datetime # coding: utf-8
import os
import os.path from datetime import datetime
from hashlib import sha1 from hashlib import sha1
import os
from django.db import models
from django.contrib.auth.models import User, Group
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User, Group
from django.db import models
from django.db.models import aggregates
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from djangobb_forum.fields import AutoOneToOneField, ExtendedImageField, JSONField from djangobb_forum.fields import AutoOneToOneField, ExtendedImageField, JSONField
from djangobb_forum.util import smiles, convert_text_to_html from djangobb_forum.util import smiles, convert_text_to_html
@ -410,6 +412,54 @@ class Attachment(models.Model):
self.path) self.path)
#------------------------------------------------------------------------------
class Poll(models.Model):
topic = models.ForeignKey(Topic)
question = models.CharField(max_length=200)
choice_count = models.PositiveSmallIntegerField(default=1,
help_text=_("How many choices are allowed simultaneously."),
)
active = models.BooleanField(default=True,
help_text=_("Can users vote to this poll or just see the result?"),
)
deactivate_date = models.DateTimeField(null=True, blank=True,
help_text=_("Point of time after this poll would be automatic deactivated"),
)
users = models.ManyToManyField(User, blank=True, null=True,
help_text=_("Users who has voted this poll."),
)
def auto_deactivate(self):
if self.active and self.deactivate_date:
now = datetime.now()
if now > self.deactivate_date:
self.active = False
self.save()
def __unicode__(self):
return self.question
class PollChoice(models.Model):
poll = models.ForeignKey(Poll, related_name="choices")
choice = models.CharField(max_length=200)
votes = models.IntegerField(default=0, editable=False)
def percent(self):
if not self.votes:
return 0.0
result = PollChoice.objects.filter(poll=self.poll).aggregate(aggregates.Sum("votes"))
votes_sum = result["votes__sum"]
return float(self.votes) / votes_sum * 100
def __unicode__(self):
return self.choice
#------------------------------------------------------------------------------
from .signals import post_saved, topic_saved from .signals import post_saved, topic_saved
post_save.connect(post_saved, sender=Post, dispatch_uid='djangobb_post_save') post_save.connect(post_saved, sender=Post, dispatch_uid='djangobb_post_save')

View file

@ -73,4 +73,24 @@ $(document).ready(function() {
paste("[b]"+nick+"[/b]\n"); paste("[b]"+nick+"[/b]\n");
}); });
$(".username").attr('title', 'Click to paste nick name in reply form.'); $(".username").attr('title', 'Click to paste nick name in reply form.');
window.onbeforeunload = function() {
var obj = $("textarea#id_body");
if (obj.length != 1) {
// object not found in page -> do nothing
return
}
var text = obj.val().trim();
//log("onbeforeunload text:" + text);
if (text.length > 3) {
// Firefox will not use the string. IE use it
// TODO: Translate string
return "Leave page with unsaved content?";
}
// if nothing returned, browser leave the page without any message
};
$("form#post").bind("submit", function() {
//log("unbind onbeforeunload");
window.onbeforeunload = null;
});
}); });

View file

@ -315,3 +315,13 @@ TD DIV.tclcon {MARGIN-LEFT: 2.3em}
color: #8A1F11; color: #8A1F11;
} }
/****************************************************************/
/* for poll results */
/****************************************************************/
#poll .bar {
height: 4px;
background-color: #46586A;
}
#poll li {
height: 2.5em;
}

View file

@ -1,46 +0,0 @@
{% extends 'djangobb_forum/base.html' %}
{% load forum_extras %}
{% load i18n %}
{% block content %}
<div class="linkst">
<div class="inbox">
{% if forum %}
<ul class="start"><li><a href="{% url djangobb:index %}">{% trans "Root" %}</a> </li><li>&raquo; {% link forum %}</li></ul>
{% else %}
<ul><li><a href="{% url djangobb:index %}">{% trans "Root" %}</a> </li><li>&raquo; {% link topic.forum %}</li><li>&raquo; {{ topic }}</li></ul>
{% endif %}
<div class="clearer"></div>
</div>
</div>
{% include "djangobb_forum/includes/post_form.html" %}
{% if not forum %}
<div id="postreview" class="blockpost">
<h2><span>{% trans "Topic review (newest first)" %}</span></h2>
{% for post in posts reversed %}
<div class="box rowodd">
<div class="inbox">
<div class="postleft">
<dl>
<dt><strong><a href="javascript:pasteN('{{ post.user.username }}');">{{ post.user.username }}</a></strong></dt>
<dd>{% forum_time post.created %}</dd>
</dl>
</div>
<div class="postright">
<div class="postmsg">
{{ post.body_html|safe }}
</div>
</div>
<div class="clearer"></div>
<div class="postfootright"><ul><li class="postquote"><a onmouseover="copyQ('{{ post.user.username }}');" href="javascript:pasteQ();">{% trans "Quote" %}</a></li></ul></div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,17 @@
{% extends 'djangobb_forum/base.html' %}
{% load forum_extras %}
{% load i18n %}
{% block content %}
<div class="linkst">
<div class="inbox">
{% if forum %}
<ul class="start"><li><a href="{% url djangobb:index %}">{% trans "Root" %}</a> </li><li>&raquo; {% link forum %}</li></ul>
{% else %}
<ul><li><a href="{% url djangobb:index %}">{% trans "Root" %}</a> </li><li>&raquo; {% link topic.forum %}</li><li>&raquo; {{ topic }}</li></ul>
{% endif %}
<div class="clearer"></div>
</div>
</div>
{% include "djangobb_forum/includes/post_form.html" %}
{% endblock %}

View file

@ -2,8 +2,30 @@
<div class="blockform" id="reply"> <div class="blockform" id="reply">
<h2><span>{% if forum %}{% trans "New topic" %}{% else %}{% trans "New reply" %}{% endif %}</span></h2> <h2><span>{% if forum %}{% trans "New topic" %}{% else %}{% trans "New reply" %}{% endif %}</span></h2>
<div class="box"> <div class="box">
<form id="post" action="{% if forum %}{% url djangobb:add_topic forum.id %}{% else %}{% url djangobb:add_post topic.id %}{% endif %}" method="post" enctype="multipart/form-data"> <form id="post" action="{{ form_url|default_if_none:"." }}" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{% if create_poll_form %}
<script>{# TODO: move to html head! #}
$(document).ready(function() {
$('.poll .infldset').hide();
$(".poll").click(function() {
$('.poll .infldset').slideDown();
});
});
</script>
<div class="inform poll">
<fieldset>
<legend>{% trans "Create a poll" %}</legend>
<div class="infldset">
<div class="rbox">
{{ create_poll_form }}
</div>
</div>
</fieldset>
</div>
{% endif %}
<div class="inform"> <div class="inform">
<fieldset> <fieldset>
<legend>{% trans "Write your message and submit" %}</legend> <legend>{% trans "Write your message and submit" %}</legend>
@ -33,7 +55,7 @@
</fieldset> </fieldset>
</div> </div>
{% endif %} {% endif %}
<p><input type="submit" value="{% trans "Submit" %}" /><a href="javascript:history.go(-1)">{% trans "Go back" %}</a></p> <p><input type="submit" name="{{ form.FORM_NAME }}" value="{% trans "Submit" %}" /><a href="{{ back_url|default_if_none:"javascript:history.go(-1)" }}">{% trans "Go back" %}</a></p>
</form> </form>
</div> </div>
</div> </div>

View file

@ -18,6 +18,37 @@
<div class="clearer"></div> <div class="clearer"></div>
</div> </div>
</div> </div>
{% if poll %}
<div id="poll" class="block">
<h2><span>{% trans "Poll" %}</span></h2>
<div class="box">
<div class="inbox"><p><strong>{{ poll.question }}</strong></p>
{% if poll_form %}
<form action="." method="post">{% csrf_token %}
{{ poll_form }}
{% if poll.choice_count > 1 %}
<p>
{% blocktrans with count=poll.choice_count %}({{ count }} answers allows.){% endblocktrans %}
</p>
{% endif %}
<input type="submit" name="{{ poll_form.FORM_NAME }}" value="{% trans "Vote" %}" />
</form>
{% else %}
<ul>
{% for choice in poll.choices.all %}
<li>
<div class="bar" style="width:{{ choice.percent }}%;" title="{{ choice.choice }}">&nbsp;</div>
{{ choice.votes }} vote{{ choice.votes|pluralize }} ({{ choice.percent|floatformat:1 }}%) for: {{ choice.choice }}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
</div>
{% endif %}
{% for post in posts %} {% for post in posts %}
<div id="p{{ post.id }}" class="blockpost roweven firstpost"> <div id="p{{ post.id }}" class="blockpost roweven firstpost">
<a name="post-{{ post.id }}"></a> <a name="post-{{ post.id }}"></a>
@ -152,10 +183,14 @@
<div class="clearer"></div> <div class="clearer"></div>
</div> </div>
</div> </div>
{% if not topic.closed and user.is_authenticated %}
{% include "djangobb_forum/includes/post_form.html" %} {% if reply_form %}
{% with form=reply_form %}
{% include "djangobb_forum/includes/post_form.html" %}
{% endwith %}
{% endif %} {% endif %}
{% endblock %}
{% endblock content%}
{% block controls %} {% block controls %}
<div class="conl"> <div class="conl">

View file

@ -2,12 +2,12 @@ from django.conf.urls.defaults import *
from djangobb_forum import settings as forum_settings from djangobb_forum import settings as forum_settings
from djangobb_forum import views as forum_views from djangobb_forum import views as forum_views
from djangobb_forum.feeds import LastPosts, LastTopics, LastPostsOnForum,\ from djangobb_forum.feeds import LastPosts, LastTopics, LastPostsOnForum, \
LastPostsOnCategory, LastPostsOnTopic LastPostsOnCategory, LastPostsOnTopic
from djangobb_forum.forms import EssentialsProfileForm,\ from djangobb_forum.forms import EssentialsProfileForm, \
PersonalProfileForm, MessagingProfileForm, PersonalityProfileForm,\ PersonalProfileForm, MessagingProfileForm, PersonalityProfileForm, \
DisplayProfileForm, PrivacyProfileForm, UploadAvatarForm DisplayProfileForm, PrivacyProfileForm, UploadAvatarForm
urlpatterns = patterns('', urlpatterns = patterns('',
@ -54,16 +54,13 @@ urlpatterns = patterns('',
# Topic # Topic
url('^topic/(?P<topic_id>\d+)/$', forum_views.show_topic, name='topic'), url('^topic/(?P<topic_id>\d+)/$', forum_views.show_topic, name='topic'),
url('^(?P<forum_id>\d+)/topic/add/$', forum_views.add_post, url('^(?P<forum_id>\d+)/topic/add/$', forum_views.add_topic, name='add_topic'),
{'topic_id': None}, name='add_topic'),
url('^topic/(?P<topic_id>\d+)/delete_posts/$', forum_views.delete_posts, name='delete_posts'), url('^topic/(?P<topic_id>\d+)/delete_posts/$', forum_views.delete_posts, name='delete_posts'),
url('^topic/move/$', forum_views.move_topic, name='move_topic'), url('^topic/move/$', forum_views.move_topic, name='move_topic'),
url('^topic/(?P<topic_id>\d+)/stick_unstick/(?P<action>[s|u])/$', forum_views.stick_unstick_topic, name='stick_unstick_topic'), url('^topic/(?P<topic_id>\d+)/stick_unstick/(?P<action>[s|u])/$', forum_views.stick_unstick_topic, name='stick_unstick_topic'),
url('^topic/(?P<topic_id>\d+)/open_close/(?P<action>[c|o])/$', forum_views.open_close_topic, name='open_close_topic'), url('^topic/(?P<topic_id>\d+)/open_close/(?P<action>[c|o])/$', forum_views.open_close_topic, name='open_close_topic'),
# Post # Post
url('^topic/(?P<topic_id>\d+)/post/add/$', forum_views.add_post,
{'forum_id': None}, name='add_post'),
url('^post/(?P<post_id>\d+)/$', forum_views.show_post, name='post'), url('^post/(?P<post_id>\d+)/$', forum_views.show_post, name='post'),
url('^post/(?P<post_id>\d+)/edit/$', forum_views.edit_post, name='edit_post'), url('^post/(?P<post_id>\d+)/edit/$', forum_views.edit_post, name='edit_post'),
url('^post/(?P<post_id>\d+)/delete/$', forum_views.delete_post, name='delete_post'), url('^post/(?P<post_id>\d+)/delete/$', forum_views.delete_post, name='delete_post'),
@ -73,7 +70,7 @@ urlpatterns = patterns('',
# Subscription # Subscription
url('^subscription/topic/(?P<topic_id>\d+)/delete/$', forum_views.delete_subscription, name='forum_delete_subscription'), url('^subscription/topic/(?P<topic_id>\d+)/delete/$', forum_views.delete_subscription, name='forum_delete_subscription'),
url('^subscription/topic/(?P<topic_id>\d+)/add/$', forum_views.add_subscription, name='forum_add_subscription'), url('^subscription/topic/(?P<topic_id>\d+)/add/$', forum_views.add_subscription, name='forum_add_subscription'),
# Feeds # Feeds
url(r'^feeds/posts/$', LastPosts(), name='forum_posts_feed'), url(r'^feeds/posts/$', LastPosts(), name='forum_posts_feed'),
url(r'^feeds/topics/$', LastTopics(), name='forum_topics_feed'), url(r'^feeds/topics/$', LastTopics(), name='forum_topics_feed'),

View file

@ -1,33 +1,35 @@
# coding: utf-8
import math import math
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.shortcuts import get_object_or_404, render from django.contrib import messages
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.core.cache import cache from django.core.cache import cache
from django.db.models import Q, F, Sum from django.core.urlresolvers import reverse
from django.utils.encoding import smart_str
from django.db import transaction from django.db import transaction
from django.views.decorators.csrf import csrf_exempt from django.db.models import Q, F
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import get_object_or_404, render
from django.utils.encoding import smart_str
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.decorators.csrf import csrf_exempt
from haystack.query import SearchQuerySet, SQ
from djangobb_forum import settings as forum_settings from djangobb_forum import settings as forum_settings
from djangobb_forum.forms import AddPostForm, EditPostForm, UserSearchForm, \ from djangobb_forum.forms import AddPostForm, EditPostForm, UserSearchForm, \
PostSearchForm, ReputationForm, MailToForm, EssentialsProfileForm, \ PostSearchForm, ReputationForm, MailToForm, EssentialsProfileForm, \
PersonalProfileForm, MessagingProfileForm, PersonalityProfileForm, \ VotePollForm, ReportForm, VotePollForm, PollForm
DisplayProfileForm, PrivacyProfileForm, ReportForm, UploadAvatarForm from djangobb_forum.models import Category, Forum, Topic, Post, Reputation, \
from djangobb_forum.models import Category, Forum, Topic, Post, Profile, Reputation, \
Attachment, PostTracking Attachment, PostTracking
from djangobb_forum.templatetags import forum_extras from djangobb_forum.templatetags import forum_extras
from djangobb_forum.templatetags.forum_extras import forum_moderated_by from djangobb_forum.templatetags.forum_extras import forum_moderated_by
from djangobb_forum.util import build_form, paginate, set_language, smiles, convert_text_to_html from djangobb_forum.util import build_form, paginate, set_language, smiles, convert_text_to_html
from haystack.query import SearchQuerySet, SQ
from django.contrib import messages
from django.core.exceptions import SuspiciousOperation
def index(request, full=True): def index(request, full=True):
@ -312,6 +314,19 @@ def show_forum(request, forum_id, full=True):
@transaction.commit_on_success @transaction.commit_on_success
def show_topic(request, topic_id, full=True): def show_topic(request, topic_id, full=True):
"""
* Display a topic
* save a reply
* save a poll vote
TODO: Add reply in lofi mode
"""
post_request = request.method == "POST"
user_is_authenticated = request.user.is_authenticated()
if post_request and not user_is_authenticated:
# Info: only user that are logged in should get forms in the page.
return HttpResponseForbidden()
topic = get_object_or_404(Topic.objects.select_related(), pk=topic_id) topic = get_object_or_404(Topic.objects.select_related(), pk=topic_id)
if not topic.forum.category.has_access(request.user): if not topic.forum.category.has_access(request.user):
return HttpResponseForbidden() return HttpResponseForbidden()
@ -323,82 +338,147 @@ def show_topic(request, topic_id, full=True):
topic.update_read(request.user) topic.update_read(request.user)
posts = topic.posts.all().select_related() posts = topic.posts.all().select_related()
initial = {} moderator = request.user.is_superuser or request.user in topic.forum.moderators.all()
if request.user.is_authenticated(): if user_is_authenticated and request.user in topic.subscribers.all():
initial = {
'markup': request.user.forum_profile.markup,
'subscribe': request.user.forum_profile.auto_subscribe,
}
form = AddPostForm(topic=topic, initial=initial)
moderator = request.user.is_superuser or\
request.user in topic.forum.moderators.all()
if request.user.is_authenticated() and request.user in topic.subscribers.all():
subscribed = True subscribed = True
else: else:
subscribed = False subscribed = False
# reply form
reply_form = None
form_url = None
back_url = None
if user_is_authenticated and not topic.closed:
form_url = request.path + "#reply" # if form validation failed: browser should scroll down to reply form ;)
back_url = request.path
ip = request.META.get('REMOTE_ADDR', None)
post_form_kwargs = {"topic":topic, "user":request.user, "ip":ip}
if post_request and AddPostForm.FORM_NAME in request.POST:
reply_form = AddPostForm(request.POST, request.FILES, **post_form_kwargs)
if reply_form.is_valid():
post = reply_form.save()
messages.success(request, _("Your reply saved."))
return HttpResponseRedirect(post.get_absolute_url())
else:
reply_form = AddPostForm(
initial={
'markup': request.user.forum_profile.markup,
'subscribe': request.user.forum_profile.auto_subscribe,
},
**post_form_kwargs
)
# handle poll, if exists
poll_form = None
polls = topic.poll_set.all()
if not polls:
poll = None
else:
poll = polls[0]
if user_is_authenticated: # Only logged in users can vote
poll.auto_deactivate()
has_voted = request.user in poll.users.all()
if not post_request or not VotePollForm.FORM_NAME in request.POST:
# It's not a POST request or: The reply form was send and not a poll vote
if poll.active and not has_voted:
poll_form = VotePollForm(poll)
else:
if not poll.active:
messages.error(request, _("This poll is not active!"))
return HttpResponseRedirect(topic.get_absolute_url())
elif has_voted:
messages.error(request, _("You have already vote to this poll in the past!"))
return HttpResponseRedirect(topic.get_absolute_url())
poll_form = VotePollForm(poll, request.POST)
if poll_form.is_valid():
ids = poll_form.cleaned_data["choice"]
queryset = poll.choices.filter(id__in=ids)
queryset.update(votes=F('votes') + 1)
poll.users.add(request.user) # save that this user has vote
messages.success(request, _("Your votes are saved."))
return HttpResponseRedirect(topic.get_absolute_url())
highlight_word = request.GET.get('hl', '') highlight_word = request.GET.get('hl', '')
if full: if full:
return render(request, 'djangobb_forum/topic.html', {'categories': Category.objects.all(), return render(request, 'djangobb_forum/topic.html', {'categories': Category.objects.all(),
'topic': topic, 'topic': topic,
'last_post': last_post, 'last_post': last_post,
'form': form, 'form_url': form_url,
'reply_form': reply_form,
'back_url': back_url,
'moderator': moderator, 'moderator': moderator,
'subscribed': subscribed, 'subscribed': subscribed,
'posts': posts, 'posts': posts,
'highlight_word': highlight_word, 'highlight_word': highlight_word,
'poll': poll,
'poll_form': poll_form,
}) })
else: else:
return render(request, 'djangobb_forum/lofi/topic.html', {'categories': Category.objects.all(), return render(request, 'djangobb_forum/lofi/topic.html', {'categories': Category.objects.all(),
'topic': topic, 'topic': topic,
'posts': posts, 'posts': posts,
'poll': poll,
'poll_form': poll_form,
}) })
@login_required @login_required
@transaction.commit_on_success @transaction.commit_on_success
def add_post(request, forum_id, topic_id): def add_topic(request, forum_id):
forum = None """
topic = None create a new topic, with or without poll
posts = None """
forum = get_object_or_404(Forum, pk=forum_id)
if forum_id: if not forum.category.has_access(request.user):
forum = get_object_or_404(Forum, pk=forum_id) return HttpResponseForbidden()
if not forum.category.has_access(request.user):
return HttpResponseForbidden()
elif topic_id:
topic = get_object_or_404(Topic, pk=topic_id)
posts = topic.posts.all().select_related()
if not topic.forum.category.has_access(request.user):
return HttpResponseForbidden()
if topic and topic.closed:
messages.error(request, _("This topic is closed."))
return HttpResponseRedirect(topic.get_absolute_url())
ip = request.META.get('REMOTE_ADDR', None) ip = request.META.get('REMOTE_ADDR', None)
form = build_form(AddPostForm, request, topic=topic, forum=forum, post_form_kwargs = {"forum":forum, "user":request.user, "ip":ip, }
user=request.user, ip=ip,
initial={
'markup': request.user.forum_profile.markup,
'subscribe': request.user.forum_profile.auto_subscribe,
})
if 'post_id' in request.GET: if request.method == 'POST':
post_id = request.GET['post_id'] form = AddPostForm(request.POST, request.FILES, **post_form_kwargs)
post = get_object_or_404(Post, pk=post_id) if form.is_valid():
form.fields['body'].initial = u"[quote=%s]%s[/quote]" % (post.user, post.body) all_valid = True
else:
all_valid = False
if form.is_valid(): poll_form = PollForm(request.POST)
post = form.save(); create_poll = poll_form.create_poll()
messages.success(request, _("Topic saved.")) if not create_poll:
return HttpResponseRedirect(post.get_absolute_url()) # All poll fields are empty: User didn't want to create a poll
# Don't run validation and remove all form error messages
poll_form = PollForm() # create clean form without form errors
elif not poll_form.is_valid():
all_valid = False
return render(request, 'djangobb_forum/add_post.html', {'form': form, if all_valid:
'posts': posts, post = form.save()
'topic': topic, if create_poll:
'forum': forum, poll_form.save(post)
}) messages.success(request, _("Topic with poll saved."))
else:
messages.success(request, _("Topic saved."))
return HttpResponseRedirect(post.get_absolute_url())
else:
form = AddPostForm(
initial={
'markup': request.user.forum_profile.markup,
'subscribe': request.user.forum_profile.auto_subscribe,
},
**post_form_kwargs
)
if forum_id: # Create a new topic
poll_form = PollForm()
context = {
'forum': forum,
'create_poll_form': poll_form,
'form': form,
'form_url': request.path,
'back_url': forum.get_absolute_url(),
}
return render(request, 'djangobb_forum/add_topic.html', context)
@transaction.commit_on_success @transaction.commit_on_success