Merge pull request #879 from DebVortex/feature/refactor-assignments

Refactored assignments app.
This commit is contained in:
Oskar Hahn 2013-09-14 09:22:18 -07:00
commit 7ea8a6195c
9 changed files with 310 additions and 301 deletions

View File

@ -11,3 +11,4 @@ Authors of OpenSlides in chronological order of first contribution:
Roland Geider <roland@geider.net> Roland Geider <roland@geider.net>
Tobias Hößl <tobias@hoessl.eu> Tobias Hößl <tobias@hoessl.eu>
Pavel Fric <pavelfric@seznam.cz> (Czech translation) Pavel Fric <pavelfric@seznam.cz> (Czech translation)
Max Brauer <max@max-brauer.de>

View File

@ -16,12 +16,12 @@ from django.utils.translation import ugettext as _, ugettext_lazy, ugettext_noop
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from openslides.utils.person import PersonField from openslides.utils.person import PersonField
from openslides.utils.utils import html_strong
from openslides.config.api import config from openslides.config.api import config
from openslides.projector.api import register_slidemodel from openslides.projector.api import register_slidemodel
from openslides.projector.projector import SlideMixin from openslides.projector.projector import SlideMixin
from openslides.poll.models import ( from openslides.poll.models import (
BasePoll, CountInvalid, CountVotesCast, BaseOption, PublishPollMixin, BaseVote) BasePoll, CountInvalid, CountVotesCast, BaseOption, PublishPollMixin, BaseVote)
from openslides.agenda.models import Item
class AssignmentCandidate(models.Model): class AssignmentCandidate(models.Model):
@ -54,16 +54,12 @@ class Assignment(models.Model, SlideMixin):
status = models.CharField(max_length=3, choices=STATUS, default='sea') status = models.CharField(max_length=3, choices=STATUS, default='sea')
def set_status(self, status): def set_status(self, status):
error = True status_dict = dict(self.STATUS)
for a, b in Assignment.STATUS: if status not in status_dict:
if status == a: raise ValueError(_('%s is not a valid status.') % html_strong(status))
error = False
break
if error:
raise NameError(_('%s is not a valid status.') % status)
if self.status == status: if self.status == status:
raise NameError( raise ValueError(
_('The assignment status is already %s.') % self.status) _('The assignment status is already %s.') % html_strong(status_dict[status]))
self.status = status self.status = status
self.save() self.save()
@ -228,9 +224,9 @@ class Assignment(models.Model, SlideMixin):
def get_absolute_url(self, link='detail'): def get_absolute_url(self, link='detail'):
if link == 'detail' or link == 'view': if link == 'detail' or link == 'view':
return reverse('assignment_view', args=[str(self.id)]) return reverse('assignment_detail', args=[str(self.id)])
if link == 'update' or link == 'edit': if link == 'update' or link == 'edit':
return reverse('assignment_edit', args=[str(self.id)]) return reverse('assignment_update', args=[str(self.id)])
if link == 'delete': if link == 'delete':
return reverse('assignment_delete', args=[str(self.id)]) return reverse('assignment_delete', args=[str(self.id)])
@ -299,7 +295,7 @@ class AssignmentPoll(BasePoll, CountInvalid, CountVotesCast, PublishPollMixin):
@models.permalink @models.permalink
def get_absolute_url(self, link='view'): def get_absolute_url(self, link='view'):
if link == 'view': if link == 'view' or link == 'detail' or link == 'update':
return ('assignment_poll_view', [str(self.id)]) return ('assignment_poll_view', [str(self.id)])
if link == 'delete': if link == 'delete':
return ('assignment_poll_delete', [str(self.id)]) return ('assignment_poll_delete', [str(self.id)])

View File

