Merge pull request #1170 from ostcar/poll_description
Added a poll description field for each assignment poll
This commit is contained in:
commit
e10d9e5e86
@ -22,6 +22,7 @@ Other:
|
||||
- Changed api for main menu entries.
|
||||
- Enhanced http error pages.
|
||||
- Moved dashboard and select widgets view from projector to core app.
|
||||
- Created a poll description field for each assignment-poll.
|
||||
|
||||
|
||||
Version 1.5.1 (unreleased)
|
||||
|
@ -9,7 +9,7 @@ from openslides.utils.person import PersonFormField
|
||||
from .models import Assignment
|
||||
|
||||
|
||||
class AssignmentForm(forms.ModelForm, CssClassMixin):
|
||||
class AssignmentForm(CssClassMixin, forms.ModelForm):
|
||||
posts = forms.IntegerField(
|
||||
min_value=1, initial=1, label=ugettext_lazy("Number of available posts"))
|
||||
|
||||
@ -18,8 +18,7 @@ class AssignmentForm(forms.ModelForm, CssClassMixin):
|
||||
exclude = ('status', 'elected')
|
||||
|
||||
|
||||
class AssignmentRunForm(forms.Form, CssClassMixin):
|
||||
class AssignmentRunForm(CssClassMixin, forms.Form):
|
||||
candidate = PersonFormField(
|
||||
widget=forms.Select(attrs={'class': 'medium-input'}),
|
||||
label=ugettext_lazy("Nominate a participant"),
|
||||
)
|
||||
label=ugettext_lazy("Nominate a participant"))
|
||||
|
@ -50,9 +50,9 @@ class Assignment(SlideMixin, AbsoluteUrlMixin, models.Model):
|
||||
name = models.CharField(max_length=100, verbose_name=ugettext_lazy("Name"))
|
||||
description = models.TextField(null=True, blank=True, verbose_name=ugettext_lazy("Description"))
|
||||
posts = models.PositiveSmallIntegerField(verbose_name=ugettext_lazy("Number of available posts"))
|
||||
polldescription = models.CharField(
|
||||
max_length=100, null=True, blank=True,
|
||||
verbose_name=ugettext_lazy("Comment on the ballot paper"))
|
||||
poll_description_default = models.CharField(
|
||||
max_length=79, null=True, blank=True,
|
||||
verbose_name=ugettext_lazy("Default comment on the ballot paper"))
|
||||
status = models.CharField(max_length=3, choices=STATUS, default='sea')
|
||||
|
||||
class Meta:
|
||||
@ -192,8 +192,8 @@ class Assignment(SlideMixin, AbsoluteUrlMixin, models.Model):
|
||||
return person in self.elected
|
||||
|
||||
def gen_poll(self):
|
||||
poll = AssignmentPoll(assignment=self)
|
||||
poll.save()
|
||||
poll = AssignmentPoll.objects.create(
|
||||
assignment=self, description=self.poll_description_default)
|
||||
poll.set_options([{'candidate': person} for person in self.candidates])
|
||||
return poll
|
||||
|
||||
@ -255,9 +255,11 @@ class AssignmentOption(BaseOption):
|
||||
class AssignmentPoll(RelatedModelMixin, CollectInvalid, CollectVotesCast,
|
||||
PublishPollMixin, AbsoluteUrlMixin, BasePoll):
|
||||
option_class = AssignmentOption
|
||||
|
||||
assignment = models.ForeignKey(Assignment, related_name='poll_set')
|
||||
yesnoabstain = models.NullBooleanField()
|
||||
description = models.CharField(
|
||||
max_length=79, null=True, blank=True,
|
||||
verbose_name=ugettext_lazy("Comment on the ballot paper"))
|
||||
|
||||
def __unicode__(self):
|
||||
return _("Ballot %d") % self.get_ballot()
|
||||
@ -297,3 +299,6 @@ class AssignmentPoll(RelatedModelMixin, CollectInvalid, CollectVotesCast,
|
||||
|
||||
def get_ballot(self):
|
||||
return self.assignment.poll_set.filter(id__lte=self.id).count()
|
||||
|
||||
def append_pollform_fields(self, fields):
|
||||
fields.append('description')
|
||||
|
@ -25,14 +25,13 @@
|
||||
</small>
|
||||
</h1>
|
||||
|
||||
{% if assignment.polldescription %}
|
||||
<p><b>{% trans "Short description (for ballot paper)" %}:</b> {{ assignment.polldescription }}</p>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
{% trans "Special values" %}: <span class="badge badge-success">-1</span> = {% trans 'majority' %} | <span class="badge">-2</span> = {% trans 'undocumented' %}
|
||||
</p>
|
||||
<form action="" method="post" class="small-form">{% csrf_token %}
|
||||
<p>
|
||||
{% trans "Special values" %}:
|
||||
<span class="badge badge-success">-1</span> = {% trans 'majority' %}|
|
||||
<span class="badge">-2</span> = {% trans 'undocumented' %}
|
||||
</p>
|
||||
|
||||
<table class="table table-striped table-bordered" style="width: auto;">
|
||||
<tr>
|
||||
<th>{% trans "Candidates" %}</th>
|
||||
@ -73,10 +72,12 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p><strong>{% trans "Short description (for ballot paper)" %}:</strong></p>
|
||||
<p class="normal-form">{{ pollform.description }}</p>
|
||||
<p>
|
||||
<a href="{% url 'assignment_poll_pdf' poll.id %}" class="btn" target="_blank">
|
||||
<i class="icon-print"></i> {% trans 'Ballot paper as PDF' %}
|
||||
</a>
|
||||
<a href="{% url 'assignment_poll_pdf' poll.id %}" class="btn" target="_blank">
|
||||
<i class="icon-print"></i> {% trans 'Ballot paper as PDF' %}
|
||||
</a>
|
||||
</p>
|
||||
<!-- Control buttons -->
|
||||
<div class="control-group">
|
||||
|
@ -197,10 +197,11 @@ class AssignmentRunOtherDeleteView(SingleObjectMixin, QuestionView):
|
||||
class PollCreateView(SingleObjectMixin, RedirectView):
|
||||
model = Assignment
|
||||
permission_required = 'assignment.can_manage_assignment'
|
||||
url_name = 'assignment_poll_view'
|
||||
url_name = 'assignment_detail'
|
||||
|
||||
def pre_redirect(self, *args, **kwargs):
|
||||
self.object = self.get_object().gen_poll()
|
||||
self.object = self.get_object()
|
||||
self.object.gen_poll()
|
||||
messages.success(self.request, _("New ballot was successfully created."))
|
||||
|
||||
|
||||
@ -213,7 +214,7 @@ class PollUpdateView(PollFormView):
|
||||
self.assignment = self.poll.get_assignment()
|
||||
context['assignment'] = self.assignment
|
||||
context['poll'] = self.poll
|
||||
context['polls'] = self.assignment.poll_set.filter(assignment=self.assignment)
|
||||
context['polls'] = self.assignment.poll_set.all()
|
||||
context['ballotnumber'] = self.poll.get_ballot()
|
||||
return context
|
||||
|
||||
@ -513,7 +514,7 @@ class AssignmentPollPDF(PDFView):
|
||||
_("Election") + ": " + self.poll.assignment.name,
|
||||
stylesheet['Ballot_title']))
|
||||
cell.append(Paragraph(
|
||||
self.poll.assignment.polldescription,
|
||||
self.poll.description or '',
|
||||
stylesheet['Ballot_subtitle']))
|
||||
options = self.poll.get_options()
|
||||
|
||||
|
@ -5,7 +5,7 @@ from django import forms
|
||||
from openslides.utils.forms import CssClassMixin
|
||||
|
||||
|
||||
class OptionForm(forms.Form, CssClassMixin):
|
||||
class OptionForm(CssClassMixin, forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
extra = kwargs.pop('extra')
|
||||
formid = kwargs.pop('formid')
|
||||
@ -20,5 +20,4 @@ class OptionForm(forms.Form, CssClassMixin):
|
||||
label=value,
|
||||
initial=weight,
|
||||
min_value=-2,
|
||||
required=False,
|
||||
)
|
||||
required=False)
|
||||
|
@ -30,19 +30,19 @@ class PollFormView(FormMixin, TemplateView):
|
||||
error = True
|
||||
|
||||
if error:
|
||||
return self.render_to_response(self.get_context_data(
|
||||
response = self.render_to_response(self.get_context_data(
|
||||
forms=option_forms,
|
||||
pollform=pollform,
|
||||
))
|
||||
pollform=pollform))
|
||||
else:
|
||||
for form in option_forms:
|
||||
data = {}
|
||||
for value in self.poll.get_vote_values():
|
||||
data[value] = form.cleaned_data[value]
|
||||
self.poll.set_vote_objects_with_values(form.option, data)
|
||||
|
||||
for form in option_forms:
|
||||
data = {}
|
||||
for value in self.poll.get_vote_values():
|
||||
data[value] = form.cleaned_data[value]
|
||||
self.poll.set_vote_objects_with_values(form.option, data)
|
||||
|
||||
pollform.save()
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
pollform.save()
|
||||
response = HttpResponseRedirect(self.get_success_url())
|
||||
return response
|
||||
|
||||
def get_poll_class(self):
|
||||
if self.poll_class is not None:
|
||||
@ -71,4 +71,4 @@ class PollFormView(FormMixin, TemplateView):
|
||||
def get_modelform_class(self):
|
||||
fields = []
|
||||
self.poll.append_pollform_fields(fields)
|
||||
return modelform_factory(self.poll.__class__, fields=fields)
|
||||
return modelform_factory(type(self.poll), fields=fields)
|
||||
|
@ -142,6 +142,9 @@ input, textarea {
|
||||
.small-form input {
|
||||
width: 55px;
|
||||
}
|
||||
.normal-form input {
|
||||
width: 320px;
|
||||
}
|
||||
textarea {
|
||||
height: 100px;
|
||||
}
|
||||
@ -379,7 +382,7 @@ legend + .control-group {
|
||||
margin: 0 5px 0 45px;
|
||||
width: auto;
|
||||
}
|
||||
/* hide optional column */
|
||||
/* hide optional column */
|
||||
.optional {
|
||||
display: none;
|
||||
}
|
||||
|
@ -10,6 +10,13 @@ from openslides.utils.main_menu import MainMenuEntry
|
||||
class MainMenuEntryObject(TestCase):
|
||||
request_factory = RequestFactory()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Remove all receivers of the MainMenuEntry-signal, so it is not called in
|
||||
other tests.
|
||||
"""
|
||||
MainMenuEntry.signal.receivers = []
|
||||
|
||||
def get_entry(self, cls):
|
||||
request = self.request_factory.get('/')
|
||||
request.user = AnonymousUser()
|
||||
|
Loading…
Reference in New Issue
Block a user