Browse Source

Slowly getting to poll edition. #28

Rafał Pitoń 11 years ago
parent
commit
a90d8b1343

+ 3 - 3
misago/acl/builder.py

@@ -22,14 +22,14 @@ def build_form(request, role):
 
 
 
 
 def build_forum_form(request, role):
 def build_forum_form(request, role):
-    print dir(ACLFormBase)
     form_type = type('ACLFormForumFinal', (ACLFormBase,), {'fieldsets': []})
     form_type = type('ACLFormForumFinal', (ACLFormBase,), {'fieldsets': []})
     for provider in settings.PERMISSION_PROVIDERS:
     for provider in settings.PERMISSION_PROVIDERS:
         app_module = import_module(provider)
         app_module = import_module(provider)
         try:
         try:
             app_module.make_forum_form(request, role, form_type)
             app_module.make_forum_form(request, role, form_type)
-        except AttributeError:
-            pass
+        except AttributeError as e:
+            if not 'make_forum_form' in unicode(e):
+                raise e
     return form_type
     return form_type
 
 
 
 

+ 41 - 5
misago/acl/permissions/threads.py

@@ -1,5 +1,7 @@
+from datetime import timedelta
 from django.db import models
 from django.db import models
 from django.db.models import Q
 from django.db.models import Q
+from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 import floppyforms as forms
 import floppyforms as forms
 from misago.acl.builder import BaseACL
 from misago.acl.builder import BaseACL
@@ -96,11 +98,13 @@ def make_forum_form(request, role, form):
                                                                            ), coerce=int)
                                                                            ), coerce=int)
     form.base_fields['can_see_poll_votes'] = forms.BooleanField(label=_("Can always see who voted in poll"),
     form.base_fields['can_see_poll_votes'] = forms.BooleanField(label=_("Can always see who voted in poll"),
                                                                 widget=YesNoSwitch, initial=False, required=False)
                                                                 widget=YesNoSwitch, initial=False, required=False)
+    form.base_fields['can_edit_polls'] = forms.IntegerField(label=_("Time for poll edition"), min_value=0, initial=15,
+                                                            help_text=_("Enter number of minutes after poll has been started for which member (or moderator) will be able to edit poll or 0 to always allow edition of unfinished polls. If you enter zero, users will always be able to change (and possibly maniputale) unfinished polls. This permission has also effect on user's permission to delete poll."))
     form.base_fields['can_delete_polls'] = forms.TypedChoiceField(label=_("Can delete polls"),
     form.base_fields['can_delete_polls'] = forms.TypedChoiceField(label=_("Can delete polls"),
                                                                   choices=(
                                                                   choices=(
                                                                            (0, _("No")),
                                                                            (0, _("No")),
-                                                                           (1, _("Yes, soft-delete")),
-                                                                           (2, _("Yes, hard-delete")),
+                                                                           (1, _("Yes, within allowed time")),
+                                                                           (2, _("Yes, always")),
                                                                            ), coerce=int)
                                                                            ), coerce=int)
     form.base_fields['can_delete_attachments'] = forms.BooleanField(label=_("Can delete attachments"),
     form.base_fields['can_delete_attachments'] = forms.BooleanField(label=_("Can delete attachments"),
                                                                     widget=YesNoSwitch, initial=False, required=False)
                                                                     widget=YesNoSwitch, initial=False, required=False)
