def test(self):

        # Start client as admin
        broker = {
            'HOST': 'localhost',
            'PORT': 1883,
            'KEEPALIVE': 60,
            'CLEAN_SESSION': True
        }

        # Start subscribe client

        broker.update(settings.MQTT)
        broker['CLIENT_ID'] = 'test_mqttclient'

        subscribe_client = SubscribeClient(broker, debug=True)
        self.is_connected(subscribe_client)
        self.is_subscribed(subscribe_client)

        # Start test client

        broker.update(settings.MQTT)
        client_id = 'test_mqtt_subscribe_admin'
        username = broker['USERNAME']
        broker['CLIENT_ID'] = client_id

        test_client = SingletonPublishClient()
        # self.is_connected(test_client)

        # clear cache
        cache_clear()

        # retrieve permissions for user u1
        get_permissions(self.u1)
        get_permissions(self.u1)
        get_permissions(self.u1)
        get_permissions(self.u1)
        info = cache_info()
        self.assertEqual(info.hits, 3)
        self.assertEqual(info.misses, 1)
        self.assertEqual(info.currsize, 1)

        # send cache_clear
        # test_client.publish('message', '"cache_clear"')
        test_client.publish_message('cache_clear')

        # process messages
        count = 0
        while info.hits > 0 or count < 10:
            self.loop(test_client, subscribe_client)
            time.sleep(0.1)
            info = cache_info()
            count += 1

        self.assertEqual(info.hits, 0)
        self.assertEqual(info.misses, 0)
        self.assertEqual(info.currsize, 0)

        # wait for disconnect
        subscribe_client.wait()
Ejemplo n.º 2
0
    def update(self, instance, validated_data):

        # get current user
        user = validated_data['updated_by']

        # check credentials
        if not user.is_superuser:

            # serializer.instance will always exist!
            # if not user.profile.ambulances.filter(can_write=True,
            #                                      ambulance=instance.id):
            if not get_permissions(user).check_can_write(
                    ambulance=instance.id):
                raise PermissionDenied()

        # update location_client
        # stored in validated_data as {'location_client': {'client_id': client_id}}
        if 'location_client' in validated_data:

            # retrieve new location_client and remove it from validated_data
            location_client = None
            client_id = validated_data.pop('location_client')['client_id']
            if client_id:
                location_client = Client.objects.get(client_id=client_id)

            # reset location_client if either new or old is None, otherwise ignore
            if instance.location_client is None or location_client is None:

                # fine, clear or update location client
                validated_data['location_client'] = location_client

        return super().update(instance, validated_data)
Ejemplo n.º 3
0
    def update(self, instance, validated_data):

        # get current user
        user = validated_data['updated_by']

        # check credentials
        if not user.is_superuser:

            # serializer.instance will always exist!
            # if not user.profile.ambulances.filter(can_write=True,
            #                                      ambulance=instance.id):
            if not get_permissions(user).check_can_write(ambulance=instance.id):
                raise PermissionDenied()

        return super().update(instance, validated_data)
Ejemplo n.º 4
0
    def get_queryset(self):

        # print('@get_queryset {}({})'.format(self.request.user,
        #                                     self.request.method))

        # return all objects if superuser
        user = self.request.user
        if user.is_superuser or user.is_staff:
            return super().get_queryset()

        # return nothing if anonymous
        if user.is_anonymous:
            raise PermissionDenied()

        # get permissions
        from login.permissions import get_permissions
        permissions = get_permissions(user)

        # otherwise only return objects that the user can read or write to
        # if dispatcher_override is True substitute read permissions for write permissions
        if self.request.method == 'GET' or (self.dispatcher_override and
                                            user.userprofile.is_dispatcher):
            # objects that the user can read
            can_do = permissions.get_can_read(self.profile_field)

        elif (self.request.method == 'PUT' or self.request.method == 'PATCH'
              or self.request.method == 'DELETE'):
            # objects that the user can write to
            can_do = permissions.get_can_write(self.profile_field)

        else:
            raise PermissionDenied()

        # add filter
        filter_params = {self.filter_field + '__in': can_do}

        logger.debug('can_do = {}'.format(can_do))
        logger.debug('filter_params = {}'.format(filter_params))

        # retrieve query
        return super().get_queryset().filter(**filter_params)
