class PublicSignalCreateSerializer(SignalValidationMixin, serializers.ModelSerializer): """ This serializer allows anonymous users to report `signals.Signals`. Note: this is only used in the creation of new Signal instances, not to create the response body after a succesfull POST. """ location = _NestedLocationModelSerializer() reporter = _NestedReporterModelSerializer() category = _NestedCategoryModelSerializer(source='category_assignment') extra_properties = SignalExtraPropertiesField( required=False, allow_null=True, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) incident_date_start = serializers.DateTimeField() class Meta(object): model = Signal fields = ( 'text', 'text_extra', 'location', 'category', 'reporter', 'incident_date_start', 'incident_date_end', 'extra_properties', ) def validate(self, data): """Make sure any extra data is rejected""" if hasattr(self, 'initial_data'): present_keys = set(self.initial_data) allowed_keys = set(self.fields) if present_keys - allowed_keys: raise ValidationError('Extra properties present: {}'.format( ', '.join(present_keys - allowed_keys))) return super(PublicSignalCreateSerializer, self).validate(data) def create(self, validated_data): location_data = validated_data.pop('location') reporter_data = validated_data.pop('reporter') category_assignment_data = validated_data.pop('category_assignment') status_data = {"state": workflow.GEMELD} signal = Signal.actions.create_initial(validated_data, location_data, status_data, category_assignment_data, reporter_data) return signal
class PublicSignalCreateSerializer(serializers.ModelSerializer): """ This serializer allows anonymous users to report `signals.Signals`. Note: this is only used in the creation of new Signal instances, not to create the response body after a succesfull POST. """ status = _NestedStatusModelSerializer(required=False, ) location = _NestedLocationModelSerializer() reporter = _NestedReporterModelSerializer() category = _NestedCategoryModelSerializer(source='category_assignment') country = CountrySerializer(required=False) city = CitySerializer(required=False) city_object = CityObjectSerializer(many=True, required=False) updates = SignalPlanUpdateSerializer(many=True, required=False) extra_properties = SignalExtraPropertiesField( required=False, allow_null=True, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) incident_date_start = serializers.DateTimeField() #id_mapping = IDMappingSerializer(required=False) class Meta(object): model = Signal fields = ( 'text', 'text_extra', 'signal_id', 'location', 'category', 'reporter', 'incident_date_start', 'incident_date_end', 'status', 'source', 'extra_properties', 'country', 'city', 'city_object', 'webform_kenmark', 'mb_report_id', 'facilitator_report_id', 'report_days', 'forman_emp_name', 'urgency', 'plan_time', 'updates', 'updated_by', ) def validate(self, data): """Make sure any extra data is rejected""" if hasattr(self, 'initial_data'): present_keys = set(self.initial_data) allowed_keys = set(self.fields) if present_keys - allowed_keys: raise ValidationError('Extra properties present: {}'.format( ', '.join(present_keys - allowed_keys))) return data def create(self, validated_data): print("Validated data : ", validated_data) location_data = validated_data.pop('location') reporter_data = validated_data.pop('reporter') category_assignment_data = validated_data.pop('category_assignment') country_data = validated_data.pop('country', None) city_data = validated_data.pop('city', None) city_object_data = validated_data.pop('city_object', None) status_data = validated_data.pop('status', None) if not status_data: status_data = {"state": workflow.GEMELD} signal = Signal.actions.create_initial(validated_data, location_data, status_data, category_assignment_data, reporter_data, country_data, city_data, city_object_data) return signal
class PrivateSignalSerializerDetail(HALSerializer, AddressValidationMixin): """ This serializer is used for the detail endpoint and when updating the instance """ serializer_url_field = PrivateSignalLinksFieldWithArchives _display = DisplayField() country = CountrySerializer(required=False, permission_classes=(SIAPermissions, )) city = CitySerializer(required=False, permission_classes=(SIAPermissions, )) city_object = CityObjectSerializer(many=True, required=False) location = _NestedLocationModelSerializer( required=False, permission_classes=(SIAPermissions, )) status = _NestedStatusModelSerializer( required=False, permission_classes=(SignalChangeStatusPermission, )) category = _NestedCategoryModelSerializer( source='category_assignment', required=False, permission_classes=(SignalChangeCategoryPermission, )) reporter = _NestedReporterModelSerializer( required=False, permission_classes=(SIAPermissions, )) priority = _NestedPriorityModelSerializer( required=False, permission_classes=(SIAPermissions, )) notes = _NestedNoteModelSerializer( many=True, required=False, permission_classes=(SignalCreateNotePermission, )) type = _NestedTypeModelSerializer( required=False, permission_classes=(SIAPermissions, ), source='type_assignment', ) directing_departments = _NestedDepartmentModelSerializer( source='directing_departments_assignment.departments', many=True, required=False, permission_classes=(SIAPermissions, ), ) updates = SignalPlanUpdateSerializer(many=True, required=False) mb_mapping = serializers.SerializerMethodField(required=False) has_attachments = serializers.SerializerMethodField() image_category = ImageCategorySerializer(required=False) extra_properties = SignalExtraPropertiesField( required=False, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) # noqa class Meta: model = Signal fields = ( '_links', '_display', 'category', 'id', 'has_attachments', 'location', 'status', 'reporter', 'priority', 'notes', 'type', 'source', 'text', 'text_extra', 'extra_properties', 'created_at', 'updated_at', 'incident_date_start', 'incident_date_end', 'finished_by', 'directing_departments', 'country', 'city', 'city_object', 'webform_kenmark', 'mb_report_id', 'facilitator_report_id', 'report_days', 'forman_emp_name', 'urgency', 'plan_time', 'updates', 'mb_mapping', 'updated_by', 'image_category', ) read_only_fields = ( 'id', 'has_attachments', ) def get_mb_mapping(self, obj): if IDMapping.objects.filter(seda_signal_id=obj.signal_id).exists(): return IDMappingSerializer( IDMapping.objects.get(seda_signal_id=obj.signal_id)).data return None def get_has_attachments(self, obj): return obj.attachments.exists() def update(self, instance, validated_data): """ Perform update on nested models. Note: - Reporter cannot be updated via the API. - Atomic update (all fail/succeed), django signals on full success (see underlying update_multiple method of actions SignalManager). """ if not instance.is_parent() and validated_data.get( 'directing_departments_assignment') is not None: raise serializers.ValidationError( 'Directing departments can only be set on a parent Signal') user_email = self.context['request'].user.email for _property in [ 'location', 'status', 'category_assignment', 'priority' ]: if _property in validated_data: data = validated_data[_property] data['created_by'] = user_email if 'type_assignment' in validated_data: type_data = validated_data.pop('type_assignment') type_data['created_by'] = user_email validated_data['type'] = type_data if 'notes' in validated_data and validated_data['notes']: note_data = validated_data['notes'][0] note_data['created_by'] = user_email if 'directing_departments_assignment' in validated_data and validated_data[ 'directing_departments_assignment']: validated_data['directing_departments_assignment'][ 'created_by'] = user_email signal = Signal.actions.update_multiple(validated_data, instance) return signal
class PrivateSignalSerializerList(HALSerializer, AddressValidationMixin): """ This serializer is used for the list endpoint and when creating a new instance """ serializer_url_field = PrivateSignalLinksField _display = DisplayField() country = CountrySerializer(required=False, permission_classes=(SIAPermissions, )) city = CitySerializer(required=False, permission_classes=(SIAPermissions, )) city_object = CityObjectSerializer(many=True, required=False) location = _NestedLocationModelSerializer( permission_classes=(SIAPermissions, )) status = _NestedStatusModelSerializer( required=False, permission_classes=(SignalCreateInitialPermission, )) category = _NestedCategoryModelSerializer( source='category_assignment', permission_classes=(SignalCreateInitialPermission, )) reporter = _NestedReporterModelSerializer( permission_classes=(SIAPermissions, )) priority = _NestedPriorityModelSerializer( required=False, permission_classes=(SIAPermissions, )) notes = _NestedNoteModelSerializer( many=True, required=False, permission_classes=(SignalCreateInitialPermission, )) type = _NestedTypeModelSerializer( required=False, permission_classes=(SIAPermissions, ), source='type_assignment', ) updates = SignalPlanUpdateSerializer(many=True, required=False) directing_departments = _NestedDepartmentModelSerializer( source='directing_departments_assignment.departments', many=True, required=False, permission_classes=(SIAPermissions, ), ) has_attachments = serializers.SerializerMethodField() extra_properties = SignalExtraPropertiesField( required=False, allow_null=True, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) class Meta: model = Signal fields = ( '_links', '_display', 'id', 'signal_id', 'source', 'text', 'text_extra', 'status', 'location', 'category', 'reporter', 'priority', 'type', 'created_at', 'updated_at', 'incident_date_start', 'incident_date_end', 'operational_date', 'has_attachments', 'extra_properties', 'notes', 'directing_departments', 'finished_by', 'country', 'city', 'city_object', 'webform_kenmark', 'mb_report_id', 'facilitator_report_id', 'report_days', 'forman_emp_name', 'urgency', 'plan_time', 'updates', 'updated_by', ) read_only_fields = ( 'created_at', 'updated_at', 'has_attachments', ) extra_kwargs = { 'source': { 'validators': [SignalSourceValidator()] }, } def get_has_attachments(self, obj): return obj.attachments.exists() def create(self, validated_data): if validated_data.get('directing_departments_assignment') is not None: raise serializers.ValidationError( 'Directing departments cannot be set on initial creation') if validated_data.get('status') is not None: raise serializers.ValidationError( "Status cannot be set on initial creation") # Set default status logged_in_user = self.context['request'].user INITIAL_STATUS = { 'state': workflow.GEMELD, # see models.py is already default 'text': None, 'user': logged_in_user.email, } # We require location and reporter to be set and to be valid. reporter_data = validated_data.pop('reporter') location_data = validated_data.pop('location') location_data['created_by'] = logged_in_user.email category_assignment_data = validated_data.pop('category_assignment') category_assignment_data['created_by'] = logged_in_user.email # We will use the priority and signal type on the incoming message if present. priority_data = validated_data.pop( 'priority', {'priority': Priority.PRIORITY_NORMAL}) priority_data['created_by'] = logged_in_user.email type_data = validated_data.pop('type_assignment', {}) type_data['created_by'] = logged_in_user.email country_data = validated_data.pop('country', None) city_data = validated_data.pop('city', None) city_object_data = validated_data.pop('city_object', None) signal = Signal.actions.create_initial(validated_data, location_data, INITIAL_STATUS, category_assignment_data, reporter_data, country_data, city_data, city_object_data, priority_data, type_data) return signal
class PrivateSignalSerializerList(SignalValidationMixin, HALSerializer): """ This serializer is used for the list endpoint and when creating a new instance """ serializer_url_field = PrivateSignalLinksField _display = DisplayField() location = _NestedLocationModelSerializer( permission_classes=(SIAPermissions, )) status = _NestedStatusModelSerializer( required=False, permission_classes=(SignalCreateInitialPermission, )) category = _NestedCategoryModelSerializer( source='category_assignment', permission_classes=(SignalCreateInitialPermission, )) reporter = _NestedReporterModelSerializer( permission_classes=(SIAPermissions, )) priority = _NestedPriorityModelSerializer( required=False, permission_classes=(SIAPermissions, )) notes = _NestedNoteModelSerializer( many=True, required=False, permission_classes=(SignalCreateInitialPermission, )) type = _NestedTypeModelSerializer( required=False, permission_classes=(SIAPermissions, ), source='type_assignment', ) directing_departments = _NestedDepartmentModelSerializer( source='directing_departments_assignment.departments', many=True, required=False, permission_classes=(SIAPermissions, ), ) routing_departments = _NestedDepartmentModelSerializer( source='routing_assignment.departments', many=True, required=False, allow_null=True, permission_classes=(SIAPermissions, ), ) has_attachments = serializers.SerializerMethodField() assigned_user_id = serializers.IntegerField( source='user_assignment.user.id', required=False, allow_null=True) extra_properties = SignalExtraPropertiesField( required=False, allow_null=True, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) parent = serializers.PrimaryKeyRelatedField(required=False, read_only=False, write_only=True, queryset=Signal.objects.all()) has_parent = serializers.SerializerMethodField() has_children = serializers.SerializerMethodField() attachments = PrivateSignalAttachmentRelatedField( view_name='private-signals-attachments-detail', many=True, required=False, read_only=False, write_only=True, queryset=Attachment.objects.all()) class Meta: model = Signal list_serializer_class = _SignalListSerializer fields = ('_links', '_display', 'id', 'signal_id', 'source', 'text', 'text_extra', 'status', 'location', 'category', 'reporter', 'priority', 'type', 'created_at', 'updated_at', 'incident_date_start', 'incident_date_end', 'operational_date', 'has_attachments', 'extra_properties', 'notes', 'directing_departments', 'routing_departments', 'attachments', 'parent', 'has_parent', 'has_children', 'assigned_user_id') read_only_fields = ( 'created_at', 'updated_at', 'has_attachments', 'has_parent', 'has_children', ) extra_kwargs = { 'source': { 'validators': [SignalSourceValidator()] }, } def get_has_attachments(self, obj): return obj.attachments.exists() def get_has_parent(self, obj): return obj.parent_id is not None # True is a parent_id is set, False if not def get_has_children(self, obj): return obj.children.exists() def validate(self, attrs): errors = {} if attrs.get('directing_departments_assignment') is not None: errors.update({ 'directing_departments_assignment': ['Directing departments cannot be set on initial creation'] }) if attrs.get('routing_assignment') is not None: errors.update({ 'routing_assignment': [ 'Signal departments relation cannot be set on initial creation' ] }) if attrs.get('status') is not None: errors.update( {'status': ['Status cannot be set on initial creation']}) attachments = attrs.get('attachments') parent = attrs.get('parent') if attachments and parent is None: errors.update({ 'attachments': [ 'Attachments can only be copied when creating a child Signal' ] }) if attachments and parent: attachments_belong_to_parent = all([ parent.pk == attachment._signal_id for attachment in attachments ]) if not attachments_belong_to_parent: errors.update({ 'attachments': ['Attachments can only be copied from the parent Signal'] }) if errors: raise serializers.ValidationError(errors) return super(PrivateSignalSerializerList, self).validate(attrs=attrs) def create(self, validated_data): # Set default status logged_in_user = self.context['request'].user INITIAL_STATUS = { 'state': workflow.GEMELD, # see models.py is already default 'text': None, 'user': logged_in_user.email, } # We require location and reporter to be set and to be valid. reporter_data = validated_data.pop('reporter') location_data = validated_data.pop('location') location_data['created_by'] = logged_in_user.email category_assignment_data = validated_data.pop('category_assignment') category_assignment_data['created_by'] = logged_in_user.email # We will use the priority and signal type on the incoming message if present. priority_data = validated_data.pop( 'priority', {'priority': Priority.PRIORITY_NORMAL}) priority_data['created_by'] = logged_in_user.email type_data = validated_data.pop('type_assignment', {}) type_data['created_by'] = logged_in_user.email attachments = validated_data.pop( 'attachments') if 'attachments' in validated_data else None signal = Signal.actions.create_initial(validated_data, location_data, INITIAL_STATUS, category_assignment_data, reporter_data, priority_data, type_data) if attachments: Signal.actions.copy_attachments(data=attachments, signal=signal) signal.refresh_from_db() return signal
class PrivateSignalSerializerDetail(HALSerializer, AddressValidationMixin): """ This serializer is used for the detail endpoint and when updating the instance """ serializer_url_field = PrivateSignalLinksFieldWithArchives _display = DisplayField() location = _NestedLocationModelSerializer( required=False, permission_classes=(SIAPermissions, )) status = _NestedStatusModelSerializer( required=False, permission_classes=(SignalChangeStatusPermission, )) category = _NestedCategoryModelSerializer( source='category_assignment', required=False, permission_classes=(SignalChangeCategoryPermission, )) reporter = _NestedReporterModelSerializer( required=False, permission_classes=(SIAPermissions, )) priority = _NestedPriorityModelSerializer( required=False, permission_classes=(SIAPermissions, )) notes = _NestedNoteModelSerializer( many=True, required=False, permission_classes=(SignalCreateNotePermission, )) type = _NestedTypeModelSerializer( required=False, permission_classes=(SIAPermissions, ), source='type_assignment', ) directing_departments = _NestedDepartmentModelSerializer( source='directing_departments_assignment.departments', many=True, required=False, permission_classes=(SIAPermissions, ), ) routing_departments = _NestedDepartmentModelSerializer( source='routing_assignment.departments', many=True, required=False, allow_null=True, permission_classes=(SIAPermissions, ), ) has_attachments = serializers.SerializerMethodField() assigned_user_id = serializers.IntegerField( source='user_assignment.user.id', required=False, allow_null=True) extra_properties = SignalExtraPropertiesField( required=False, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) attachments = PrivateSignalAttachmentRelatedField( view_name='private-signals-attachments-detail', many=True, required=False, read_only=True) class Meta: model = Signal fields = ( '_links', '_display', 'category', 'id', 'has_attachments', 'location', 'status', 'reporter', 'priority', 'notes', 'type', 'source', 'text', 'text_extra', 'extra_properties', 'created_at', 'updated_at', 'incident_date_start', 'incident_date_end', 'directing_departments', 'routing_departments', 'attachments', 'assigned_user_id', ) read_only_fields = ( 'id', 'has_attachments', ) def get_has_attachments(self, obj): return obj.attachments.exists() def update(self, instance, validated_data): # noqa """ Perform update on nested models. Note: - Reporter cannot be updated via the API. - Atomic update (all fail/succeed), django signals on full success (see underlying update_multiple method of actions SignalManager). """ if not instance.is_parent() and validated_data.get( 'directing_departments_assignment') is not None: raise serializers.ValidationError( 'Directing departments can only be set on a parent Signal') user_email = self.context['request'].user.email for _property in [ 'location', 'status', 'category_assignment', 'priority' ]: if _property in validated_data: data = validated_data[_property] data['created_by'] = user_email if 'type_assignment' in validated_data: type_data = validated_data.pop('type_assignment') type_data['created_by'] = user_email validated_data['type'] = type_data if 'notes' in validated_data and validated_data['notes']: note_data = validated_data['notes'][0] note_data['created_by'] = user_email if 'directing_departments_assignment' in validated_data and validated_data[ 'directing_departments_assignment']: validated_data['directing_departments_assignment'][ 'created_by'] = user_email if 'routing_assignment' in validated_data and validated_data[ 'routing_assignment']: validated_data['routing_assignment']['created_by'] = user_email if 'user_assignment' in validated_data and validated_data[ 'user_assignment']: validated_data['created_by'] = user_email signal = Signal.actions.update_multiple(validated_data, instance) return signal
class PublicSignalCreateSerializer(serializers.ModelSerializer): """ This serializer allows anonymous users to report `signals.Signals`. """ location = _NestedLocationModelSerializer() reporter = _NestedReporterModelSerializer() status = _NestedStatusModelSerializer(required=False) category = _NestedCategoryModelSerializer(source='category_assignment') priority = _NestedPriorityModelSerializer(required=False, read_only=True) attachments = _NestedAttachmentModelSerializer(many=True, read_only=True) extra_properties = SignalExtraPropertiesField( required=False, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) incident_date_start = serializers.DateTimeField() class Meta(object): model = Signal fields = ( 'id', 'signal_id', 'source', 'text', 'text_extra', 'location', 'category', 'reporter', 'status', 'priority', 'created_at', 'updated_at', 'incident_date_start', 'incident_date_end', 'operational_date', 'image', 'attachments', 'extra_properties', ) read_only_fields = ( 'id', 'signal_id', 'created_at', 'updated_at', 'status', 'image' 'attachments', ) extra_kwargs = { 'id': { 'label': 'ID' }, 'signal_id': { 'label': 'SIGNAL_ID' }, 'source': { 'validators': [SignalSourceValidator()] }, } def create(self, validated_data): if validated_data.get('status') is not None: raise serializers.ValidationError( "Status cannot be set on initial creation") location_data = validated_data.pop('location') reporter_data = validated_data.pop('reporter') category_assignment_data = validated_data.pop('category_assignment') status_data = {"state": workflow.GEMELD} signal = Signal.actions.create_initial(validated_data, location_data, status_data, category_assignment_data, reporter_data) return signal
class PrivateSignalSerializerDetail(HALSerializer, AddressValidationMixin): """ This serializer is used for the detail endpoint and when updating the instance """ serializer_url_field = PrivateSignalLinksFieldWithArchives _display = DisplayField() location = _NestedLocationModelSerializer( required=False, permission_classes=(SIAPermissions, )) status = _NestedStatusModelSerializer( required=False, permission_classes=(SignalChangeStatusPermission, )) category = _NestedCategoryModelSerializer( source='category_assignment', required=False, permission_classes=(SignalChangeCategoryPermission, )) reporter = _NestedReporterModelSerializer( required=False, permission_classes=(SIAPermissions, )) priority = _NestedPriorityModelSerializer( required=False, permission_classes=(SIAPermissions, )) notes = _NestedNoteModelSerializer( many=True, required=False, permission_classes=(SignalCreateNotePermission, )) has_attachments = serializers.SerializerMethodField() extra_properties = SignalExtraPropertiesField( required=False, validators=[ ExtraPropertiesValidator( filename=os.path.join(os.path.dirname(__file__), '..', 'json_schema', 'extra_properties.json')) ]) # noqa class Meta: model = Signal fields = ( '_links', '_display', 'category', 'id', 'has_attachments', 'location', 'status', 'reporter', 'priority', 'notes', 'source', 'text', 'text_extra', 'extra_properties', 'created_at', 'updated_at', 'incident_date_start', 'incident_date_end', ) read_only_fields = ( 'id', 'has_attachments', ) def get_has_attachments(self, obj): return obj.attachments.exists() def update(self, instance, validated_data): """ Perform update on nested models. Note: - Reporter cannot be updated via the API. - Atomic update (all fail/succeed), django signals on full success (see underlying update_multiple method of actions SignalManager). """ user_email = self.context['request'].user.email for _property in [ 'location', 'status', 'category_assignment', 'priority' ]: if _property in validated_data: data = validated_data[_property] data['created_by'] = user_email if 'notes' in validated_data and validated_data['notes']: note_data = validated_data['notes'][0] note_data['created_by'] = user_email signal = Signal.actions.update_multiple(validated_data, instance) return signal