@@ -127,7 +131,7 @@ def make_forum_form(request, role, form):
                           ))
                           ))
     form.fieldsets.append((
     form.fieldsets.append((
                            _("Polls"),
                            _("Polls"),
-                           ('can_make_polls', 'can_vote_in_polls', 'can_see_poll_votes')
+                           ('can_make_polls', 'can_vote_in_polls', 'can_see_poll_votes', 'can_edit_polls', 'can_delete_polls')
                           ))
                           ))
     form.fieldsets.append((
     form.fieldsets.append((
                            _("Attachments"),
                            _("Attachments"),
@@ -138,7 +142,7 @@ def make_forum_form(request, role, form):
                            _("Moderation"),
                            _("Moderation"),
                            ('can_approve', 'can_edit_labels', 'can_see_changelog', 'can_pin_threads', 'can_edit_threads_posts',
                            ('can_approve', 'can_edit_labels', 'can_see_changelog', 'can_pin_threads', 'can_edit_threads_posts',
                             'can_move_threads_posts', 'can_close_threads', 'can_protect_posts', 'can_delete_threads',
                             'can_move_threads_posts', 'can_close_threads', 'can_protect_posts', 'can_delete_threads',
-                            'can_delete_posts', 'can_delete_polls', 'can_delete_attachments', 'can_delete_checkpoints', 'can_see_deleted_checkpoints')
+                            'can_delete_posts', 'can_delete_attachments', 'can_delete_checkpoints', 'can_see_deleted_checkpoints')
                           ))
                           ))
 
 
 
 
@@ -611,6 +615,34 @@ class ThreadsACL(BaseACL):
         except KeyError:
         except KeyError:
             raise ACLError403(_("You don't have permission to see votes in this poll."))
             raise ACLError403(_("You don't have permission to see votes in this poll."))
 
 
+    def can_edit_poll(self, forum, poll):
+        try:
+            if poll.over:
+                return False
+            forum_role = self.get_role(forum)
+            if forum_role['can_edit_polls'] == 0:
+                return True
+            edition_expires = poll.start_date + timedelta(minutes=forum_role['can_edit_polls'])
+            return timezone.now() <= edition_expires
+        except KeyError:
+            return False
+
+    def can_delete_poll(self, forum, poll):
+        try:
+            forum_role = self.get_role(forum)
+            if not forum_role['can_delete_polls']:
+                return False
+            if forum_role['can_edit_threads_posts']:
+                return True
+            if poll.over:
+                return False
+            if forum_role['can_delete_polls'] == 1:
+                edition_expires = poll.start_date + timedelta(minutes=forum_role['can_edit_polls'])
+                return timezone.now() <= edition_expires
+            return True
+        except KeyError:
+            return False
+
     def can_see_all_checkpoints(self, forum):
     def can_see_all_checkpoints(self, forum):
         try:
         try:
             forum_role = self.get_role(forum)
             forum_role = self.get_role(forum)
@@ -692,6 +724,7 @@ def build_forums(acl, perms, forums, forum_roles):
                      'can_delete_threads': 0,
                      'can_delete_threads': 0,
                      'can_delete_posts': 0,
                      'can_delete_posts': 0,
                      'can_see_poll_votes': False,
                      'can_see_poll_votes': False,
+                     'can_edit_polls': 15,
                      'can_delete_polls': 0,
                      'can_delete_polls': 0,
                      'can_delete_attachments': False,
                      'can_delete_attachments': False,
                      'can_see_deleted_checkpoints': False,
                      'can_see_deleted_checkpoints': False,
@@ -703,7 +736,10 @@ def build_forums(acl, perms, forums, forum_roles):
                 role = forum_roles[perm['forums'][forum.pk]]
                 role = forum_roles[perm['forums'][forum.pk]]
                 for p in forum_role:
                 for p in forum_role:
                     try:
                     try:
-                        if p in ['attachment_size', 'attachment_limit'] and role[p] == 0:
+                        if p  == 'can_edit_polls':
+                            if role[p] < forum_role[p]:
+                                forum_role[p] = role[p]
+                        elif p in ['attachment_size', 'attachment_limit'] and role[p] == 0:
                             forum_role[p] = 0
                             forum_role[p] = 0
                         elif role[p] > forum_role[p]:
                         elif role[p] > forum_role[p]:
                             forum_role[p] = role[p]
                             forum_role[p] = role[p]

+ 85 - 29
misago/apps/threads/forms.py