Ejemplo n.º 5
0
    def check_ambulance_permissions(self):

        # retrieve call_id
        call_id = int(self.kwargs['call_id'])

        # does call exist?
        try:
            call = Call.objects.get(id=call_id)
        except Call.DoesNotExist:
            raise exceptions.NotFound()

        # get user
        user = self.request.user
        if not (user.is_superuser or user.is_staff):

            # return nothing if anonymous
            if user.is_anonymous:
                raise exceptions.PermissionDenied()

            # get permissions
            permissions = get_permissions(user)
            can_do = set()
            if user.userprofile.is_dispatcher:
                can_do.update(permissions.get_can_read('ambulances'))
            else:
                can_do.update(permissions.get_can_write('ambulances'))

            # query ambulances
            ambulance_ids = set(flatten(call.ambulancecall_set.values_list('ambulance_id')))

            # logger.debug(can_do)
            # logger.debug(ambulance_ids)

            # fail if disjoints
            if can_do.isdisjoint(ambulance_ids):
                logger.info("call note create: '%s' is not super, staff, authorized user, or dispatcher", user)
                raise exceptions.PermissionDenied()

        return call
Ejemplo n.º 6
0
    def perform_create(self, serializer):

        # retrieve call_id
        call_id = int(self.kwargs['call_id'])

        # retrieve ambulance_id
        ambulance_id = int(self.kwargs['ambulance_id'])

        # does ambulancecall exist?
        try:
            ambulance_call = AmbulanceCall.objects.get(call_id=call_id, ambulance_id=ambulance_id)
        except AmbulanceCall.DoesNotExist:
            raise exceptions.NotFound()

        # check permission, create does not invoke queryset
        user = self.request.user
        if not (user.is_superuser or user.is_staff):

            # return nothing if anonymous
            if user.is_anonymous:
                raise exceptions.PermissionDenied()

            # get permissions
            permissions = get_permissions(user)
            can_do = set()
            if user.userprofile.is_dispatcher:
                can_do.update(permissions.get_can_read('ambulances'))
            else:
                can_do.update(permissions.get_can_write('ambulances'))

            # query ambulances
            if ambulance_call.ambulance.id not in can_do:

                logger.info("call waypoint create: '%s' is not super, staff, authorized user, or dispatcher", user)
                raise exceptions.PermissionDenied()

        # create
        super().perform_create(serializer, ambulance_call=ambulance_call)
Ejemplo n.º 7
0
    def test_cache(self):

        # clear cache
        cache_clear()

        # retrieve permissions for user u1
        get_permissions(self.u1)
        get_permissions(self.u1)
        get_permissions(self.u1)
        get_permissions(self.u1)
        info = cache_info()
        self.assertEqual(info.hits, 3)
        self.assertEqual(info.misses, 1)
        self.assertEqual(info.currsize, 1)

        # retrieve permissions for user u2 and u1
        get_permissions(self.u2)
        get_permissions(self.u1)
        get_permissions(self.u2)
        get_permissions(self.u1)
        info = cache_info()
        self.assertEqual(info.hits, 6)
        self.assertEqual(info.misses, 2)
        self.assertEqual(info.currsize, 2)

        # clear cache
        cache_clear()

        info = cache_info()
        self.assertEqual(info.hits, 0)
        self.assertEqual(info.misses, 0)
        self.assertEqual(info.currsize, 0)
