2018-08-23 21:26:24 +02:00
|
|
|
from typing import Dict, Optional
|
2017-08-24 12:26:55 +02:00
|
|
|
|
2015-04-30 19:13:28 +02:00
|
|
|
from django.db import transaction
|
|
|
|
from django.utils.translation import ugettext as _
|
|
|
|
|
2017-04-28 22:10:18 +02:00
|
|
|
from ..poll.serializers import default_votes_validator
|
2018-08-31 15:33:41 +02:00
|
|
|
from ..utils.auth import get_group_model
|
2018-10-01 15:36:16 +02:00
|
|
|
from ..utils.autoupdate import inform_changed_data
|
2017-04-28 22:10:18 +02:00
|
|
|
from ..utils.rest_api import (
|
2015-04-30 19:13:28 +02:00
|
|
|
CharField,
|
2018-08-22 17:34:16 +02:00
|
|
|
DecimalField,
|
2015-07-22 15:23:57 +02:00
|
|
|
DictField,
|
2016-07-29 23:33:47 +02:00
|
|
|
Field,
|
2018-08-31 15:33:41 +02:00
|
|
|
IdPrimaryKeyRelatedField,
|
2015-04-30 19:13:28 +02:00
|
|
|
IntegerField,
|
|
|
|
ModelSerializer,
|
2015-10-21 21:13:45 +02:00
|
|
|
SerializerMethodField,
|
2015-06-16 10:37:23 +02:00
|
|
|
ValidationError,
|
|
|
|
)
|
2017-04-28 22:10:18 +02:00
|
|
|
from ..utils.validate import validate_html
|
2015-01-24 16:35:50 +01:00
|
|
|
from .models import (
|
|
|
|
Category,
|
|
|
|
Motion,
|
2016-10-01 20:42:44 +02:00
|
|
|
MotionBlock,
|
2016-09-10 18:49:38 +02:00
|
|
|
MotionChangeRecommendation,
|
2018-08-31 15:33:41 +02:00
|
|
|
MotionComment,
|
|
|
|
MotionCommentSection,
|
2015-01-24 16:35:50 +01:00
|
|
|
MotionLog,
|
|
|
|
MotionPoll,
|
|
|
|
State,
|
2018-09-24 10:28:31 +02:00
|
|
|
StatuteParagraph,
|
2018-06-12 14:17:02 +02:00
|
|
|
Submitter,
|
2015-06-16 10:37:23 +02:00
|
|
|
Workflow,
|
|
|
|
)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
|
2015-04-30 19:13:28 +02:00
|
|
|
def validate_workflow_field(value):
|
|
|
|
"""
|
|
|
|
Validator to ensure that the workflow with the given id exists.
|
|
|
|
"""
|
|
|
|
if not Workflow.objects.filter(pk=value).exists():
|
2016-02-06 00:02:22 +01:00
|
|
|
raise ValidationError({'detail': _('Workflow %(pk)d does not exist.') % {'pk': value}})
|
2015-04-30 19:13:28 +02:00
|
|
|
|
|
|
|
|
2018-09-24 10:28:31 +02:00
|
|
|
class StatuteParagraphSerializer(ModelSerializer):
|
|
|
|
"""
|
|
|
|
Serializer for motion.models.StatuteParagraph objects.
|
|
|
|
"""
|
|
|
|
class Meta:
|
|
|
|
model = StatuteParagraph
|
|
|
|
fields = ('id', 'title', 'text', 'weight')
|
|
|
|
|
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class CategorySerializer(ModelSerializer):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
|
|
|
Serializer for motion.models.Category objects.
|
|
|
|
"""
|
|
|
|
class Meta:
|
|
|
|
model = Category
|
2015-02-04 00:08:38 +01:00
|
|
|
fields = ('id', 'name', 'prefix',)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
|
2016-10-01 20:42:44 +02:00
|
|
|
class MotionBlockSerializer(ModelSerializer):
|
|
|
|
"""
|
|
|
|
Serializer for motion.models.Category objects.
|
|
|
|
"""
|
2018-08-15 11:15:54 +02:00
|
|
|
agenda_type = IntegerField(write_only=True, required=False, min_value=1, max_value=3)
|
2018-01-20 09:54:46 +01:00
|
|
|
agenda_parent_id = IntegerField(write_only=True, required=False, min_value=1)
|
|
|
|
|
2016-10-01 20:42:44 +02:00
|
|
|
class Meta:
|
|
|
|
model = MotionBlock
|
2018-01-20 09:54:46 +01:00
|
|
|
fields = ('id', 'title', 'agenda_item_id', 'agenda_type', 'agenda_parent_id',)
|
|
|
|
|
|
|
|
def create(self, validated_data):
|
|
|
|
"""
|
|
|
|
Customized create method. Set information about related agenda item
|
|
|
|
into agenda_item_update_information container.
|
|
|
|
"""
|
|
|
|
agenda_type = validated_data.pop('agenda_type', None)
|
|
|
|
agenda_parent_id = validated_data.pop('agenda_parent_id', None)
|
|
|
|
motion_block = MotionBlock(**validated_data)
|
|
|
|
motion_block.agenda_item_update_information['type'] = agenda_type
|
|
|
|
motion_block.agenda_item_update_information['parent_id'] = agenda_parent_id
|
|
|
|
motion_block.save()
|
|
|
|
return motion_block
|
2016-10-01 20:42:44 +02:00
|
|
|
|
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class StateSerializer(ModelSerializer):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
|
|
|
Serializer for motion.models.State objects.
|
|
|
|
"""
|
|
|
|
class Meta:
|
|
|
|
model = State
|
|
|
|
fields = (
|
|
|
|
'id',
|
|
|
|
'name',
|
2016-09-03 21:43:11 +02:00
|
|
|
'recommendation_label',
|
2015-11-03 21:38:53 +01:00
|
|
|
'css_class',
|
2015-01-24 16:35:50 +01:00
|
|
|
'required_permission_to_see',
|
|
|
|
'allow_support',
|
|
|
|
'allow_create_poll',
|
|
|
|
'allow_submitter_edit',
|
|
|
|
'dont_set_identifier',
|
2016-10-27 14:01:12 +02:00
|
|
|
'show_state_extension_field',
|
2018-11-04 11:11:48 +01:00
|
|
|
'merge_amendment_into_final',
|
2016-10-27 14:01:12 +02:00
|
|
|
'show_recommendation_extension_field',
|
2015-11-03 10:03:44 +01:00
|
|
|
'next_states',
|
|
|
|
'workflow')
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class WorkflowSerializer(ModelSerializer):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
|
|
|
Serializer for motion.models.Workflow objects.
|
|
|
|
"""
|
2015-11-03 10:03:44 +01:00
|
|
|
states = StateSerializer(many=True, read_only=True)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Workflow
|
2015-11-03 10:03:44 +01:00
|
|
|
fields = ('id', 'name', 'states', 'first_state',)
|
2018-07-16 09:37:53 +02:00
|
|
|
read_only_fields = ('first_state',)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
2018-06-26 15:59:05 +02:00
|
|
|
@transaction.atomic
|
|
|
|
def create(self, validated_data):
|
|
|
|
"""
|
|
|
|
Customized create method. Creating a new workflow does always create a
|
|
|
|
new state which is used as first state.
|
|
|
|
"""
|
|
|
|
workflow = super().create(validated_data)
|
|
|
|
first_state = State.objects.create(
|
|
|
|
name='new',
|
|
|
|
workflow=workflow,
|
|
|
|
allow_create_poll=True,
|
|
|
|
allow_support=True,
|
|
|
|
allow_submitter_edit=True
|
|
|
|
)
|
|
|
|
workflow.first_state = first_state
|
|
|
|
workflow.save()
|
|
|
|
return workflow
|
|
|
|
|
2015-01-24 16:35:50 +01:00
|
|
|
|
2018-06-12 13:43:28 +02:00
|
|
|
class AmendmentParagraphsJSONSerializerField(Field):
|
|
|
|
"""
|
|
|
|
Serializer for motions's amendment_paragraphs JSONField.
|
|
|
|
"""
|
|
|
|
def to_representation(self, obj):
|
|
|
|
"""
|
|
|
|
Returns the value of the field.
|
|
|
|
"""
|
|
|
|
return obj
|
|
|
|
|
|
|
|
def to_internal_value(self, data):
|
|
|
|
"""
|
|
|
|
Checks that data is a list of strings.
|
|
|
|
"""
|
|
|
|
if type(data) is not list:
|
|
|
|
raise ValidationError({'detail': 'Data must be a list.'})
|
|
|
|
for paragraph in data:
|
|
|
|
if type(paragraph) is not str and paragraph is not None:
|
|
|
|
raise ValidationError({'detail': 'Paragraph must be either a string or null/None.'})
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class MotionLogSerializer(ModelSerializer):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
|
|
|
Serializer for motion.models.MotionLog objects.
|
|
|
|
"""
|
2015-11-03 21:38:53 +01:00
|
|
|
message = SerializerMethodField()
|
|
|
|
|
2015-01-24 16:35:50 +01:00
|
|
|
class Meta:
|
|
|
|
model = MotionLog
|
2015-11-03 21:38:53 +01:00
|
|
|
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)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class MotionPollSerializer(ModelSerializer):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
|
|
|
Serializer for motion.models.MotionPoll objects.
|
|
|
|
"""
|
2015-10-21 21:13:45 +02:00
|
|
|
yes = SerializerMethodField()
|
|
|
|
no = SerializerMethodField()
|
|
|
|
abstain = SerializerMethodField()
|
2015-07-22 15:23:57 +02:00
|
|
|
votes = DictField(
|
2018-08-22 17:34:16 +02:00
|
|
|
child=DecimalField(max_digits=15, decimal_places=6, min_value=-2, allow_null=True),
|
2015-07-22 15:23:57 +02:00
|
|
|
write_only=True)
|
2016-01-14 22:43:49 +01:00
|
|
|
has_votes = SerializerMethodField()
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = MotionPoll
|
|
|
|
fields = (
|
2015-07-22 15:23:57 +02:00
|
|
|
'id',
|
2015-10-13 21:23:21 +02:00
|
|
|
'motion',
|
2015-10-21 21:13:45 +02:00
|
|
|
'yes',
|
|
|
|
'no',
|
|
|
|
'abstain',
|
2015-01-24 16:35:50 +01:00
|
|
|
'votesvalid',
|
|
|
|
'votesinvalid',
|
2015-07-22 15:23:57 +02:00
|
|
|
'votescast',
|
2016-01-14 22:43:49 +01:00
|
|
|
'votes',
|
|
|
|
'has_votes')
|
2016-02-09 21:04:29 +01:00
|
|
|
validators = (default_votes_validator,)
|
2015-10-21 21:13:45 +02:00
|
|
|
|
2016-02-27 20:49:28 +01:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
# The following dictionary is just a cache for several votes.
|
2018-08-22 22:00:08 +02:00
|
|
|
self._votes_dicts: Dict[int, Dict[int, int]] = {}
|
2016-02-27 20:49:28 +01:00
|
|
|
return super().__init__(*args, **kwargs)
|
|
|
|
|
2015-10-21 21:13:45 +02:00
|
|
|
def get_yes(self, obj):
|
2015-10-21 22:24:11 +02:00
|
|
|
try:
|
2018-08-23 21:26:24 +02:00
|
|
|
result: Optional[str] = str(self.get_votes_dict(obj)['Yes'])
|
2016-02-24 10:27:42 +01:00
|
|
|
except KeyError:
|
2015-10-21 22:24:11 +02:00
|
|
|
result = None
|
|
|
|
return result
|
2015-10-21 21:13:45 +02:00
|
|
|
|
|
|
|
def get_no(self, obj):
|
2015-10-21 22:24:11 +02:00
|
|
|
try:
|
2018-08-23 21:26:24 +02:00
|
|
|
result: Optional[str] = str(self.get_votes_dict(obj)['No'])
|
2016-02-24 10:27:42 +01:00
|
|
|
except KeyError:
|
2015-10-21 22:24:11 +02:00
|
|
|
result = None
|
|
|
|
return result
|
2015-10-21 21:13:45 +02:00
|
|
|
|
|
|
|
def get_abstain(self, obj):
|
2015-10-21 22:24:11 +02:00
|
|
|
try:
|
2018-08-23 21:26:24 +02:00
|
|
|
result: Optional[str] = str(self.get_votes_dict(obj)['Abstain'])
|
2016-02-24 10:27:42 +01:00
|
|
|
except KeyError:
|
2015-10-21 22:24:11 +02:00
|
|
|
result = None
|
|
|
|
return result
|
2015-07-22 15:23:57 +02:00
|
|
|
|
2016-02-24 10:27:42 +01:00
|
|
|
def get_votes_dict(self, obj):
|
|
|
|
try:
|
2016-02-27 20:49:28 +01:00
|
|
|
votes_dict = self._votes_dicts[obj.pk]
|
|
|
|
except KeyError:
|
|
|
|
votes_dict = self._votes_dicts[obj.pk] = {}
|
2016-02-24 10:27:42 +01:00
|
|
|
for vote in obj.get_votes():
|
|
|
|
votes_dict[vote.value] = vote.weight
|
|
|
|
return votes_dict
|
|
|
|
|
2016-01-14 22:43:49 +01:00
|
|
|
def get_has_votes(self, obj):
|
|
|
|
"""
|
|
|
|
Returns True if this poll has some votes.
|
|
|
|
"""
|
|
|
|
return obj.has_votes()
|
|
|
|
|
2015-07-22 15:23:57 +02:00
|
|
|
@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})
|
2016-10-12 11:23:53 +02:00
|
|
|
instance.set_vote_objects_with_values(instance.get_options().get(), votes, skip_autoupdate=True)
|
2015-07-22 15:23:57 +02:00
|
|
|
|
|
|
|
# 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
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
|
2016-09-10 18:49:38 +02:00
|
|
|
class MotionChangeRecommendationSerializer(ModelSerializer):
|
|
|
|
"""
|
|
|
|
Serializer for motion.models.MotionChangeRecommendation objects.
|
|
|
|
"""
|
|
|
|
class Meta:
|
|
|
|
model = MotionChangeRecommendation
|
|
|
|
fields = (
|
|
|
|
'id',
|
2018-08-31 15:33:41 +02:00
|
|
|
'motion',
|
2016-11-13 13:19:16 +01:00
|
|
|
'rejected',
|
2018-10-25 15:11:38 +02:00
|
|
|
'internal',
|
2016-11-13 16:42:56 +01:00
|
|
|
'type',
|
2017-11-17 12:10:46 +01:00
|
|
|
'other_description',
|
2016-09-10 18:49:38 +02:00
|
|
|
'line_from',
|
|
|
|
'line_to',
|
|
|
|
'text',
|
|
|
|
'creation_time',)
|
|
|
|
|
2018-03-07 16:36:30 +01:00
|
|
|
def is_title_cr(self, data):
|
|
|
|
return int(data['line_from']) == 0 and int(data['line_to']) == 0
|
|
|
|
|
2017-01-20 11:34:05 +01:00
|
|
|
def validate(self, data):
|
2018-03-07 16:36:30 +01:00
|
|
|
# Change recommendations for titles are stored as plain-text, thus they don't need to be html-escaped
|
|
|
|
if 'text' in data and not self.is_title_cr(data):
|
2017-03-28 08:27:54 +02:00
|
|
|
data['text'] = validate_html(data['text'])
|
2017-01-20 11:34:05 +01:00
|
|
|
return data
|
|
|
|
|
2016-09-10 18:49:38 +02:00
|
|
|
|
2018-08-31 15:33:41 +02:00
|
|
|
class MotionCommentSectionSerializer(ModelSerializer):
|
|
|
|
"""
|
|
|
|
Serializer for motion.models.MotionCommentSection objects.
|
|
|
|
"""
|
|
|
|
read_groups = IdPrimaryKeyRelatedField(
|
|
|
|
many=True,
|
|
|
|
required=False,
|
|
|
|
queryset=get_group_model().objects.all())
|
|
|
|
|
|
|
|
write_groups = IdPrimaryKeyRelatedField(
|
|
|
|
many=True,
|
|
|
|
required=False,
|
|
|
|
queryset=get_group_model().objects.all())
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = MotionCommentSection
|
|
|
|
fields = (
|
|
|
|
'id',
|
|
|
|
'name',
|
|
|
|
'read_groups',
|
|
|
|
'write_groups',)
|
|
|
|
|
2018-10-01 15:36:16 +02:00
|
|
|
def create(self, validated_data):
|
|
|
|
""" Call inform_changed_data on creation, so the cache includes the groups. """
|
|
|
|
section = super().create(validated_data)
|
|
|
|
inform_changed_data(section)
|
|
|
|
return section
|
|
|
|
|
2018-08-31 15:33:41 +02:00
|
|
|
|
|
|
|
class MotionCommentSerializer(ModelSerializer):
|
|
|
|
"""
|
|
|
|
Serializer for motion.models.MotionComment objects.
|
|
|
|
"""
|
|
|
|
read_groups_id = SerializerMethodField()
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = MotionComment
|
|
|
|
fields = (
|
|
|
|
'id',
|
|
|
|
'comment',
|
|
|
|
'section',
|
|
|
|
'read_groups_id',)
|
|
|
|
|
|
|
|
def get_read_groups_id(self, comment):
|
|
|
|
return [group.id for group in comment.section.read_groups.all()]
|
|
|
|
|
|
|
|
|
2018-06-12 14:17:02 +02:00
|
|
|
class SubmitterSerializer(ModelSerializer):
|
|
|
|
"""
|
|
|
|
Serializer for motion.models.Submitter objects.
|
|
|
|
"""
|
|
|
|
class Meta:
|
|
|
|
model = Submitter
|
|
|
|
fields = (
|
|
|
|
'id',
|
|
|
|
'user',
|
|
|
|
'motion',
|
|
|
|
'weight',
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2015-02-12 18:48:14 +01:00
|
|
|
class MotionSerializer(ModelSerializer):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
|
|
|
Serializer for motion.models.Motion objects.
|
|
|
|
"""
|
2018-08-31 15:33:41 +02:00
|
|
|
comments = MotionCommentSerializer(many=True, read_only=True)
|
2015-01-24 16:35:50 +01:00
|
|
|
log_messages = MotionLogSerializer(many=True, read_only=True)
|
2015-04-30 19:13:28 +02:00
|
|
|
polls = MotionPollSerializer(many=True, read_only=True)
|
2018-08-31 15:33:41 +02:00
|
|
|
modified_final_version = CharField(allow_blank=True, required=False)
|
|
|
|
reason = CharField(allow_blank=True, required=False)
|
2016-12-09 18:00:45 +01:00
|
|
|
state_required_permission_to_see = SerializerMethodField()
|
2018-08-31 15:33:41 +02:00
|
|
|
text = CharField(allow_blank=True)
|
|
|
|
title = CharField(max_length=255)
|
|
|
|
amendment_paragraphs = AmendmentParagraphsJSONSerializerField(required=False)
|
2015-11-03 10:03:44 +01:00
|
|
|
workflow_id = IntegerField(
|
|
|
|
min_value=1,
|
|
|
|
required=False,
|
2018-09-06 13:39:16 +02:00
|
|
|
validators=[validate_workflow_field])
|
2018-08-15 11:15:54 +02:00
|
|
|
agenda_type = IntegerField(write_only=True, required=False, min_value=1, max_value=3)
|
2018-01-20 09:54:46 +01:00
|
|
|
agenda_parent_id = IntegerField(write_only=True, required=False, min_value=1)
|
2018-06-12 14:17:02 +02:00
|
|
|
submitters = SubmitterSerializer(many=True, read_only=True)
|
2015-01-24 16:35:50 +01:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Motion
|
|
|
|
fields = (
|
2015-02-04 00:08:38 +01:00
|
|
|
'id',
|
2015-01-24 16:35:50 +01:00
|
|
|
'identifier',
|
2015-04-30 19:13:28 +02:00
|
|
|
'title',
|
|
|
|
'text',
|
2018-06-12 13:43:28 +02:00
|
|
|
'amendment_paragraphs',
|
2018-07-13 10:08:18 +02:00
|
|
|
'modified_final_version',
|
2015-04-30 19:13:28 +02:00
|
|
|
'reason',
|
|
|
|
'parent',
|
|
|
|
'category',
|
2018-08-31 15:33:41 +02:00
|
|
|
'comments',
|
2016-10-01 20:42:44 +02:00
|
|
|
'motion_block',
|
2016-07-13 14:45:40 +02:00
|
|
|
'origin',
|
2015-04-30 19:13:28 +02:00
|
|
|
'submitters',
|
|
|
|
'supporters',
|
2015-01-24 16:35:50 +01:00
|
|
|
'state',
|
2018-08-31 15:33:41 +02:00
|
|
|
'state_extension',
|
2016-12-09 18:00:45 +01:00
|
|
|
'state_required_permission_to_see',
|
2018-10-28 11:06:36 +01:00
|
|
|
'statute_paragraph',
|
2015-11-03 10:03:44 +01:00
|
|
|
'workflow_id',
|
2016-09-03 21:43:11 +02:00
|
|
|
'recommendation',
|
2018-08-31 15:33:41 +02:00
|
|
|
'recommendation_extension',
|
2015-04-30 19:13:28 +02:00
|
|
|
'tags',
|
2015-01-24 16:35:50 +01:00
|
|
|
'attachments',
|
|
|
|
'polls',
|
2015-10-24 19:02:43 +02:00
|
|
|
'agenda_item_id',
|
2018-01-20 09:54:46 +01:00
|
|
|
'agenda_type',
|
|
|
|
'agenda_parent_id',
|
2018-09-24 10:28:31 +02:00
|
|
|
'log_messages',
|
|
|
|
'sort_parent',
|
|
|
|
'weight',)
|
2016-09-03 21:43:11 +02:00
|
|
|
read_only_fields = ('state', 'recommendation',) # Some other fields are also read_only. See definitions above.
|
2015-01-24 16:35:50 +01:00
|
|
|
|
2017-01-20 11:34:05 +01:00
|
|
|
def validate(self, data):
|
2017-03-28 08:27:54 +02:00
|
|
|
if 'text'in data:
|
|
|
|
data['text'] = validate_html(data['text'])
|
2018-06-12 13:43:28 +02:00
|
|
|
|
2018-07-13 10:08:18 +02:00
|
|
|
if 'modified_final_version' in data:
|
|
|
|
data['modified_final_version'] = validate_html(data['modified_final_version'])
|
|
|
|
|
2017-03-28 08:27:54 +02:00
|
|
|
if 'reason' in data:
|
|
|
|
data['reason'] = validate_html(data['reason'])
|
2018-06-12 13:43:28 +02:00
|
|
|
|
|
|
|
if 'amendment_paragraphs' in data:
|
|
|
|
data['amendment_paragraphs'] = list(map(lambda entry: validate_html(entry) if type(entry) is str else None,
|
|
|
|
data['amendment_paragraphs']))
|
|
|
|
data['text'] = ''
|
|
|
|
else:
|
|
|
|
if 'text' in data and len(data['text']) == 0:
|
|
|
|
raise ValidationError({
|
|
|
|
'detail': _('This field may not be blank.')
|
|
|
|
})
|
|
|
|
|
2017-01-20 11:34:05 +01:00
|
|
|
return data
|
|
|
|
|
2015-04-30 19:13:28 +02:00
|
|
|
@transaction.atomic
|
|
|
|
def create(self, validated_data):
|
|
|
|
"""
|
|
|
|
Customized method to create a new motion from some data.
|
2018-01-20 09:54:46 +01:00
|
|
|
|
|
|
|
Set also information about related agenda item into
|
|
|
|
agenda_item_update_information container.
|
2015-04-30 19:13:28 +02:00
|
|
|
"""
|
|
|
|
motion = Motion()
|
|
|
|
motion.title = validated_data['title']
|
|
|
|
motion.text = validated_data['text']
|
2018-06-12 13:43:28 +02:00
|
|
|
motion.amendment_paragraphs = validated_data.get('amendment_paragraphs')
|
2018-07-13 10:08:18 +02:00
|
|
|
motion.modified_final_version = validated_data.get('modified_final_version', '')
|
2015-04-30 19:13:28 +02:00
|
|
|
motion.reason = validated_data.get('reason', '')
|
|
|
|
motion.identifier = validated_data.get('identifier')
|
|
|
|
motion.category = validated_data.get('category')
|
2016-10-01 20:42:44 +02:00
|
|
|
motion.motion_block = validated_data.get('motion_block')
|
2016-07-13 14:45:40 +02:00
|
|
|
motion.origin = validated_data.get('origin', '')
|
2016-08-19 21:03:14 +02:00
|
|
|
motion.parent = validated_data.get('parent')
|
2018-10-28 11:06:36 +01:00
|
|
|
motion.statute_paragraph = validated_data.get('statute_paragraph')
|
2015-11-03 10:03:44 +01:00
|
|
|
motion.reset_state(validated_data.get('workflow_id'))
|
2018-01-20 09:54:46 +01:00
|
|
|
motion.agenda_item_update_information['type'] = validated_data.get('agenda_type')
|
|
|
|
motion.agenda_item_update_information['parent_id'] = validated_data.get('agenda_parent_id')
|
2015-04-30 19:13:28 +02:00
|
|
|
motion.save()
|
2015-07-06 09:19:42 +02:00
|
|
|
motion.supporters.add(*validated_data.get('supporters', []))
|
|
|
|
motion.attachments.add(*validated_data.get('attachments', []))
|
|
|
|
motion.tags.add(*validated_data.get('tags', []))
|
2015-04-30 19:13:28 +02:00
|
|
|
return motion
|
|
|
|
|
|
|
|
@transaction.atomic
|
|
|
|
def update(self, motion, validated_data):
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
2015-04-30 19:13:28 +02:00
|
|
|
Customized method to update a motion.
|
2015-01-24 16:35:50 +01:00
|
|
|
"""
|
2018-08-31 15:33:41 +02:00
|
|
|
workflow_id = None
|
|
|
|
if 'workflow_id' in validated_data:
|
|
|
|
workflow_id = validated_data.pop('workflow_id')
|
|
|
|
|
|
|
|
result = super().update(motion, validated_data)
|
2015-04-30 19:13:28 +02:00
|
|
|
|
2018-09-06 13:39:16 +02:00
|
|
|
if workflow_id is not None and workflow_id != motion.workflow_id:
|
2015-11-03 10:03:44 +01:00
|
|
|
motion.reset_state(workflow_id)
|
2018-08-31 15:33:41 +02:00
|
|
|
motion.save()
|
2015-04-30 19:13:28 +02:00
|
|
|
|
2018-08-31 15:33:41 +02:00
|
|
|
return result
|
2016-12-09 18:00:45 +01:00
|
|
|
|
|
|
|
def get_state_required_permission_to_see(self, motion):
|
|
|
|
"""
|
|
|
|
Returns the permission (as string) that is required for non
|
|
|
|
managers that are not submitters to see this motion in this state.
|
|
|
|
|
|
|
|
Hint: Most states have and empty string here so this restriction is
|
|
|
|
disabled.
|
|
|
|
"""
|
|
|
|
return motion.state.required_permission_to_see
|