@@ -1,36 +1,60 @@
 from django.utils.translation import ungettext, ugettext_lazy as _
 from django.utils.translation import ungettext, ugettext_lazy as _
 import floppyforms as forms
 import floppyforms as forms
-from misago.apps.threadtype.posting.forms import NewThreadForm as NewThreadFormBase
+from misago.apps.threadtype.posting.forms import NewThreadForm as NewThreadFormBase, EditThreadForm as EditThreadFormBase
 from misago.forms import Form
 from misago.forms import Form
 from misago.validators import validate_sluggable
 from misago.validators import validate_sluggable
 
 
-class NewThreadForm(NewThreadFormBase):
-    def type_fields(self):
-        if self.request.acl.threads.can_make_polls(self.forum):
-            self.add_field('poll_question',
-                           forms.CharField(label=_("Poll Question"),
-                                           required=False))
-            self.add_field('poll_choices',
-                           forms.CharField(label=_("Poll Choices"),
-                                           help_text=_("Enter options poll members will vote on, every one in new line."),
-                                           required=False,
-                                           widget=forms.Textarea))
-            self.add_field('poll_max_choices',
-                           forms.IntegerField(label=_("Choices Per User"),
-                                              help_text=_("Select on how many options individual user will be able to vote on."),
-                                              min_value=1,
-                                              initial=1))
-            self.add_field('poll_length',
-                           forms.IntegerField(label=_("Poll Length"),
-                                              help_text=_("Number of days since poll creations users will be allowed to vote in poll. Enter zero for permanent poll."),
-                                              min_value=0,
-                                              initial=0))
-            self.add_field('poll_public',
-                           forms.BooleanField(label=_("Public Voting"),
-                                              required=False))
-            self.add_field('poll_changing_votes',
-                           forms.BooleanField(label=_("Allow Changing Votes"),
-                                              required=False))
+
+class PollFormMixin(object):
+    def create_poll_form(self):
+        self.add_field('poll_question',
+                       forms.CharField(label=_("Poll Question"),
+                                       required=False))
+        self.add_field('poll_choices',
+                       forms.CharField(label=_("Poll Choices"),
+                                       help_text=_("Enter options poll members will vote on, every one in new line."),
+                                       required=False,
+                                       widget=forms.Textarea))
+        self.add_field('poll_max_choices',
+                       forms.IntegerField(label=_("Choices Per User"),
+                                          help_text=_("Select on how many options individual user will be able to vote on."),
+                                          min_value=1,
+                                          initial=1))
+        self.add_field('poll_length',
+                       forms.IntegerField(label=_("Poll Length"),
+                                          help_text=_("Number of days since poll creations users will be allowed to vote in poll. Enter zero for permanent poll."),
+                                          min_value=0,
+                                          initial=0))
+        self.add_field('poll_public',
+                       forms.BooleanField(label=_("Public Voting"),
+                                          required=False))
+        self.add_field('poll_changing_votes',
+                       forms.BooleanField(label=_("Allow Changing Votes"),
+                                          required=False))
+
+    def edit_poll_form(self):
+        self.add_field('poll_question',
+                       forms.CharField(label=_("Poll Question"),
+                                       initial=self.poll.question))
+        self.add_field('poll_choices',
+                       forms.CharField(label=_("New Choices"),
+                                       help_text=_("If you want, you can add new options to poll. Enter every option in new line."),
+                                       required=False,
+                                       widget=forms.Textarea))
+        self.add_field('poll_max_choices',
+                       forms.IntegerField(label=_("Choices Per User"),
+                                          help_text=_("Select on how many options individual user will be able to vote on."),
+                                          min_value=1,
+                                          initial=1))
+        self.add_field('poll_length',
+                       forms.IntegerField(label=_("Poll Length"),
+                                          help_text=_("Number of days since poll creations users will be allowed to vote in poll. Enter zero for permanent poll."),
+                                          min_value=0,
+                                          initial=0))
+
+        self.add_field('poll_changing_votes',
+                       forms.BooleanField(label=_("Allow Changing Votes"),
+                                          required=False))
 
 
     def clean_poll_question(self):
     def clean_poll_question(self):
         data = self.cleaned_data['poll_question'].strip()
         data = self.cleaned_data['poll_question'].strip()
