OpenSlides/openslides/motions/serializers.py
Emanuel Schuetze ed72a90306 Reworked all motions templates.
motion detail:
- added progres bar for motionpoll
- added support/unsupport function
- show log

motion list:
- added state filter
- added css animations for enter/leave

motion form:
- use angular-formly (instead of old ng-fab-forms with no angular 1.4.x support)

general:
- Workflow states use new field 'css_class' (instead of unused
  'icon'). Added migration file.
- added 'allowed_actions' to rest api for each motion (by Norman)
- updated all JavaScript dependencies (bower.json)
2015-11-11 10:50:49 +01:00

282 lines
8.3 KiB
Python

from django.db import transaction
from django.utils.translation import ugettext as _
from openslides.utils.rest_api import (
CharField,
DictField,
IntegerField,
ModelSerializer,
PrimaryKeyRelatedField,
SerializerMethodField,
ValidationError,
)
from .models import (
Category,
Motion,
MotionLog,
MotionPoll,
MotionVersion,
State,
Workflow,
)
def validate_workflow_field(value):
"""
Validator to ensure that the workflow with the given id exists.
"""
if not Workflow.objects.filter(pk=value).exists():
raise ValidationError(_('Workflow %(pk)d does not exist.') % {'pk': value})
class CategorySerializer(ModelSerializer):
"""
Serializer for motion.models.Category objects.
"""
class Meta:
model = Category
fields = ('id', 'name', 'prefix',)
class StateSerializer(ModelSerializer):
"""
Serializer for motion.models.State objects.
"""
class Meta:
model = State
fields = (
'id',
'name',
'action_word',
'css_class',
'required_permission_to_see',
'allow_support',
'allow_create_poll',
'allow_submitter_edit',
'versioning',
'leave_old_version_active',
'dont_set_identifier',
'next_states',
'workflow')
class WorkflowSerializer(ModelSerializer):
"""
Serializer for motion.models.Workflow objects.
"""
states = StateSerializer(many=True, read_only=True)
first_state = PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Workflow
fields = ('id', 'name', 'states', 'first_state',)
class MotionLogSerializer(ModelSerializer):
"""
Serializer for motion.models.MotionLog objects.
"""
message = SerializerMethodField()
class Meta:
model = MotionLog
fields = ('message_list', 'person', 'time', 'message',)
def get_message(self, obj):
"""
Concats the message parts to one string. Useful for smart template code.
"""
return str(obj)
class MotionPollSerializer(ModelSerializer):
"""
Serializer for motion.models.MotionPoll objects.
"""
yes = SerializerMethodField()
no = SerializerMethodField()
abstain = SerializerMethodField()
votes = DictField(
child=IntegerField(min_value=-2),
write_only=True)
class Meta:
model = MotionPoll
fields = (
'id',
'motion',
'yes',
'no',
'abstain',
'votesvalid',
'votesinvalid',
'votescast',
'votes',)
def get_yes(self, obj):
try:
result = obj.get_votes().get(value='Yes').weight
except obj.get_vote_class().DoesNotExist:
result = None
return result
def get_no(self, obj):
try:
result = obj.get_votes().get(value='No').weight
except obj.get_vote_class().DoesNotExist:
result = None
return result
def get_abstain(self, obj):
try:
result = obj.get_votes().get(value='Abstain').weight
except obj.get_vote_class().DoesNotExist:
result = None
return result
@transaction.atomic
def update(self, instance, validated_data):
"""
Customized update method for polls. To update votes use the write
only field 'votes'.
Example data:
"votes": {"Yes": 10, "No": 4, "Abstain": -2}
"""
# Update votes.
votes = validated_data.get('votes')
if votes:
if len(votes) != 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.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(instance.get_options().get(), votes)
# Update remaining writeable fields.
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 MotionVersionSerializer(ModelSerializer):
"""
Serializer for motion.models.MotionVersion objects.
"""
class Meta:
model = MotionVersion
fields = (
'id',
'version_number',
'creation_time',
'title',
'text',
'reason',)
class MotionSerializer(ModelSerializer):
"""
Serializer for motion.models.Motion objects.
"""
active_version = PrimaryKeyRelatedField(read_only=True)
log_messages = MotionLogSerializer(many=True, read_only=True)
polls = MotionPollSerializer(many=True, read_only=True)
reason = CharField(allow_blank=True, required=False, write_only=True)
text = CharField(write_only=True)
title = CharField(max_length=255, write_only=True)
versions = MotionVersionSerializer(many=True, read_only=True)
workflow_id = IntegerField(
min_value=1,
required=False,
validators=[validate_workflow_field],
write_only=True)
class Meta:
model = Motion
fields = (
'id',
'identifier',
'title',
'text',
'reason',
'versions',
'active_version',
'parent',
'category',
'submitters',
'supporters',
'state',
'workflow_id',
'tags',
'attachments',
'polls',
'agenda_item_id',
'log_messages',)
read_only_fields = ('parent', 'state') # Some other fields are also read_only. See definitions above.
@transaction.atomic
def create(self, validated_data):
"""
Customized method to create a new motion from some data.
"""
motion = Motion()
motion.title = validated_data['title']
motion.text = validated_data['text']
motion.reason = validated_data.get('reason', '')
motion.identifier = validated_data.get('identifier')
motion.category = validated_data.get('category')
motion.reset_state(validated_data.get('workflow_id'))
motion.save()
if validated_data.get('submitters'):
motion.submitters.add(*validated_data['submitters'])
else:
motion.submitters.add(validated_data['request_user'])
motion.supporters.add(*validated_data.get('supporters', []))
motion.attachments.add(*validated_data.get('attachments', []))
motion.tags.add(*validated_data.get('tags', []))
return motion
@transaction.atomic
def update(self, motion, validated_data):
"""
Customized method to update a motion.
"""
# Identifier and category.
for key in ('identifier', 'category'):
if key in validated_data.keys():
setattr(motion, key, validated_data[key])
# Workflow.
workflow_id = validated_data.get('workflow_id')
if workflow_id is not None and workflow_id != motion.workflow:
motion.reset_state(workflow_id)
# Decide if a new version is saved to the database.
if (motion.state.versioning and
not validated_data.get('disable_versioning', False)): # TODO
version = motion.get_new_version()
else:
version = motion.get_last_version()
# Title, text, reason.
for key in ('title', 'text', 'reason'):
if key in validated_data.keys():
setattr(version, key, validated_data[key])
motion.save(use_version=version)
# Submitters, supporters, attachments and tags
for key in ('submitters', 'supporters', 'attachments', 'tags'):
if key in validated_data.keys():
attr = getattr(motion, key)
attr.clear()
attr.add(*validated_data[key])
return motion