Ejemplo n.º 8
0
    def update(self, instance, validated_data):

        # Get current user.
        user = validated_data['updated_by']

        # Make sure ambulancecall_set is not present
        if 'ambulancecall_set' in validated_data:
            raise serializers.ValidationError('Cannot modify ambulancecall_set')

        # Check permissions
        if not (user.is_superuser or user.is_staff):
            # Get ambulances
            for ambulancecall in instance.ambulancecall_set.all():
                # dispatcher override
                if user.userprofile.is_dispatcher:
                    if not get_permissions(user).check_can_read(ambulance=ambulancecall.ambulance.id):
                        raise PermissionDenied()
                else:
                    if not get_permissions(user).check_can_write(ambulance=ambulancecall.ambulance.id):
                        raise PermissionDenied()

        # Makes sure database rolls back in case of integrity or other errors
        with transaction.atomic():

            # Update patients
            if 'patient_set' in validated_data:

                # Extract patient set
                patient_set = validated_data.pop('patient_set')

                if patient_set:

                    # existing patients
                    logger.debug(patient_set)
                    existing_patients = [patient['id'] for patient in patient_set
                                         if 'id' in patient and patient['id'] is not None]

                    if existing_patients:

                        # delete if not in new patients
                        instance.patient_set.exclude(id__in=existing_patients).delete()

                    # create or update patients
                    for patient in patient_set:
                        pk = patient.pop('id', None)
                        if pk is None:
                            # create patient and do not publish
                            obj = Patient(call=instance, **patient)
                            obj.save(publish=False)
                        else:
                            # update patient, does not call save hence do not publish
                            Patient.objects.filter(id=pk).update(call=instance, **patient)

                else:

                    # delete all patients
                    instance.patient_set.all().delete()

            # Update sms_notifications
            sms_notifications_update = False
            sms_notifications = []
            if 'sms_notifications' in validated_data:
                sms_notifications = validated_data.pop('sms_notifications', [])
                sms_notifications_update = True

            # call super to update call, which will publish
            super().update(instance, validated_data)

            # sms notifications updated?
            if sms_notifications_update:

                # Extract users
                user_ids = set([user.id for user in sms_notifications])

                # delete users not in current notifications
                for user in instance.sms_notifications.exclude(id__in=user_ids):
                    instance.sms_notifications.remove(user)

                # remove ids of users already in
                user_ids = user_ids -\
                    set(instance.sms_notifications.filter(id__in=user_ids).values_list('id', flat=True))

                # add users not already in
                for id in user_ids:
                    instance.sms_notifications.add(User.objects.get(id=id))

                # publish, again, to updaate users
                # TODO: is there a way to avoid the double publication?
                instance.publish()

        # call super
        return instance