@@ -77,7 +101,7 @@ class NewThreadForm(NewThreadFormBase):
             raise forms.ValidationError(_("Poll length cannot be longer than 300 days."))
             raise forms.ValidationError(_("Poll length cannot be longer than 300 days."))
         return data
         return data
 
 
-    def clean(self):
+    def clean_poll(self, data):
         data = super(NewThreadForm, self).clean()
         data = super(NewThreadForm, self).clean()
         try:
         try:
             if bool(data['poll_question']) != bool(self.clean_choices):
             if bool(data['poll_question']) != bool(self.clean_choices):
@@ -90,6 +114,38 @@ class NewThreadForm(NewThreadFormBase):
         return data
         return data
 
 
 
 
+class NewThreadForm(NewThreadFormBase, PollFormMixin):
+    def type_fields(self):
+        if self.request.acl.threads.can_make_polls(self.forum):
+            self.create_poll_form()
+
+    def clean(self):
+        data = super(NewThreadForm, self).clean()
+        data = self.clean_poll(data)
+        return data
+
+
+class EditThreadForm(EditThreadFormBase, PollFormMixin):
+    def type_fields(self):
+        self.poll = self.thread.poll
+        if self.poll:
+            if self.request.acl.threads.can_edit_poll(self.forum, self.poll):
+                self.edit_poll_form()
+        else:
+            if self.request.acl.threads.can_make_polls(self.forum):
+                self.create_poll_form()
+
+        if self.poll and self.request.acl.threads.can_delete_poll(self.forum, self.poll):
+            self.add_field('poll_delete',
+                           forms.BooleanField(label=_("Delete poll"),
+                                              required=False))
+
+    def clean(self):
+        data = super(EditThreadForm, self).clean()
+        data = self.clean_poll(data)
+        return data
+
+
 class PollVoteForm(Form):
 class PollVoteForm(Form):
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
         self.poll = kwargs.pop('poll')
         self.poll = kwargs.pop('poll')

+ 31 - 8
misago/apps/threads/posting.py

@@ -3,18 +3,14 @@ from django.shortcuts import redirect
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago import messages
 from misago import messages
-from misago.apps.threads.forms import NewThreadForm
+from misago.apps.threads.forms import NewThreadForm, EditThreadForm
 from misago.apps.threadtype.posting import NewThreadBaseView, EditThreadBaseView, NewReplyBaseView, EditReplyBaseView
 from misago.apps.threadtype.posting import NewThreadBaseView, EditThreadBaseView, NewReplyBaseView, EditReplyBaseView
 from misago.models import Forum, Thread, Post, Poll, PollOption
 from misago.models import Forum, Thread, Post, Poll, PollOption
 from misago.apps.threads.mixins import TypeMixin
 from misago.apps.threads.mixins import TypeMixin
 
 