@ -19,8 +19,8 @@
<h1> <h1>
{{ assignment }} {{ assignment }}
<small class="pull-right"> <small class="pull-right">
<a href="{% url 'assignment_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a> <a href="{% url 'assignment_list' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
<a href="{% url 'print_assignment' assignment.id %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Print election as PDF' %}" target="_blank"><i class="icon-print"></i> PDF</a> <a href="{% url 'assignment_pdf' assignment.id %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Print election as PDF' %}" target="_blank"><i class="icon-print"></i> PDF</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.projector.can_manage_projector %}
<a href="{% url 'projector_activate_slide' assignment.sid %}" class="activate_link btn {% if assignment.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show election' %}"> <a href="{% url 'projector_activate_slide' assignment.sid %}" class="activate_link btn {% if assignment.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show election' %}">
@ -35,9 +35,9 @@
<ul class="dropdown-menu pull-right"> <ul class="dropdown-menu pull-right">
{% if perms.assignment.can_manage_assignment %} {% if perms.assignment.can_manage_assignment %}
<!-- edit --> <!-- edit -->
<li><a href="{% url 'assignment_edit' assignment.id %}"><i class="icon-pencil"></i> {% trans 'Edit election' %}</a></li> <li><a href="{{ assignment|absolute_url:'update' }}"><i class="icon-pencil"></i> {% trans 'Edit election' %}</a></li>
<!-- delete --> <!-- delete -->
<li><a href="{% url 'assignment_delete' assignment.id %}"><i class="icon-remove"></i> {% trans 'Delete election' %}</a></li> <li><a href="{{ assignment|absolute_url:'delete' }}"><i class="icon-remove"></i> {% trans 'Delete election' %}</a></li>
{% endif %} {% endif %}
<!-- create agenda item --> <!-- create agenda item -->
{% if perms.agenda.can_manage_agenda %} {% if perms.agenda.can_manage_agenda %}
@ -65,7 +65,7 @@
<ol> <ol>
{% for person in assignment.get_participants %} {% for person in assignment.get_participants %}
<li> <li>
<a href="{% model_url person 'view' %}">{{ person }}</a> <a href="{{ person|absolute_url:'detail' }}">{{ person }}</a>
{% if perms.assignment.can_manage_assignment %} {% if perms.assignment.can_manage_assignment %}
{% if assignment.status == "sea" or assignment.status == "vot" %} {% if assignment.status == "sea" or assignment.status == "vot" %}
<a href="{% url 'assignment_delother' assignment.id person.person_id %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Remove candidate' %}"><i class="icon-remove"></i></a> <a href="{% url 'assignment_delother' assignment.id person.person_id %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Remove candidate' %}"><i class="icon-remove"></i></a>
@ -126,7 +126,7 @@
<ul> <ul>
{% for person in blocked_candidates %} {% for person in blocked_candidates %}
<li> <li>
<a href="{% model_url person 'view' %}">{{ person }}</a> <a href="{{ person|absolute_url:'detail' }}">{{ person }}</a>
<a class="btn btn-mini" href="{% url 'assignment_delother' assignment.id person.person_id %}" <a class="btn btn-mini" href="{% url 'assignment_delother' assignment.id person.person_id %}"
rel="tooltip" data-original-title="{% trans 'Remove candidate' %}"> rel="tooltip" data-original-title="{% trans 'Remove candidate' %}">
<i class="icon-ban-circle"></i> <i class="icon-ban-circle"></i>
@ -168,16 +168,16 @@
<i class="icon-unchecked-new"></i> <i class="icon-unchecked-new"></i>
{% endif %} {% endif %}
</a> </a>
<a href="{% url 'assignment_poll_view' poll.id %}" class="btn btn-mini" <a href="{{ poll|absolute_url:'update' }}" class="btn btn-mini"
rel="tooltip" data-original-title="{% trans 'Edit' %}"><i class="icon-pencil"></i></a> rel="tooltip" data-original-title="{% trans 'Edit' %}"><i class="icon-pencil"></i></a>
<a href="{% url 'assignment_poll_delete' poll.id %}" class="btn btn-mini" <a href="{{ poll|absolute_url:'delete' }}" class="btn btn-mini"
rel="tooltip" data-original-title="{% trans 'Delete' %}"><i class="icon-remove"></i></a> rel="tooltip" data-original-title="{% trans 'Delete' %}"><i class="icon-remove"></i></a>
{% endif %} {% endif %}
</th> </th>
{% endfor %} {% endfor %}
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %} {% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
<th class="span1 nobr"> <th class="span1 nobr">
<a href="{% url 'assignment_gen_poll' assignment.id %}" class="btn btn-mini"> <a href="{% url 'assignment_poll_create' assignment.id %}" class="btn btn-mini">
<i class="icon-plus"></i> {% trans 'New ballot' %} <i class="icon-plus"></i> {% trans 'New ballot' %}
</a> </a>
</th> </th>
@ -200,7 +200,7 @@
<a class="election_link" href="{% url 'assignment_user_elected' assignment.id candidate.person_id %}"></a> <a class="election_link" href="{% url 'assignment_user_elected' assignment.id candidate.person_id %}"></a>
{% endif %} {% endif %}
{% endif %} {% endif %}
<a href="{% model_url candidate 'view' %}">{{ candidate }}</a> <a href="{{ candidate|absolute_url:'detail' }}">{{ candidate }}</a>
</td> </td>
{% for vote in poll_list %} {% for vote in poll_list %}
<td style="white-space:nowrap;"> <td style="white-space:nowrap;">
@ -259,7 +259,7 @@
<i>{% trans "No ballots available." %}</i> <i>{% trans "No ballots available." %}</i>
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %} {% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
<p> <p>
<a href='{% url 'assignment_gen_poll' assignment.id %}' class="btn"> <a href='{% url 'assignment_poll_create' assignment.id %}' class="btn">
<i class="icon-plus"></i> {% trans 'New ballot' %} <i class="icon-plus"></i> {% trans 'New ballot' %}
</a> </a>
</p> </p>

View File

@ -19,7 +19,7 @@
{% trans "New election" %} {% trans "New election" %}
{% endif %} {% endif %}
<small class="pull-right"> <small class="pull-right">
<a href="{% url 'assignment_overview' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a> <a href="{% url 'assignment_list' %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to overview" %}</a>
</small> </small>
</h1> </h1>
@ -27,7 +27,7 @@
{% include "form.html" %} {% include "form.html" %}
<p> <p>
{% include "formbuttons_saveapply.html" %} {% include "formbuttons_saveapply.html" %}
<a href='{% url 'assignment_overview' %}' class="btn"> <a href='{% url 'assignment_list' %}' class="btn">
{% trans 'Cancel' %} {% trans 'Cancel' %}
</a> </a>
</p> </p>

View File

@ -2,6 +2,7 @@
{% load i18n %} {% load i18n %}
{% load staticfiles %} {% load staticfiles %}
{% load tags %}
{% block title %}{% trans "Elections" %} {{ block.super }}{% endblock %} {% block title %}{% trans "Elections" %} {{ block.super }}{% endblock %}
@ -18,10 +19,10 @@
<h1>{% trans "Elections" %} <h1>{% trans "Elections" %}
<small class="pull-right"> <small class="pull-right">
{% if perms.assignment.can_manage_assignment %} {% if perms.assignment.can_manage_assignment %}
<a href="{% url 'assignment_new' %}" class="btn btn-mini btn-primary" rel="tooltip" data-original-title="{% trans 'New election' %}"><i class="icon-plus icon-white"></i> {% trans "New" %}</a> <a href="{% url 'assignment_create' %}" class="btn btn-mini btn-primary" rel="tooltip" data-original-title="{% trans 'New election' %}"><i class="icon-plus icon-white"></i> {% trans "New" %}</a>
{% endif %} {% endif %}
{% if perms.assignment.can_see_assignment %} {% if perms.assignment.can_see_assignment %}
<a href="{% url 'print_assignment' %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Print all elections as PDF' %}" target="_blank"><i class="icon-print"></i> PDF</a> <a href="{% url 'assignment_list_pdf' %}" class="btn btn-mini" rel="tooltip" data-original-title="{% trans 'Print all elections as PDF' %}" target="_blank"><i class="icon-print"></i> PDF</a>
{% endif %} {% endif %}
</small> </small>
</h1> </h1>
@ -35,41 +36,41 @@
<th class="mini_width">{% trans "Actions" %}</th> <th class="mini_width">{% trans "Actions" %}</th>
</tr> </tr>
</thead> </thead>
{% for assignment in assignments %} {% for object in object_list %}
<tr class="{% if assignment.active %}activeline{% endif %}"> <tr class="{% if object.active %}activeline{% endif %}">
<td><a href="{% url 'assignment_view' assignment.id %}">{{ assignment }}</a></td> <td><a href="{{ object|absolute_url:'detail' }}">{{ object }}</a></td>
<td class="optional"> <td class="optional">
<!-- posts --> <!-- posts -->
{% trans "Posts" context "Number of searched candidates for an election" %}: {% trans "Posts" context "Number of searched candidates for an election" %}:
<span class="badge badge-info">{{ assignment.posts }}</span> <span class="badge badge-info">{{ object.posts }}</span>
<!-- candidates --> <!-- candidates -->
{% if assignment.status != 'fin' %} {% if object.status != 'fin' %}
| {% trans "Candidates" %}: <span class="badge badge-warning">{{ assignment.get_participants|length }}</span> | {% trans "Candidates" %}: <span class="badge badge-warning">{{ object.get_participants|length }}</span>
{% endif %} {% endif %}
<!-- elected candidates --> <!-- elected candidates -->
| {% trans "Elected" %}: <span class="badge badge-success">{{ assignment.elected|length }}</span> | {% trans "Elected" %}: <span class="badge badge-success">{{ object.elected|length }}</span>
</td> </td>
<td><span class="label label-info">{{ assignment.get_status_display }}</status></td> <td><span class="label label-info">{{ object.get_status_display }}</status></td>
<td> <td>
<span style="width: 1px; white-space: nowrap;"> <span style="width: 1px; white-space: nowrap;">
{% if perms.projector.can_manage_projector %} {% if perms.projector.can_manage_projector %}
<a href="{% url 'projector_activate_slide' assignment.sid %}" <a href="{% url 'projector_activate_slide' object.sid %}"
class="activate_link btn {% if assignment.active %}btn-primary{% endif %} btn-mini" class="activate_link btn {% if object.active %}btn-primary{% endif %} btn-mini"
rel="tooltip" data-original-title="{% trans 'Show election' %}"> rel="tooltip" data-original-title="{% trans 'Show election' %}">
<i class="icon-facetime-video {% if assignment.active %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if object.active %}icon-white{% endif %}"></i>
</a> </a>
{% endif %} {% endif %}
{% if perms.assignment.can_manage_assignment %} {% if perms.assignment.can_manage_assignment %}
<a href="{% url 'assignment_edit' assignment.id %}" <a href="{{ object|absolute_url:'update' }}"
rel="tooltip" data-original-title="{% trans 'Edit' %}" rel="tooltip" data-original-title="{% trans 'Edit' %}"
class="btn btn-mini"><i class="icon-pencil"></i> class="btn btn-mini"><i class="icon-pencil"></i>
</a> </a>
<a href="{% url 'assignment_delete' assignment.id %}" <a href="{% url 'assignment_delete' object.id %}"
rel="tooltip" data-original-title="{% trans 'Delete' %}" rel="tooltip" data-original-title="{% trans 'Delete' %}"
class="btn btn-mini"><i class="icon-remove"></i> class="btn btn-mini"><i class="icon-remove"></i>
</a> </a>
{% endif %} {% endif %}
<a href="{% url 'print_assignment' assignment.id %}" <a href="{% url 'assignment_pdf' object.id %}"
data-original-title="{% trans 'Print election as PDF' %}" target="_blank" data-original-title="{% trans 'Print election as PDF' %}" target="_blank"
class="btn btn-mini tooltip-left"><i class="icon-print"></i> PDF class="btn btn-mini tooltip-left"><i class="icon-print"></i> PDF
</a> </a>

View File

@ -2,6 +2,7 @@
{% load i18n %} {% load i18n %}
{% load humanize %} {% load humanize %}
{% load tags %}
{% block title %}{% trans "Election" %} "{{ assignment }}", {{ ballotnumber }}. {% trans "ballot" %} {{ block.super }}{% endblock %} {% block title %}{% trans "Election" %} "{{ assignment }}", {{ ballotnumber }}. {% trans "ballot" %} {{ block.super }}{% endblock %}
@ -12,7 +13,7 @@
{{ ballotnumber|ordinal|safe }} {% trans "ballot" %} {{ ballotnumber|ordinal|safe }} {% trans "ballot" %}
</small> </small>
<small class="pull-right"> <small class="pull-right">
<a href="{% url 'assignment_view' assignment.id %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to election" %}</a> <a href="{{ assignment|absolute_url:'detail' }}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to election" %}</a>
<!-- activate projector --> <!-- activate projector -->
{% if perms.projector.can_manage_projector %} {% if perms.projector.can_manage_projector %}
<a href="{% url 'projector_activate_slide' assignment.sid %}" class="activate_link btn {% if assignment.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show election' %}"> <a href="{% url 'projector_activate_slide' assignment.sid %}" class="activate_link btn {% if assignment.active %}btn-primary{% endif %} btn-mini" rel="tooltip" data-original-title="{% trans 'Show election' %}">
@ -71,7 +72,7 @@
</table> </table>
<p> <p>
<a href="{% url 'print_assignment_poll' poll.id %}" class="btn" target="_blank"> <a href="{% url 'assignment_poll_pdf' poll.id %}" class="btn" target="_blank">
<i class="icon-print"></i> {% trans 'Ballot paper as PDF' %} <i class="icon-print"></i> {% trans 'Ballot paper as PDF' %}
</a> </a>
</p> </p>
@ -83,7 +84,7 @@
<button type="submit" name="apply" class="btn"> <button type="submit" name="apply" class="btn">
{% trans 'Apply' %} {% trans 'Apply' %}
</button> </button>
<a href="{% url 'assignment_view' poll.assignment.id %}" class="btn"> <a href="{{ poll.assignment|absolute_url:'detail' }}" class="btn">
{% trans 'Cancel' %} {% trans 'Cancel' %}
</a> </a>
</div> </div>

