diff --git a/src/c3nav/editor/forms.py b/src/c3nav/editor/forms.py index 6626a4e3..e532a83b 100644 --- a/src/c3nav/editor/forms.py +++ b/src/c3nav/editor/forms.py @@ -309,13 +309,6 @@ class EditorFormBase(I18nModelFormMixin, ModelForm): _('Can not add redirecting slug ā€œ%sā€: it is already used elsewhere.') % slug ) - def clean_data(self): - data = self.cleaned_data['data'] - if not data.wifi: - raise ValidationError(_('WiFi scan data is missing.')) - data.wifi = [[item for item in scan if item.ssid] for scan in data.wifi] - return data - def clean(self): if self.is_json: for name, field in self.missing_fields: @@ -325,6 +318,15 @@ class EditorFormBase(I18nModelFormMixin, ModelForm): if not self.cleaned_data.get('geometry'): raise ValidationError('Missing geometry.') + data = self.cleaned_data['data'] + if self.cleaned_data['fill_quest']: + if self.cleaned_data['data'].wifi: + raise ValidationError(_('Why is there WiFi scan data if this is a fill quest?')) + else: + if not self.cleaned_data['data'].wifi: + raise ValidationError(_('WiFi scan data is missing.')) + self.cleaned_data['data'].wifi = [[item for item in scan if item.ssid] for scan in data.wifi] + super().clean() def _save_m2m(self): diff --git a/src/c3nav/mapdata/quests/positioning.py b/src/c3nav/mapdata/quests/positioning.py index 8a86ef0f..1ef49903 100644 --- a/src/c3nav/mapdata/quests/positioning.py +++ b/src/c3nav/mapdata/quests/positioning.py @@ -6,8 +6,9 @@ from django.utils.translation import gettext_lazy as _ from shapely import Point from shapely.geometry import mapping -from c3nav.mapdata.models.geometry.space import RangingBeacon +from c3nav.mapdata.models.geometry.space import RangingBeacon, BeaconMeasurement from c3nav.mapdata.quests.base import ChangeSetModelForm, register_quest, Quest +from c3nav.routing.schemas import BeaconMeasurementDataSchema class RangingBeaconAltitudeQuestForm(ChangeSetModelForm): @@ -103,3 +104,49 @@ class RangingBeaconBSSIDsQuest(Quest): @classmethod def _qs_for_request(cls, request): return RangingBeacon.qs_for_request(request).filter(import_tag__startswith="noc:", wifi_bssids=[]) + + +class BeaconMeasurementQuestForm(ChangeSetModelForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["data"].widget = HiddenInput() + + def clean_bssids(self): + data = self.cleaned_data["data"] + if not data: + raise ValidationError(_("Need at least one scan.")) + return data + + class Meta: + model = BeaconMeasurement + fields = ("data", ) + + @property + def changeset_title(self): + return f'Beacon Measurement Quest: {self.instance.title}' + + +@register_quest +@dataclass +class BeaconMeasurementQuest(Quest): + quest_type = "beacon_measurement" + quest_type_label = _('Wifi/BLE Positioning') + quest_type_icon = "wifi" + form_class = BeaconMeasurementQuestForm + obj: BeaconMeasurement + + @property + def quest_description(self) -> list[str]: + return [ + _("Please stand as close to the given location as possible. " + "Feel free to close this window again to double-check."), + _("When you're ready, please click the button below and wait for measurements to arrive."), + ] + + @property + def point(self) -> Point: + return mapping(self.obj.geometry) + + @classmethod + def _qs_for_request(cls, request): + return BeaconMeasurement.qs_for_request(request).filter(data=BeaconMeasurementDataSchema()) diff --git a/src/c3nav/routing/schemas.py b/src/c3nav/routing/schemas.py index bc4131e6..29c0b012 100644 --- a/src/c3nav/routing/schemas.py +++ b/src/c3nav/routing/schemas.py @@ -114,4 +114,7 @@ class LocateIBeaconPeerSchema(BaseSchema): class BeaconMeasurementDataSchema(BaseSchema): wifi: list[list[LocateWifiPeerSchema]] = [] - ibeacon: list[list[LocateIBeaconPeerSchema]] = [] \ No newline at end of file + ibeacon: list[list[LocateIBeaconPeerSchema]] = [] + + def __bool__(self): + return bool(self.wifi or self.ibeacon) \ No newline at end of file