-class NewThreadView(NewThreadBaseView, TypeMixin):
-    form_type = NewThreadForm
 
 
-    def set_forum_context(self):
-        self.forum = Forum.objects.get(pk=self.kwargs.get('forum'), type='forum')
-
-    def after_form(self, form):
+class PollFormMixin(object):
+    def create_poll(self, form):
         poll = Poll(forum=self.forum,
         poll = Poll(forum=self.forum,
                     thread=self.thread,
                     thread=self.thread,
                     user=self.request.user,
                     user=self.request.user,
@@ -44,6 +40,23 @@ class NewThreadView(NewThreadBaseView, TypeMixin):
         self.thread.has_poll = True
         self.thread.has_poll = True
         self.thread.save()
         self.thread.save()
 
 
+    def update_poll(self, form):
+        pass
+
+    def delete_poll(self):
+        self.thread.poll.delete()
+
+
+class NewThreadView(NewThreadBaseView, TypeMixin, PollFormMixin):
+    form_type = NewThreadForm
+
+    def set_forum_context(self):
+        self.forum = Forum.objects.get(pk=self.kwargs.get('forum'), type='forum')
+
+    def after_form(self, form):
+        if form.cleaned_data.get('poll_question'):
+            self.create_poll(form)
+
     def response(self):
     def response(self):
         if self.post.moderated:
         if self.post.moderated:
             messages.success(self.request, _("New thread has been posted. It will be hidden from other members until moderator reviews it."), 'threads')
             messages.success(self.request, _("New thread has been posted. It will be hidden from other members until moderator reviews it."), 'threads')
@@ -53,7 +66,17 @@ class NewThreadView(NewThreadBaseView, TypeMixin):
 
 
 
 
 class EditThreadView(EditThreadBaseView, TypeMixin):
 class EditThreadView(EditThreadBaseView, TypeMixin):
-    form_type = NewThreadForm
+    form_type = EditThreadForm
+
+    def after_form(self, form):
+        if self.thread.poll:
+            if form.cleaned_data.get('poll_delete'):
+                self.delete_poll()
+                self.thread.save()
+            else:
+                self.update_poll(form)
+        elif form.cleaned_data.get('poll_question'):
+            self.create_poll(form)
 
 
     def response(self):
     def response(self):
         messages.success(self.request, _("Your thread has been edited."), 'threads_%s' % self.post.pk)
         messages.success(self.request, _("Your thread has been edited."), 'threads_%s' % self.post.pk)

+ 6 - 1
misago/fixtures/forumsroles.py

@@ -21,6 +21,8 @@ def load():
                         'can_make_polls': True,
                         'can_make_polls': True,
                         'can_vote_in_polls': True,
                         'can_vote_in_polls': True,
                         'can_see_poll_votes': True,
                         'can_see_poll_votes': True,
+                        'can_edit_polls': 0,
+                        'can_delete_polls': 2,
                         'can_see_attachments': True,
                         'can_see_attachments': True,
                         'can_upload_attachments': True,
                         'can_upload_attachments': True,
                         'can_download_attachments': True,
                         'can_download_attachments': True,
@@ -36,7 +38,6 @@ def load():
                         'can_protect_posts': True,
                         'can_protect_posts': True,
                         'can_delete_threads': 2,
                         'can_delete_threads': 2,
                         'can_delete_posts': 2,
                         'can_delete_posts': 2,
-                        'can_delete_polls': 2,
                         'can_delete_attachments': True,
                         'can_delete_attachments': True,
                         'can_see_deleted_checkpoints': True,
                         'can_see_deleted_checkpoints': True,
                         'can_delete_checkpoints': 2,
                         'can_delete_checkpoints': 2,
@@ -59,6 +60,8 @@ def load():
                         'can_see_posts_scores': 2,
                         'can_see_posts_scores': 2,
                         'can_make_polls': True,
                         'can_make_polls': True,
                         'can_vote_in_polls': True,
                         'can_vote_in_polls': True,
+                        'can_edit_polls': 30,
+                        'can_delete_polls': 1,
                         'can_upload_attachments': True,
                         'can_upload_attachments': True,
                         'can_download_attachments': True,
                         'can_download_attachments': True,
                         'attachment_size': 100,
                         'attachment_size': 100,
@@ -82,6 +85,8 @@ def load():
                         'can_see_posts_scores': 2,
                         'can_see_posts_scores': 2,
                         'can_make_polls': True,
                         'can_make_polls': True,
                         'can_vote_in_polls': True,
                         'can_vote_in_polls': True,
+                        'can_edit_polls': 30,
+                        'can_delete_polls': 1,
                         'can_download_attachments': True,
                         'can_download_attachments': True,
                        }
                        }
     role.save(force_insert=True)
     role.save(force_insert=True)