View File

@ -7,13 +7,13 @@
<a href="{% url 'projector_activate_slide' assignment.sid %}" class="activate_link btn {% if assignment.active %}btn-primary{% endif %} btn-mini" title="{% trans 'Show' %}"> <a href="{% url 'projector_activate_slide' assignment.sid %}" class="activate_link btn {% if assignment.active %}btn-primary{% endif %} btn-mini" title="{% trans 'Show' %}">
<i class="icon-facetime-video {% if assignment.active %}icon-white{% endif %}"></i> <i class="icon-facetime-video {% if assignment.active %}icon-white{% endif %}"></i>
</a>&nbsp; </a>&nbsp;
<a href="{% model_url assignment 'edit' %}" title="{% trans 'Edit' %}" class="btn btn-mini right"> <a href="{{ assignment|absolute_url:'update' }}" title="{% trans 'Edit' %}" class="btn btn-mini right">
<i class="icon-pencil"></i> <i class="icon-pencil"></i>
</a> </a>
<a href="{% url 'projctor_preview_slide' assignment.sid %}" title="{% trans 'Preview' %}" class="btn btn-mini right"> <a href="{% url 'projctor_preview_slide' assignment.sid %}" title="{% trans 'Preview' %}" class="btn btn-mini right">
<i class="icon-search"></i> <i class="icon-search"></i>
</a> </a>
<a href="{% model_url assignment 'view' %}">{{ assignment }}</a> <a href="{{ assignment|absolute_url:'detail' }}">{{ assignment }}</a>
</li> </li>
{% empty %} {% empty %}
<li>{% trans 'No assignments available.' %}</li> <li>{% trans 'No assignments available.' %}</li>