Ejemplo n.º 9
0
    def create(self, validated_data):

        # Get current user.
        user = validated_data['updated_by']

        # Make sure user is super, staff, or dispatcher.
        if not (user.is_superuser or user.is_staff or user.userprofile.is_dispatcher):
            raise PermissionDenied()
        
        ambulancecall_set = validated_data.pop('ambulancecall_set', [])
        patient_set = validated_data.pop('patient_set', [])
        sms_notifications = validated_data.pop('sms_notifications', [])

        # Makes sure database rolls back in case of integrity or other errors
        with transaction.atomic():

            # creates call first, do not publish
            call = Call(**validated_data)
            call.save(publish=False)

            # then patients, do not publish
            for patient in patient_set:
                obj = Patient(call=call, **patient)
                obj.save(publish=False)

            if call.status != CallStatus.P.name and len(ambulancecall_set) == 0:
                raise serializers.ValidationError('Started call and ended call must have ambulancecall_set')

            # then add ambulances, do not publish
            for ambulancecall in ambulancecall_set:
                ambulance = ambulancecall.pop('ambulance_id')

                # check permisssions in case of dispatcher
                if not (user.is_superuser or user.is_staff):
                    # this is the dispatcher_override
                    if not get_permissions(user).check_can_read(ambulance=ambulance.id):
                        raise PermissionDenied()

                waypoint_set = ambulancecall.pop('waypoint_set', [])
                ambulance_call = AmbulanceCall(call=call, ambulance=ambulance, **ambulancecall, updated_by=user)
                ambulance_call.save(publish=False)
                # add waypoints
                for waypoint in waypoint_set:
                    location = waypoint.pop('location', {})
                    if not location:
                        raise serializers.ValidationError('Location is not defined')
                    if 'id' in location:
                        # location already exists, retrieve
                        location = Location.objects.get(id=location['id'])
                    else:
                        # location does not exist, create one
                        if 'type' not in location:
                            raise serializers.ValidationError('Location type is not defined')
                        elif location['type'] == LocationType.h.name:
                            raise serializers.ValidationError('Hospitals must be created before using as waypoints')
                        elif location['type'] == LocationType.i.name or location['type'] == LocationType.w.name:
                            # TODO: check to see if a close by waypoint already exists to contain proliferation
                            location = Location.objects.create(**location, updated_by=user)
                        else:
                            raise serializers.ValidationError("Invalid waypoint '{}'".format(location))
                    # add waypoint
                    obj = Waypoint.objects.create(ambulance_call=ambulance_call, **waypoint,
                                                  location=location, updated_by=user)

            # add users to sms notifications
            for user in sms_notifications:
                if user.userprofile.mobile_number:
                    call.sms_notifications.add(user)
                else:
                    logger.warning("User %s does not have a mobile phone on file, skipping", user)

            # publish call to mqtt only after all includes have succeeded
            call.publish()

            # then publish ambulance calls
            for ambulancecall in call.ambulancecall_set.all():
                ambulancecall.publish()

        return call