+ 1 - 1
static/cranefly/css/cranefly.css

@@ -813,7 +813,7 @@ a.btn-link:hover,a.btn-link:active,a.btn-link:focus{color:#333;text-decoration:n
 .pagination{margin:0;padding:0}.pagination .count{margin-right:10.5px;padding:4px 0;color:#999}
 .pagination{margin:0;padding:0}.pagination .count{margin-right:10.5px;padding:4px 0;color:#999}
 .pagination ul{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.pagination ul li{float:left;margin:0;margin-right:4.666666666666667px;padding:0}.pagination ul li a:link,.pagination ul li a:visited{background-color:#fff;border:1px solid #f0f0f0;border-radius:3px;padding:3px 7px;color:#999}.pagination ul li a:link i,.pagination ul li a:visited i{display:inline-block;width:12px;text-align:center}
 .pagination ul{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.pagination ul li{float:left;margin:0;margin-right:4.666666666666667px;padding:0}.pagination ul li a:link,.pagination ul li a:visited{background-color:#fff;border:1px solid #f0f0f0;border-radius:3px;padding:3px 7px;color:#999}.pagination ul li a:link i,.pagination ul li a:visited i{display:inline-block;width:12px;text-align:center}
 .pagination ul li a:active,.pagination ul li a:hover{border:1px solid #999;color:#555}
 .pagination ul li a:active,.pagination ul li a:hover{border:1px solid #999;color:#555}
-.editor{background-color:#fff;border:1px solid #e6e6e6;border-radius:3px}.editor .editor-error{padding:10.5px;padding-bottom:0;margin-bottom:-10.5px}.editor .editor-error .help-block{color:#cf402e;font-weight:bold}
+.editor{background-color:#fff;border:1px solid #e6e6e6;border-radius:3px;margin-bottom:20px}.editor .editor-error{padding:10.5px;padding-bottom:0;margin-bottom:-10.5px}.editor .editor-error .help-block{color:#cf402e;font-weight:bold}
 .editor .editor-input{padding:10.5px}.editor .editor-input>div{margin-right:22px;position:relative}.editor .editor-input>div textarea{border:none;box-shadow:none;margin:-10.5px;padding:10.5px;padding-right:32px;width:100%;font-family:Monaco,Menlo,Consolas,"Courier New",monospace}
 .editor .editor-input{padding:10.5px}.editor .editor-input>div{margin-right:22px;position:relative}.editor .editor-input>div textarea{border:none;box-shadow:none;margin:-10.5px;padding:10.5px;padding-right:32px;width:100%;font-family:Monaco,Menlo,Consolas,"Courier New",monospace}
 .editor .editor-input>div .editor-zen-on{display:none;position:absolute;top:-4px;right:-26px;padding-left:8px}.editor .editor-input>div .editor-zen-on a{border-radius:4px;display:block;opacity:.5;filter:alpha(opacity=50);padding:2px 0;padding-bottom:3px;width:29px;color:#333;font-size:24px;text-align:center}.editor .editor-input>div .editor-zen-on a:hover,.editor .editor-input>div .editor-zen-on a:active{box-shadow:0 0 3px #999;text-decoration:none}
 .editor .editor-input>div .editor-zen-on{display:none;position:absolute;top:-4px;right:-26px;padding-left:8px}.editor .editor-input>div .editor-zen-on a{border-radius:4px;display:block;opacity:.5;filter:alpha(opacity=50);padding:2px 0;padding-bottom:3px;width:29px;color:#333;font-size:24px;text-align:center}.editor .editor-input>div .editor-zen-on a:hover,.editor .editor-input>div .editor-zen-on a:active{box-shadow:0 0 3px #999;text-decoration:none}
 .editor .editor-actions{border-top:1px solid #e6e6e6;overflow:auto;padding:10.5px}.editor .editor-actions>.btn{margin-left:14px}
 .editor .editor-actions{border-top:1px solid #e6e6e6;overflow:auto;padding:10.5px}.editor .editor-actions>.btn{margin-left:14px}

+ 1 - 0
static/cranefly/css/cranefly/editor.less

@@ -5,6 +5,7 @@
   background-color: @editorBackground;
   background-color: @editorBackground;
   border: 1px solid darken(@editorBackground, 10%);
   border: 1px solid darken(@editorBackground, 10%);
   border-radius: @baseBorderRadius;
   border-radius: @baseBorderRadius;
+  margin-bottom: @baseLineHeight;
 
 
   .editor-error {
   .editor-error {
     padding: @editorPadding;
     padding: @editorPadding;

+ 13 - 2
templates/cranefly/threads/posting.html

@@ -70,16 +70,23 @@
             {{ form_theme.row(form.edit_reason, attrs={'class': 'span8'}) }}
             {{ form_theme.row(form.edit_reason, attrs={'class': 'span8'}) }}
             {% endif %}
             {% endif %}
 
 
-            {% if 'poll_question' in form.fields %}
+            {% if 'poll_question' in form.fields or 'poll_delete' in form.fields %}
             <hr>
             <hr>
-            <h4>{% trans %}Create Poll{% endtrans %}</h4>
+            <h4>{% if thread and thread.poll %}{% trans %}Edit Poll{% endtrans %}{% else %}{% trans %}Create Poll{% endtrans %}{% endif %}</h4>
+            {% if 'poll_question' in form.fields %}
             {{ form_theme.row(form.poll_question, attrs={'class': 'span8'}) }}
             {{ form_theme.row(form.poll_question, attrs={'class': 'span8'}) }}
             {{ form_theme.row(form.poll_choices, attrs={'class': 'span8', 'rows': 4}) }}
             {{ form_theme.row(form.poll_choices, attrs={'class': 'span8', 'rows': 4}) }}
             {{ form_theme.row(form.poll_max_choices, attrs={'class': 'span8'}) }}
             {{ form_theme.row(form.poll_max_choices, attrs={'class': 'span8'}) }}
             {{ form_theme.row(form.poll_length, attrs={'class': 'span8'}) }}
             {{ form_theme.row(form.poll_length, attrs={'class': 'span8'}) }}
+            {% if 'poll_public' in form.fields %}
             {{ form_theme.row(form.poll_public, attrs={'inline': lang_poll_public()}) }}
             {{ form_theme.row(form.poll_public, attrs={'inline': lang_poll_public()}) }}
+            {% endif %}
             {{ form_theme.row(form.poll_changing_votes, attrs={'inline': lang_poll_changing_votes()}) }}
             {{ form_theme.row(form.poll_changing_votes, attrs={'inline': lang_poll_changing_votes()}) }}
             {% endif %}
             {% endif %}
+            {% if 'poll_delete' in form.fields %}
+            {{ form_theme.row(form.poll_delete, attrs={'inline': lang_poll_delete()}) }}
+            {% endif %}
+            {% endif %}
 
 
             {% if intersect(form.fields, ('thread_weight', 'close_thread')) %}
             {% if intersect(form.fields, ('thread_weight', 'close_thread')) %}
             <hr>
             <hr>
@@ -214,4 +221,8 @@
 
 
 {% macro lang_poll_changing_votes() -%}
 {% macro lang_poll_changing_votes() -%}
 {% trans %}Allow users to change their votes.{% endtrans %}
 {% trans %}Allow users to change their votes.{% endtrans %}
+{%- endmacro %}
+
+{% macro lang_poll_delete() -%}
+{% trans %}Delete this poll from thread.{% endtrans %}
 {%- endmacro %}
 {%- endmacro %}