View File

@ -12,62 +12,61 @@
from django.conf.urls import url, patterns from django.conf.urls import url, patterns
from openslides.assignment.views import (ViewPoll, AssignmentPDF, from openslides.assignment.views import (AssignmentListView, AssignmentDetail,
AssignmentPollPDF, AssignmentPollDelete, CreateRelatedAgendaItemView) AssignmentCreateView, AssignmentUpdateView, AssignmentDeleteView,
AssignmentSetStatusView, AssignmentRunView, AssignmentRunDeleteView,
AssignmentRunOtherDeleteView, PollCreateView, PollUpdateView, AssignmentPDF,
AssignmentPollPDF, AssignmentPollDeleteView, SetPublishStatusView,
SetElectedView, CreateRelatedAgendaItemView)
urlpatterns = patterns('openslides.assignment.views', urlpatterns = patterns('openslides.assignment.views',
url(r'^$', url(r'^$',
'get_overview', AssignmentListView.as_view(),
name='assignment_overview', name='assignment_list',
), ),
url(r'^(?P<assignment_id>\d+)/$', url(r'^(?P<pk>\d+)/$',
'view', AssignmentDetail.as_view(),
name='assignment_view'), name='assignment_detail'),
url(r'^new/$', url(r'^new/$',
'edit', AssignmentCreateView.as_view(),
name='assignment_new', name='assignment_create',
), ),
url(r'^(?P<assignment_id>\d+)/edit/$', url(r'^(?P<pk>\d+)/edit/$',
'edit', AssignmentUpdateView.as_view(),
name='assignment_edit', name='assignment_update',
), ),
url(r'^(?P<assignment_id>\d+)/del/$', url(r'^(?P<pk>\d+)/del/$',
'delete', AssignmentDeleteView.as_view(),
name='assignment_delete', name='assignment_delete',
), ),
url(r'^(?P<assignment_id>\d+)/setstatus/(?P<status>[a-z]{3})/$', url(r'^(?P<pk>\d+)/setstatus/(?P<status>[a-z]{3})/$',
'set_status', AssignmentSetStatusView.as_view(),
name='assignment_set_status', name='assignment_set_status',
), ),
url(r'^(?P<assignment_id>\d+)/run/$', url(r'^(?P<pk>\d+)/run/$',
'run', AssignmentRunView.as_view(),
name='assignment_run', name='assignment_run',
), ),
url(r'^(?P<assignment_id>\d+)/delrun/$', url(r'^(?P<pk>\d+)/delrun/$',
'delrun', AssignmentRunDeleteView.as_view(),
name='assignment_delrun', name='assignment_delrun',
), ),
url(r'^(?P<assignment_id>\d+)/delother/(?P<user_id>[^/]+)/$', url(r'^(?P<pk>\d+)/delother/(?P<user_id>[^/]+)/$',
'delother', AssignmentRunOtherDeleteView.as_view(),
name='assignment_delother', name='assignment_delother',
), ),
url(r'^(?P<assignment_id>\d+)/set_active/$',
'set_active',
name='assignment_activate_item',
),
url(r'^poll/(?P<poll_id>\d+)/print/$', url(r'^poll/(?P<poll_id>\d+)/print/$',
AssignmentPollPDF.as_view(), AssignmentPollPDF.as_view(),
name='print_assignment_poll', name='assignment_poll_pdf',
), ),
url(r'^(?P<pk>\d+)/agenda/$', url(r'^(?P<pk>\d+)/agenda/$',
@ -77,42 +76,42 @@ urlpatterns = patterns('openslides.assignment.views',
url(r'^print/$', url(r'^print/$',
AssignmentPDF.as_view(), AssignmentPDF.as_view(),
name='print_assignment', name='assignment_list_pdf',
), ),
url(r'^(?P<assignment_id>\d+)/print/$', url(r'^(?P<pk>\d+)/print/$',
AssignmentPDF.as_view(), AssignmentPDF.as_view(),
name='print_assignment', name='assignment_pdf',
), ),
url(r'^(?P<assignment_id>\d+)/gen_poll/$', url(r'^(?P<pk>\d+)/gen_poll/$',
'gen_poll', PollCreateView.as_view(),
name='assignment_gen_poll', name='assignment_poll_create',
), ),
url(r'^poll/(?P<poll_id>\d+)/$', url(r'^poll/(?P<poll_id>\d+)/$',
ViewPoll.as_view(), PollUpdateView.as_view(),
name='assignment_poll_view', name='assignment_poll_view',
), ),
url(r'^poll/(?P<pk>\d+)/del/$', url(r'^poll/(?P<pk>\d+)/del/$',
AssignmentPollDelete.as_view(), AssignmentPollDeleteView.as_view(),
name='assignment_poll_delete', name='assignment_poll_delete',
), ),
url(r'^poll/(?P<poll_id>\d+)/pub/$', url(r'^poll/(?P<pk>\d+)/pub/$',
'set_publish_status', SetPublishStatusView.as_view(),
name='assignment_poll_publish_status', name='assignment_poll_publish_status',
), ),
url(r'^(?P<assignment_id>\d+)/elected/(?P<user_id>[^/]+)/$', url(r'^(?P<pk>\d+)/elected/(?P<user_id>[^/]+)/$',
'set_elected', SetElectedView.as_view(),
{'elected': True}, {'elected': True},
name='assignment_user_elected', name='assignment_user_elected',
), ),
url(r'^(?P<assignment_id>\d+)/notelected/(?P<user_id>[^/]+)/$', url(r'^(?P<pk>\d+)/notelected/(?P<user_id>[^/]+)/$',
'set_elected', SetElectedView.as_view(),
{'elected': False}, {'elected': False},
name='assignment_user_not_elected', name='assignment_user_not_elected',
), ),

View File

@ -20,16 +20,18 @@ from reportlab.lib.units import cm
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import ungettext, ugettext as _ from django.utils.translation import ungettext, ugettext as _
from openslides.utils.pdf import stylesheet from openslides.utils.pdf import stylesheet
from openslides.utils.template import Tab from openslides.utils.template import Tab
from openslides.utils.utils import ( from openslides.utils.utils import gen_confirm_form
template, permission_required, gen_confirm_form, del_confirm_form, ajax_request)
from openslides.utils.views import FormView, DeleteView, PDFView, RedirectView from openslides.utils.views import (
CreateView, DeleteView, RedirectView, UpdateView, ListView, PDFView,
DetailView, View, PermissionMixin, SingleObjectMixin, QuestionMixin)
from openslides.utils.person import get_person from openslides.utils.person import get_person
from openslides.utils.utils import html_strong
from openslides.config.api import config from openslides.config.api import config
from openslides.participant.models import User, Group from openslides.participant.models import User, Group
from openslides.projector.projector import Widget from openslides.projector.projector import Widget
@ -39,199 +41,194 @@ from openslides.assignment.models import Assignment, AssignmentPoll
from openslides.assignment.forms import AssignmentForm, AssignmentRunForm from openslides.assignment.forms import AssignmentForm, AssignmentRunForm
@permission_required('assignment.can_see_assignment') class AssignmentListView(ListView):
@template('assignment/overview.html') """ListView for all Assignments"""
def get_overview(request): permission_required = 'assignment.can_see_assignment'
assignments = Assignment.objects.all() model = Assignment
return {
'assignments': assignments,
}
@permission_required('assignment.can_see_assignment') class AssignmentDetail(DetailView):
@template('assignment/view.html') permission_required = 'assignment.can_see_assignment'
def view(request, assignment_id=None): model = Assignment
form = None form_class = AssignmentRunForm
assignment = Assignment.objects.get(pk=assignment_id)
if request.method == 'POST': def get_context_data(self, *args, **kwargs):
if request.user.has_perm('assignment.can_nominate_other'): context = super(AssignmentDetail, self).get_context_data(*args, **kwargs)
form = AssignmentRunForm(request.POST) if self.request.method == 'POST':
context['form'] = self.form_class(self.request.POST)
else:
context['form'] = self.form_class()
polls = self.object.poll_set.all()
if not self.request.user.has_perm('assignment.can_manage_assignment'):
polls = self.object.poll_set.filter(published=True)
vote_results = self.object.vote_results(only_published=True)
else:
polls = self.object.poll_set.all()
vote_results = self.object.vote_results(only_published=False)
blocked_candidates = [
candidate.person for candidate in
self.object.assignment_candidates.filter(blocked=True)]
context['polls'] = polls
context['vote_results'] = vote_results
context['blocked_candidates'] = blocked_candidates
context['user_is_candidate'] = self.object.is_candidate(self.request.user)
return context
def post(self, *args, **kwargs):
self.object = self.get_object()
if self.request.user.has_perm('assignment.can_nominate_other'):
form = self.form_class(self.request.POST)
if form.is_valid(): if form.is_valid():
user = form.cleaned_data['candidate'] user = form.cleaned_data['candidate']
try: try:
assignment.run(user, request.user) self.object.run(user, self.request.user)
except NameError, e: except NameError, e:
messages.error(request, e) messages.error(self.request, e)
else: else:
messages.success(request, _( messages.success(self.request, _(
"Candidate <b>%s</b> was nominated successfully.") "Candidate %s was nominated successfully.")
% user) % html_strong(user))
else: return super(AssignmentDetail, self).get(*args, **kwargs)
if request.user.has_perm('assignment.can_nominate_other'):
form = AssignmentRunForm()
polls = assignment.poll_set.all()
if not request.user.has_perm('assignment.can_manage_assignment'):
polls = assignment.poll_set.filter(published=True)
vote_results = assignment.vote_results(only_published=True)
else:
polls = assignment.poll_set.all()
vote_results = assignment.vote_results(only_published=False)
blocked_candidates = [
candidate.person for candidate in
assignment.assignment_candidates.filter(blocked=True)]
return {
'assignment': assignment,
'blocked_candidates': blocked_candidates,
'form': form,
'vote_results': vote_results,
'polls': polls,
'user_is_candidate': assignment.is_candidate(request.user)}
@permission_required('assignment.can_manage_assignment') class AssignmentCreateView(CreateView):
@template('assignment/edit.html') model = Assignment
def edit(request, assignment_id=None): form_class = AssignmentForm
""" permission_required = 'assignment.can_manage_assignment'
View zum editieren und neuanlegen von Wahlen
"""
if assignment_id is not None:
assignment = Assignment.objects.get(id=assignment_id)
else:
assignment = None
if request.method == 'POST':
form = AssignmentForm(request.POST, instance=assignment)
if form.is_valid():
assignment = form.save()
if assignment_id is None:
messages.success(request, _('New election was successfully created.'))
else:
messages.success(request, _('Election was successfully modified.'))
if not 'apply' in request.POST:
return redirect(reverse("assignment_overview"))
if assignment_id is None:
return redirect(reverse('assignment_edit', args=[assignment.id]))
else:
messages.error(request, _('Please check the form for errors.'))
else:
form = AssignmentForm(instance=assignment)
if assignment:
polls = assignment.poll_set.filter(assignment=assignment)
else:
polls = None
return {
'form': form,
'assignment': assignment,
'polls': polls,
}
@permission_required('assignment.can_manage_assignment') class AssignmentUpdateView(UpdateView):
def delete(request, assignment_id): model = Assignment
assignment = Assignment.objects.get(pk=assignment_id) form_class = AssignmentForm
if request.method == 'POST': permission_required = 'assignment.can_manage_assignment'
if 'submit' in request.POST:
assignment.delete()
messages.success(request, _('Election <b>%s</b> was successfully deleted.') % assignment)
else:
del_confirm_form(request, assignment)
return redirect(reverse('assignment_overview'))
@permission_required('assignment.can_manage_assignment') class AssignmentDeleteView(DeleteView):
@template('assignment/view.html') permission_required = 'assignment.can_manage_assignment'
def set_status(request, assignment_id=None, status=None): model = Assignment
try: success_url_name = 'assignment_list'
class AssignmentSetStatusView(SingleObjectMixin, RedirectView):
model = Assignment
permission_required = 'assignment.can_manage_assignment'
url_name = 'assignment_detail'
def pre_redirect(self, *args, **kwargs):
self.object = self.get_object()
status = kwargs.get('status')
if status is not None: if status is not None:
assignment = Assignment.objects.get(pk=assignment_id) try:
assignment.set_status(status) self.object.set_status(status)
messages.success(request, _('Election status was set to: <b>%s</b>.') % assignment.get_status_display()) except ValueError, e:
except Assignment.DoesNotExist: messages.error(self.request, e)
pass else:
except NameError, e: messages.success(
messages.error(request, e) self.request,
return redirect(reverse('assignment_view', args=[assignment_id])) _('Election status was set to: %s.') %
html_strong(self.object.get_status_display())
)
@permission_required('assignment.can_nominate_self') class AssignmentRunView(SingleObjectMixin, PermissionMixin, View):
def run(request, assignment_id): model = Assignment
assignment = Assignment.objects.get(pk=assignment_id) permission_required = 'assignment.can_nominate_self'
try:
assignment.run(request.user, request.user)
messages.success(request, _('You have set your candidature successfully.'))
except NameError, e:
messages.error(request, e)
return redirect(reverse('assignment_view', args=[assignment_id]))
def get(self, *args, **kwargs):
@login_required assignment = self.get_object()
def delrun(request, assignment_id):
assignment = Assignment.objects.get(pk=assignment_id)
if assignment.status == 'sea' or request.user.has_perm("assignment.can_manage_assignment"):
try: try:
assignment.delrun(request.user, blocked=True) assignment.run(self.request.user, self.request.user)
except Exception, e: except NameError, e:
messages.error(request, e) messages.error(self.request, e)
else: else:
messages.success( messages.success(
request, self.request, _('You have set your candidature successfully.'))
_("You have withdrawn your candidature successfully. " return redirect(reverse('assignment_detail', args=[assignment.pk]))
"You can not be nominated by other participants anymore."))
else:
messages.error(request, _('The candidate list is already closed.'))
return redirect(reverse('assignment_view', args=[assignment_id]))
@permission_required('assignment.can_manage_assignment') class AssignmentRunDeleteView(SingleObjectMixin, RedirectView):
def delother(request, assignment_id, user_id): model = Assignment
assignment = Assignment.objects.get(pk=assignment_id) url_name = 'assignment_detail'
person = get_person(user_id) success_message = _("You have withdrawn your candidature successfully. "
is_blocked = assignment.is_blocked(person) "You can not be nominated by other participants anymore.")
if request.method == 'POST': def pre_redirect(self, *args, **kwargs):
if 'submit' in request.POST: self.object = self.get_object()
if self.object.status == 'sea' or self.request.user.has_perm(
"assignment.can_manage_assignment"):
try: try:
assignment.delrun(person, blocked=False) self.object.delrun(self.request.user, blocked=True)
except Exception, e: except Exception, e:
messages.error(request, e) messages.error(self.request, e)
else: else:
if not is_blocked: messages.success(self.request, self.success_message)
message = _("Candidate <b>%s</b> was withdrawn successfully.") % person
else:
message = _("<b>%s</b> was unblocked successfully.") % person
messages.success(request, message)
else:
if not is_blocked:
message = _("Do you really want to withdraw <b>%s</b> from the election?") % person
else: else:
message = _("Do you really want to unblock <b>%s</b> for the election?") % person messages.error(self.request, _('The candidate list is already closed.'))
gen_confirm_form(request, message, reverse('assignment_delother', args=[assignment_id, user_id]))
return redirect(reverse('assignment_view', args=[assignment_id]))
@permission_required('assignment.can_manage_assignment') class AssignmentRunOtherDeleteView(SingleObjectMixin, QuestionMixin,
def set_active(request, assignment_id): RedirectView):
assignment = Assignment.objects.get(pk=assignment_id) model = Assignment
assignment.set_active() permission_required = 'assignment.can_manage_assignment'
return redirect(reverse('assignment_view', args=[assignment_id])) question_url_name = 'assignment_detail'
success_url_name = 'assignment_detail'
success_message = ''
def pre_redirect(self, *args, **kwargs):
self._get_person_information(*args, **kwargs)
if not self.is_blocked:
message = _("Do you really want to withdraw %s from the election?") % html_strong(self.person)
else:
message = _("Do you really want to unblock %s for the election?") % html_strong(self.person)
gen_confirm_form(self.request, message, reverse('assignment_delother',
args=[self.object.pk, kwargs['user_id']]))
def pre_post_redirect(self, *args, **kwargs):
self._get_person_information(*args, **kwargs)
if self.get_answer() == 'yes':
self.case_yes()
def get_answer(self):
if 'submit' in self.request.POST:
return 'yes'
def case_yes(self):
try:
self.object.delrun(self.person, blocked=False)
except Exception, e:
messages.error(self.request, e)
else:
messages.success(self.request, self.get_success_message())
def get_success_message(self):
success_message = _("Candidate %s was withdrawn successfully.") % html_strong(self.person)
if self.is_blocked:
success_message = _("%s was unblocked successfully.") % html_strong(self.person)
return success_message
def _get_person_information(self, *args, **kwargs):
self.object = self.get_object()
self.person = get_person(kwargs.get('user_id'))
self.is_blocked = self.object.is_blocked(self.person)
@permission_required('assignment.can_manage_assignment') class PollCreateView(SingleObjectMixin, RedirectView):
def gen_poll(request, assignment_id): model = Assignment
poll = Assignment.objects.get(pk=assignment_id).gen_poll() permission_required = 'assignment.can_manage_assignment'
messages.success(request, _("New ballot was successfully created.")) url_name = 'assignment_poll_view'
return redirect(reverse('assignment_poll_view', args=[poll.id]))
def pre_redirect(self, *args, **kwargs):
self.object = self.get_object().gen_poll()
messages.success(self.request, _("New ballot was successfully created."))
class ViewPoll(PollFormView): class PollUpdateView(PollFormView):
poll_class = AssignmentPoll poll_class = AssignmentPoll
template_name = 'assignment/poll_view.html' template_name = 'assignment/poll_view.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(ViewPoll, self).get_context_data(**kwargs) context = super(PollUpdateView, self).get_context_data(**kwargs)
self.assignment = self.poll.get_assignment() self.assignment = self.poll.get_assignment()
context['assignment'] = self.assignment context['assignment'] = self.assignment
context['poll'] = self.poll context['poll'] = self.poll
@ -240,52 +237,63 @@ class ViewPoll(PollFormView):
return context return context
def get_success_url(self): def get_success_url(self):
return_url = ''
if not 'apply' in self.request.POST: if not 'apply' in self.request.POST:
return reverse('assignment_view', args=[self.poll.assignment.id]) return_url = reverse('assignment_detail', args=[self.poll.assignment.id])
return '' return return_url
@permission_required('assignment.can_manage_assignment') class SetPublishStatusView(SingleObjectMixin, RedirectView):
def set_publish_status(request, poll_id): model = AssignmentPoll
try: permission_required = 'assignment.can_manage_assignment'
poll = AssignmentPoll.objects.get(pk=poll_id) url_name = 'assignment_list'
if poll.published: allow_ajax = True
poll.set_published(False)
def get_ajax_context(self):
return {'published': self.object.published}
def pre_redirect(self, *args, **kwargs):
try:
self.object = self.get_object()
except self.model.DoesNotExist:
messages.error(self.request, _('Ballot ID %d does not exist.') %
int(kwargs['poll_id']))
return
if self.object.published:
self.object.set_published(False)
else: else:
poll.set_published(True) self.object.set_published(True)
except AssignmentPoll.DoesNotExist: if self.object.published:
messages.error(request, _('Ballot ID %d does not exist.') % int(poll_id)) messages.success(self.request, _("Ballot successfully published."))
return redirect(reverse('assignment_overview')) else:
messages.success(self.request, _("Ballot successfully unpublished."))
if request.is_ajax():
return ajax_request({'published': poll.published})
if poll.published:
messages.success(request, _("Ballot successfully published."))
else:
messages.success(request, _("Ballot successfully unpublished."))
return redirect(reverse('assignment_view', args=[poll.assignment.id]))
@permission_required('assignment.can_manage_assignment') class SetElectedView(SingleObjectMixin, RedirectView):
def set_elected(request, assignment_id, user_id, elected=True): model = Assignment
assignment = Assignment.objects.get(pk=assignment_id) permission_required = 'assignment.can_manage_assignment'
person = get_person(user_id) url_name = 'assignment_detail'
assignment.set_elected(person, elected) allow_ajax = True
if request.is_ajax(): def pre_redirect(self, *args, **kwargs):
if elected: self.object = self.get_object()
link = reverse('assignment_user_not_elected', args=[assignment.id, person.person_id]) self.person = get_person(kwargs['user_id'])
self.elected = kwargs['elected']
self.object.set_elected(self.person, self.elected)
def get_ajax_context(self):
if self.elected:
link = reverse('assignment_user_not_elected',
args=[self.object.id, self.person.person_id])
text = _('not elected') text = _('not elected')
else: else:
link = reverse('assignment_user_elected', args=[assignment.id, person.person_id]) link = reverse('assignment_user_elected',
args=[self.self.object.id, self.person.person_id])
text = _('elected') text = _('elected')
return ajax_request({'elected': elected, 'link': link, 'text': text}) return {'elected': self.elected, 'link': link, 'text': text}
return redirect(reverse('assignment_view', args=[assignment_id]))
class AssignmentPollDelete(DeleteView): class AssignmentPollDeleteView(DeleteView):
""" """
Delete an assignment poll object. Delete an assignment poll object.
""" """
@ -294,17 +302,17 @@ class AssignmentPollDelete(DeleteView):
def pre_redirect(self, request, *args, **kwargs): def pre_redirect(self, request, *args, **kwargs):
self.set_assignment() self.set_assignment()
super(AssignmentPollDelete, self).pre_redirect(request, *args, **kwargs) super(AssignmentPollDeleteView, self).pre_redirect(request, *args, **kwargs)
def pre_post_redirect(self, request, *args, **kwargs): def pre_post_redirect(self, request, *args, **kwargs):
self.set_assignment() self.set_assignment()
super(AssignmentPollDelete, self).pre_post_redirect(request, *args, **kwargs) super(AssignmentPollDeleteView, self).pre_post_redirect(request, *args, **kwargs)
def set_assignment(self): def set_assignment(self):
self.assignment = self.object.assignment self.assignment = self.object.assignment
def get_redirect_url(self, **kwargs): def get_redirect_url(self, **kwargs):
return reverse('assignment_view', args=[self.assignment.id]) return reverse('assignment_detail', args=[self.assignment.id])
def get_success_message(self): def get_success_message(self):
return _('Ballot was successfully deleted.') return _('Ballot was successfully deleted.')
@ -316,7 +324,7 @@ class AssignmentPDF(PDFView):
def get_filename(self): def get_filename(self):
try: try:
assignment_id = self.kwargs['assignment_id'] assignment_id = self.kwargs['pk']
assignment = Assignment.objects.get(id=assignment_id) assignment = Assignment.objects.get(id=assignment_id)
filename = u'%s-%s' % ( filename = u'%s-%s' % (
_("Assignment"), _("Assignment"),
@ -327,7 +335,7 @@ class AssignmentPDF(PDFView):
def append_to_pdf(self, story): def append_to_pdf(self, story):
try: try:
assignment_id = self.kwargs['assignment_id'] assignment_id = self.kwargs['pk']
except KeyError: except KeyError:
assignment_id = None assignment_id = None
if assignment_id is None: # print all assignments if assignment_id is None: # print all assignments
@ -455,13 +463,16 @@ class AssignmentPDF(PDFView):
data_votes.append(footrow_two) data_votes.append(footrow_two)
table_votes = Table(data_votes) table_votes = Table(data_votes)
table_votes.setStyle(TableStyle([ table_votes.setStyle(
('GRID', (0, 0), (-1, -1), 0.5, colors.grey), TableStyle([
('VALIGN', (0, 0), (-1, -1), 'TOP'), ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
('LINEABOVE', (0, 0), (-1, 0), 2, colors.black), ('VALIGN', (0, 0), (-1, -1), 'TOP'),
('LINEABOVE', (0, 1), (-1, 1), 1, colors.black), ('LINEABOVE', (0, 0), (-1, 0), 2, colors.black),
('LINEBELOW', (0, -1), (-1, -1), 2, colors.black), ('LINEABOVE', (0, 1), (-1, 1), 1, colors.black),
('ROWBACKGROUNDS', (0, 1), (-1, -1), (colors.white, (.9, .9, .9)))])) ('LINEBELOW', (0, -1), (-1, -1), 2, colors.black),
('ROWBACKGROUNDS', (0, 1), (-1, -1), (colors.white, (.9, .9, .9)))
])
)
# table # table
data = [] data = []
@ -482,9 +493,9 @@ class AssignmentPDF(PDFView):
story.append(Spacer(0, 1 * cm)) story.append(Spacer(0, 1 * cm))
# text # text
story.append(Paragraph( story.append(
"%s" % assignment.description.replace('\r\n', Paragraph("%s" % assignment.description.replace('\r\n', '<br/>'),
'<br/>'), stylesheet['Paragraph'])) stylesheet['Paragraph']))
class CreateRelatedAgendaItemView(_CreateRelatedAgendaItemView): class CreateRelatedAgendaItemView(_CreateRelatedAgendaItemView):
@ -536,8 +547,8 @@ class AssignmentPollPDF(PDFView):
"%d available post", "%d available posts", "%d available post", "%d available posts",
self.poll.assignment.posts) % self.poll.assignment.posts self.poll.assignment.posts) % self.poll.assignment.posts
cell.append(Paragraph( cell.append(Paragraph(
"%s, %s, %s" % (ballot_string, candidate_string, "%s, %s, %s" % (ballot_string, candidate_string, available_posts_string),
available_posts_string), stylesheet['Ballot_description'])) stylesheet['Ballot_description']))
cell.append(Spacer(0, 0.4 * cm)) cell.append(Spacer(0, 0.4 * cm))
data = [] data = []
@ -624,7 +635,7 @@ def register_tab(request):
return Tab( return Tab(
title=_('Elections'), title=_('Elections'),
app='assignment', app='assignment',
url=reverse('assignment_overview'), url=reverse('assignment_list'),
permission=( permission=(
request.user.has_perm('assignment.can_see_assignment') or request.user.has_perm('assignment.can_see_assignment') or
request.user.has_perm('assignment.can_nominate_other') or request.user.has_perm('assignment.can_nominate_other') or