Ejemplo n.º 10
0
    def save(self, *args, **kwargs):

        from ambulance.models import Ambulance
        from hospital.models import Hospital

        # creation?
        created = self.pk is None

        # loaded_values?
        loaded_values = self._loaded_values is not None

        # log
        log = []

        # publication list
        publish_ambulance = set()
        publish_hospital = set()

        # logger.debug('self = {}'.format(self))
        # if loaded_values:
        #     logger.debug('_loaded_values = {}'.format(self._loaded_values))

        # online or reconnect
        if self.status == ClientStatus.O.name or self.status == ClientStatus.R.name:

            # log operation
            log.append({
                'client': self,
                'user': self.user,
                'status': self.status,
                'activity': ClientActivity.HS.name
            })

            if self.status == ClientStatus.R.name and self.ambulance is None:

                try:

                    # retrieve latest ambulance logout
                    latest = ClientLog.objects.filter(
                        status=ClientStatus.D.name,
                        activity=ClientActivity.AO.name).latest('updated_on')

                    identifier = latest.details
                    if identifier is not None:

                        # restore latest ambulance client
                        ambulance = Ambulance.objects.get(
                            identifier=identifier)
                        self.ambulance = ambulance

                except ClientLog.DoesNotExist:
                    pass

            # last ambulance
            if loaded_values and self._loaded_values[
                    'ambulance_id'] is not None:
                last_ambulance = Ambulance.objects.get(
                    id=self._loaded_values['ambulance_id'])
            else:
                last_ambulance = None

            # changed ambulance?
            if last_ambulance != self.ambulance:

                # ambulance logout?
                if last_ambulance is not None:

                    # log ambulance logout operation
                    log.append({
                        'client': self,
                        'user': self.user,
                        'status': ClientStatus.O.name,
                        'activity': ClientActivity.AO.name,
                        'details': last_ambulance.identifier
                    })

                    # publish ambulance
                    publish_ambulance.add(last_ambulance)

                # ambulance login?
                if self.ambulance is not None:

                    # log ambulance login operation
                    log.append({
                        'client': self,
                        'user': self.user,
                        'status': ClientStatus.O.name,
                        'activity': ClientActivity.AI.name,
                        'details': self.ambulance.identifier
                    })

                    # publish ambulance
                    publish_ambulance.add(self.ambulance)

            # last hospital
            if loaded_values and self._loaded_values['hospital_id'] is not None:
                last_hospital = Hospital.objects.get(
                    id=self._loaded_values['hospital_id'])
            else:
                last_hospital = None

            # changed hospital?
            if last_hospital != self.hospital:

                # hospital logout?
                if last_hospital is not None:

                    # log hospital logout operation
                    log.append({
                        'client': self,
                        'user': self.user,
                        'status': ClientStatus.O.name,
                        'activity': ClientActivity.HO.name,
                        'details': last_hospital.name
                    })

                    # publish hospital
                    publish_hospital.add(last_hospital)

                # hospital login?
                if self.hospital is not None:

                    # log hospital login operation
                    log.append({
                        'client': self,
                        'user': self.user,
                        'status': ClientStatus.O.name,
                        'activity': ClientActivity.HI.name,
                        'details': self.hospital.name
                    })

                    # publish hospital
                    publish_hospital.add(self.hospital)

        # offline or disconnected
        elif self.status == ClientStatus.D.name or self.status == ClientStatus.F.name:

            # has ambulance?
            if loaded_values and self._loaded_values[
                    'ambulance_id'] is not None:

                # log ambulance logout activity
                last_ambulance = Ambulance.objects.get(
                    id=self._loaded_values['ambulance_id'])
                log.append({
                    'client': self,
                    'user': self.user,
                    'status': self.status,
                    'activity': ClientActivity.AO.name,
                    'details': last_ambulance.identifier
                })

                if self.status == ClientStatus.F.name and last_ambulance.status != AmbulanceStatus.UK.name:

                    # change status of ambulance to unknown; do not publish yet
                    last_ambulance.status = AmbulanceStatus.UK.name
                    last_ambulance.save(publish=False)

                # publish ambulance
                publish_ambulance.add(last_ambulance)

            if self.ambulance is not None:

                # log warning
                logger.error(
                    "Client.save() called with status '{}' and ambulance '{} not None"
                    .format(self.status, self.ambulance))

                # logout ambulance
                self.ambulance = None

            # has hospital?
            if loaded_values and self._loaded_values['hospital_id'] is not None:

                # log hospital logout activity
                last_hospital = Hospital.objects.get(
                    id=self._loaded_values['hospital_id'])
                log.append({
                    'client': self,
                    'user': self.user,
                    'status': self.status,
                    'activity': ClientActivity.HO.name,
                    'details': last_hospital.name
                })

                # publish hospital
                publish_hospital.add(last_hospital)

            if self.hospital is not None:
                # log warning
                logger.error(
                    "Client.save() called with status '{}' and hospital '{} not None"
                    .format(self.status, self.hospital))

                # logout hospital
                self.hospital = None

            # log operation
            log.append({
                'client': self,
                'user': self.user,
                'status': self.status,
                'activity': ClientActivity.HS.name
            })

        # check permissions
        if self.ambulance is not None or self.hospital is not None:

            permissions = get_permissions(self.user)
            if self.ambulance is not None and not permissions.check_can_write(
                    ambulance=self.ambulance.id):
                raise PermissionDenied(_('Cannot write on ambulance'))

            if self.hospital is not None and not permissions.check_can_write(
                    hospital=self.hospital.id):
                raise PermissionDenied(_('Cannot write on hospital'))

        # call super
        super().save(*args, **kwargs)

        # save logs
        for entry in log:
            # logger.debug(entry)
            ClientLog.objects.create(**entry)

        # publish to mqtt
        # logger.debug('publish_ambulance = {}'.format(publish_ambulance))
        # logger.debug('publish_hospital = {}'.format(publish_hospital))
        from mqtt.publish import SingletonPublishClient

        for ambulance in publish_ambulance:
            SingletonPublishClient().publish_ambulance(ambulance)

        for hospital in publish_hospital:
            SingletonPublishClient().publish_hospital(hospital)
