Merge pull request #1537 from normanjaeckel/RESTPoll
Added create, updated and destroy view for assignment polls.
This commit is contained in:
commit
a604f36634
@ -17,7 +17,7 @@ class AssignmentAppConfig(AppConfig):
|
||||
from openslides.utils.signals import template_manipulation
|
||||
from .signals import setup_assignment_config
|
||||
from .template import add_assignment_stylesheets
|
||||
from .views import AssignmentViewSet
|
||||
from .views import AssignmentViewSet, AssignmentPollViewSet
|
||||
|
||||
# Connect signals.
|
||||
config_signal.connect(setup_assignment_config, dispatch_uid='setup_assignment_config')
|
||||
@ -33,3 +33,4 @@ class AssignmentAppConfig(AppConfig):
|
||||
|
||||
# Register viewsets.
|
||||
router.register('assignments/assignment', AssignmentViewSet)
|
||||
router.register('assignments/assignmentpoll', AssignmentPollViewSet)
|
||||
|
@ -247,7 +247,7 @@ class Assignment(RESTModelMixin, SlideMixin, AbsoluteUrlMixin, models.Model):
|
||||
|
||||
def create_poll(self):
|
||||
"""
|
||||
Creates an new poll for the assignment and adds all candidates to all
|
||||
Creates a new poll for the assignment and adds all candidates to all
|
||||
lists of speakers of related agenda items.
|
||||
"""
|
||||
candidates = self.candidates.all()
|
||||
|
@ -1,4 +1,13 @@
|
||||
from openslides.utils.rest_api import ListSerializer, ModelSerializer
|
||||
from django.db import transaction
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from openslides.utils.rest_api import (
|
||||
DictField,
|
||||
IntegerField,
|
||||
ListField,
|
||||
ListSerializer,
|
||||
ModelSerializer,
|
||||
ValidationError)
|
||||
|
||||
from .models import (
|
||||
models,
|
||||
@ -64,6 +73,10 @@ class AssignmentAllPollSerializer(ModelSerializer):
|
||||
Serializes all polls.
|
||||
"""
|
||||
assignmentoption_set = AssignmentOptionSerializer(many=True, read_only=True)
|
||||
votes = ListField(
|
||||
child=DictField(
|
||||
child=IntegerField(min_value=-2)),
|
||||
write_only=True)
|
||||
|
||||
class Meta:
|
||||
model = AssignmentPoll
|
||||
@ -75,7 +88,46 @@ class AssignmentAllPollSerializer(ModelSerializer):
|
||||
'assignmentoption_set',
|
||||
'votesvalid',
|
||||
'votesinvalid',
|
||||
'votescast',)
|
||||
'votescast',
|
||||
'votes',)
|
||||
read_only_fields = ('yesnoabstain',)
|
||||
|
||||
@transaction.atomic
|
||||
def update(self, instance, validated_data):
|
||||
"""
|
||||
Customized update method for polls. To update votes use the write
|
||||
only field 'votes'.
|
||||
|
||||
Example data for a 'yesnoabstain' poll with two candidates:
|
||||
|
||||
"votes": [{"Yes": 10, "No": 4, "Abstain": -2},
|
||||
{"Yes": -1, "No": 0, "Abstain": -2}]
|
||||
"""
|
||||
# Update votes.
|
||||
votes = validated_data.get('votes')
|
||||
if votes:
|
||||
options = list(instance.get_options())
|
||||
if len(votes) != len(options):
|
||||
raise ValidationError({
|
||||
'detail': _('You have to submit data for %d candidates.') % len(options)})
|
||||
for index, option in enumerate(options):
|
||||
if len(votes[index]) != len(instance.get_vote_values()):
|
||||
raise ValidationError({
|
||||
'detail': _('You have to submit data for %d vote values.') % len(instance.get_vote_values())})
|
||||
for vote_value, vote_weight in votes[index].items():
|
||||
if vote_value not in instance.get_vote_values():
|
||||
raise ValidationError({
|
||||
'detail': _('Vote value %s is invalid.') % vote_value})
|
||||
instance.set_vote_objects_with_values(option, votes[index])
|
||||
|
||||
# Update remaining writeable fields.
|
||||
instance.description = validated_data.get('description', instance.description)
|
||||
instance.published = validated_data.get('published', instance.published)
|
||||
instance.votesvalid = validated_data.get('votesvalid', instance.votesvalid)
|
||||
instance.votesinvalid = validated_data.get('votesinvalid', instance.votesinvalid)
|
||||
instance.votescast = validated_data.get('votescast', instance.votescast)
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
class AssignmentShortPollSerializer(AssignmentAllPollSerializer):
|
||||
|
@ -1,5 +1,6 @@
|
||||
from cgi import escape
|
||||
|
||||
from django.db import transaction
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ungettext
|
||||
from reportlab.lib import colors
|
||||
@ -10,34 +11,46 @@ from reportlab.platypus import (PageBreak, Paragraph, SimpleDocTemplate, Spacer,
|
||||
from openslides.config.api import config
|
||||
from openslides.users.models import Group, User # TODO: remove this
|
||||
from openslides.utils.pdf import stylesheet
|
||||
from openslides.utils.rest_api import ModelViewSet, Response, ValidationError, detail_route
|
||||
from openslides.utils.rest_api import (
|
||||
DestroyModelMixin,
|
||||
GenericViewSet,
|
||||
ModelViewSet,
|
||||
Response,
|
||||
UpdateModelMixin,
|
||||
ValidationError,
|
||||
detail_route)
|
||||
from openslides.utils.views import PDFView
|
||||
|
||||
from .models import Assignment, AssignmentPoll
|
||||
from .serializers import AssignmentFullSerializer, AssignmentShortSerializer
|
||||
from .serializers import (
|
||||
AssignmentAllPollSerializer,
|
||||
AssignmentFullSerializer,
|
||||
AssignmentShortSerializer
|
||||
)
|
||||
|
||||
|
||||
class AssignmentViewSet(ModelViewSet):
|
||||
"""
|
||||
API endpoint to list, retrieve, create, update and destroy assignments and
|
||||
to manage candidatures.
|
||||
API endpoint to list, retrieve, create, update and destroy assignments
|
||||
and to manage candidatures.
|
||||
"""
|
||||
queryset = Assignment.objects.all()
|
||||
|
||||
def check_permissions(self, request):
|
||||
"""
|
||||
Calls self.permission_denied() if the requesting user has not the
|
||||
permission to see assignments and in case of create, update or destroy
|
||||
requests the permission to manage assignments.
|
||||
permission to see assignments and in case of create, update,
|
||||
partial_update or destroy requests the permission to manage
|
||||
assignments.
|
||||
"""
|
||||
if (not request.user.has_perm('assignments.can_see') or
|
||||
(self.action in ('create', 'update', 'destroy') and not
|
||||
request.user.has_perm('assignments.can_manage'))):
|
||||
(self.action in ('create', 'update', 'partial_update', 'destroy') and
|
||||
not request.user.has_perm('assignments.can_manage'))):
|
||||
self.permission_denied(request)
|
||||
|
||||
def get_serializer_class(self):
|
||||
"""
|
||||
Returns different serializer classes with respect to users permissions.
|
||||
Returns different serializer classes according to users permissions.
|
||||
"""
|
||||
if self.request.user.has_perm('assignments.can_manage'):
|
||||
serializer_class = AssignmentFullSerializer
|
||||
@ -48,8 +61,8 @@ class AssignmentViewSet(ModelViewSet):
|
||||
@detail_route(methods=['post', 'delete'])
|
||||
def candidature_self(self, request, pk=None):
|
||||
"""
|
||||
View to nominate self as candidate (POST) or withdraw own candidature
|
||||
(DELETE).
|
||||
View to nominate self as candidate (POST) or withdraw own
|
||||
candidature (DELETE).
|
||||
"""
|
||||
if not request.user.has_perm('assignments.can_nominate_self'):
|
||||
self.permission_denied(request)
|
||||
@ -157,8 +170,8 @@ class AssignmentViewSet(ModelViewSet):
|
||||
@detail_route(methods=['post', 'delete'])
|
||||
def mark_elected(self, request, pk=None):
|
||||
"""
|
||||
View to mark other users as elected (POST) undo this (DELETE). The
|
||||
client has to send {'user': <id>}.
|
||||
View to mark other users as elected (POST) or undo this (DELETE).
|
||||
The client has to send {'user': <id>}.
|
||||
"""
|
||||
if not request.user.has_perm('assignments.can_manage'):
|
||||
self.permission_denied(request)
|
||||
@ -178,6 +191,37 @@ class AssignmentViewSet(ModelViewSet):
|
||||
message = _('User %s was successfully unelected.') % user
|
||||
return Response({'detail': message})
|
||||
|
||||
@detail_route(methods=['post'])
|
||||
def create_poll(self, request, pk=None):
|
||||
"""
|
||||
View to create a poll. It is a POST request without any data.
|
||||
"""
|
||||
if not request.user.has_perm('assignments.can_manage'):
|
||||
self.permission_denied(request)
|
||||
assignment = self.get_object()
|
||||
if not assignment.candidates.exists():
|
||||
raise ValidationError({'detail': _('Can not create poll because there are no candidates.')})
|
||||
with transaction.atomic():
|
||||
assignment.create_poll()
|
||||
return Response({'detail': _(' Poll created successfully.')})
|
||||
|
||||
|
||||
class AssignmentPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
||||
"""
|
||||
API endpoint to update and destroy assignment polls.
|
||||
"""
|
||||
queryset = AssignmentPoll.objects.all()
|
||||
serializer_class = AssignmentAllPollSerializer
|
||||
|
||||
def check_permissions(self, request):
|
||||
"""
|
||||
Calls self.permission_denied() if the requesting user has not the
|
||||
permission to see assignments and to manage assignments.
|
||||
"""
|
||||
if (not request.user.has_perm('assignments.can_see') or
|
||||
not request.user.has_perm('assignments.can_manage')):
|
||||
self.permission_denied(request)
|
||||
|
||||
|
||||
class AssignmentPDF(PDFView):
|
||||
required_permission = 'assignments.can_see'
|
||||
|
@ -6,17 +6,20 @@ from django.core.urlresolvers import reverse
|
||||
from rest_framework.decorators import detail_route # noqa
|
||||
from rest_framework.serializers import ( # noqa
|
||||
CharField,
|
||||
DictField,
|
||||
Field,
|
||||
IntegerField,
|
||||
ListField,
|
||||
ListSerializer,
|
||||
ModelSerializer,
|
||||
PrimaryKeyRelatedField,
|
||||
RelatedField,
|
||||
SerializerMethodField,
|
||||
ValidationError)
|
||||
from rest_framework.mixins import DestroyModelMixin, UpdateModelMixin # noqa
|
||||
from rest_framework.response import Response # noqa
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet, ViewSet # noqa
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet, ViewSet # noqa
|
||||
from rest_framework.decorators import list_route # noqa
|
||||
|
||||
from .exceptions import OpenSlidesError
|
||||
|
Loading…
Reference in New Issue
Block a user