Ejemplo n.º 11
0
    def get_queryset(self, equipmentholder_id=None):

        # retrieve user
        user = self.request.user

        # return nothing if anonymous
        if user.is_anonymous:
            raise PermissionDenied()

        # retrieve id
        if equipmentholder_id is None:
            equipmentholder_id = int(self.kwargs['equipmentholder_id'])
        logger.debug('kwargs = {}'.format(self.kwargs))

        try:

            # retrieve equipmentholder
            equipmentholder = EquipmentHolder.objects.get(
                id=equipmentholder_id)

            # read or write?
            if self.request.method == 'GET':
                is_write = False
            elif (self.request.method == 'PUT'
                  or self.request.method == 'PATCH'
                  or self.request.method == 'DELETE'):
                is_write = True

            # is hospital?
            if equipmentholder.is_hospital():

                # check permission (and also existence)
                if is_write:
                    if not get_permissions(user).check_can_write(
                            hospital=equipmentholder.hospital.id):
                        raise PermissionDenied()
                else:
                    if not get_permissions(user).check_can_read(
                            hospital=equipmentholder.hospital.id):
                        raise PermissionDenied()

            # is ambulance?
            elif equipmentholder.is_ambulance():

                # check permission (and also existence)
                if is_write:
                    if not get_permissions(user).check_can_write(
                            ambulance=equipmentholder.ambulance.id):
                        raise PermissionDenied()
                else:
                    if not get_permissions(user).check_can_read(
                            ambulance=equipmentholder.ambulance.id):
                        raise PermissionDenied()

            else:
                raise PermissionDenied()

        except EquipmentHolder.DoesNotExist as e:
            raise PermissionDenied()

        # build queryset
        filter = {'equipmentholder_id': equipmentholder_id}
        return self.queryset.filter(**filter)
    def test_call_create_viewset_privileged_user(self):

        # instantiate client
        client = APIClient()

        # login superuser
        user = User.objects.get(email='*****@*****.**')
        client.force_authenticate(user=user)

        # create call
        call = {
            'status':
            CallStatus.P.name,
            'priority':
            CallPriority.B.name,
            'sms_notifications': [],
            'ambulancecall_set': [{
                'ambulance_id':
                self.a1.id,
                'waypoint_set': [{
                    'order': 0,
                    'location': {
                        'location': {
                            'longitude': -123.0208,
                            'latitude': 44.0464
                        },
                        'type': LocationType.i.name,
                        'number': '123',
                        'street': 'some street'
                    }
                }, {
                    'order': 1,
                    'status': WaypointStatus.D.name,
                    'location': {
                        'location': {
                            'longitude': -110.54,
                            'latitude': 35.75
                        },
                        'type': LocationType.w.name,
                    }
                }]
            }, {
                'ambulance_id':
                self.a2.id,
                'waypoint_set': [{
                    'order': 0,
                    'location': {
                        'location': {
                            'longitude': -123.0208,
                            'latitude': 44.0464
                        },
                        'type': LocationType.i.name,
                        'number': '321',
                        'street': 'another street'
                    }
                }]
            }, {
                'ambulance_id': self.a3.id,
            }],
            'patient_set': [{
                'name': 'Jose',
                'age': 3
            }, {
                'name': 'Maria',
                'age': 10
            }]
        }
        response = client.post('/en/api/call/',
                               json.dumps(call),
                               content_type='application/json')
        self.assertEqual(response.status_code, 201)

        # login as [email protected]
        user = User.objects.get(email='*****@*****.**')
        client.force_authenticate(user=user)

        # get permissions
        perms = get_permissions(user)

        # call/+/ambulance/+/wapypoint list
        call = Call.objects.get(status=CallStatus.P.name)
        for ambulancecall in call.ambulancecall_set.all():

            response = client.get(
                '/en/api/call/{}/ambulance/{}/waypoint/'.format(
                    call.id, ambulancecall.ambulance.id))
            self.assertEqual(response.status_code, 200)
            answer = JSONParser().parse(BytesIO(response.content))
            if perms.check_can_read(ambulance=ambulancecall.ambulance.id):
                expected = WaypointSerializer(ambulancecall.waypoint_set.all(),
                                              many=True).data
            else:
                expected = []
            #logger.debug("answer = %s", answer)
            #logger.debug("expected = %s", expected)
            self.assertCountEqual(answer, expected)

        # call/+/ambulance/+/wapypoint/+/ retrieve
        for ambulancecall in call.ambulancecall_set.all():

            for waypoint in ambulancecall.waypoint_set.all():
                response = client.get(
                    '/en/api/call/{}/ambulance/{}/waypoint/{}/'.format(
                        call.id, ambulancecall.ambulance.id, waypoint.id))
                if perms.check_can_read(ambulance=ambulancecall.ambulance.id):
                    self.assertEqual(response.status_code, 200)
                    answer = JSONParser().parse(BytesIO(response.content))
                    expected = WaypointSerializer(waypoint).data
                    self.assertCountEqual(answer, expected)
                else:
                    self.assertEqual(response.status_code, 404)

        # call/+/ambulance/+/wapypoint/ post
        data = {
            'order': 3,
            'location': {
                'location': {
                    'longitude': -123.0208,
                    'latitude': 44.0464
                },
                'type': LocationType.i.name,
                'number': '123',
                'street': 'some street'
            }
        }
        response = client.post('/en/api/call/{}/ambulance/{}/waypoint/'.format(
            call.id, self.a2.id),
                               json.dumps(data),
                               content_type='application/json')
        self.assertEqual(response.status_code, 403)

        response = client.post('/en/api/call/{}/ambulance/{}/waypoint/'.format(
            call.id, self.a1.id),
                               json.dumps(data),
                               content_type='application/json')
        self.assertEqual(response.status_code, 403)

        response = client.post('/en/api/call/{}/ambulance/{}/waypoint/'.format(
            call.id, self.a3.id),
                               json.dumps(data),
                               content_type='application/json')
        self.assertEqual(response.status_code, 201)
        answer = JSONParser().parse(BytesIO(response.content))
        expected = WaypointSerializer(
            call.ambulancecall_set.get(
                ambulance=self.a1).waypoint_set.last()).data
        self.assertCountEqual(answer, expected)

        # call/+/ambulance/+/wapypoint/+/ update
        data = {
            'location': {
                'type': LocationType.w.name,
            }
        }
        response = client.patch(
            '/en/api/call/{}/ambulance/{}/waypoint/{}/'.format(
                call.id, self.a2.id, answer['id']),
            json.dumps(data),
            content_type='application/json')
        logger.debug(response.content)
        self.assertEqual(response.status_code, 404)

        response = client.patch(
            '/en/api/call/{}/ambulance/{}/waypoint/{}/'.format(
                call.id, self.a1.id, answer['id']),
            json.dumps(data),
            content_type='application/json')
        logger.debug(response.content)
        self.assertEqual(response.status_code, 404)

        response = client.patch(
            '/en/api/call/{}/ambulance/{}/waypoint/{}/'.format(
                call.id, self.a3.id, answer['id']),
            json.dumps(data),
            content_type='application/json')
        logger.debug(response.content)
        self.assertEqual(response.status_code, 200)
        answer = JSONParser().parse(BytesIO(response.content))
        expected = WaypointSerializer(
            call.ambulancecall_set.get(
                ambulance=self.a3).waypoint_set.last()).data
        logger.debug(answer)
        self.assertDictEqual(answer, expected)
        self.assertEqual(answer['location']['type'], LocationType.w.name)

        # call/+/ambulance/+/wapypoint/+/ update to forbidden type
        data = {
            'location': {
                'type': LocationType.h.name,
            }
        }
        response = client.patch(
            '/en/api/call/{}/ambulance/{}/waypoint/{}/'.format(
                call.id, self.a3.id, answer['id']),
            json.dumps(data),
            content_type='application/json')
        logger.debug(response.content)
        self.assertEqual(response.status_code, 400)