integrate data overlay api into new MapdataAPIBuilder
This commit is contained in:
parent
be76f3a8db
commit
707c81f159
5 changed files with 38 additions and 41 deletions
|
@ -17,7 +17,7 @@ from c3nav.mapdata.models.geometry.space import (POI, Column, CrossDescription,
|
||||||
Obstacle, Ramp)
|
Obstacle, Ramp)
|
||||||
from c3nav.mapdata.models.locations import DynamicLocation
|
from c3nav.mapdata.models.locations import DynamicLocation
|
||||||
from c3nav.mapdata.schemas.filters import (ByCategoryFilter, ByGroupFilter, ByOnTopOfFilter, FilterSchema,
|
from c3nav.mapdata.schemas.filters import (ByCategoryFilter, ByGroupFilter, ByOnTopOfFilter, FilterSchema,
|
||||||
LevelGeometryFilter, SpaceGeometryFilter, BySpaceFilter)
|
LevelGeometryFilter, SpaceGeometryFilter, BySpaceFilter, ByOverlayFilter)
|
||||||
from c3nav.mapdata.schemas.model_base import schema_description
|
from c3nav.mapdata.schemas.model_base import schema_description
|
||||||
from c3nav.mapdata.schemas.models import (AccessRestrictionGroupSchema, AccessRestrictionSchema, AreaSchema,
|
from c3nav.mapdata.schemas.models import (AccessRestrictionGroupSchema, AccessRestrictionSchema, AreaSchema,
|
||||||
BuildingSchema, ColumnSchema, CrossDescriptionSchema, DoorSchema,
|
BuildingSchema, ColumnSchema, CrossDescriptionSchema, DoorSchema,
|
||||||
|
@ -143,6 +143,7 @@ class MapdataAPIBuilder:
|
||||||
call_func=mapdata_retrieve_endpoint,
|
call_func=mapdata_retrieve_endpoint,
|
||||||
add_call_params={"model": endpoint.model.__name__, "pk": id_field}
|
add_call_params={"model": endpoint.model.__name__, "pk": id_field}
|
||||||
)
|
)
|
||||||
|
list_func.__name__ = f"{endpoint.model_name}_by_id"
|
||||||
|
|
||||||
self.router.get(f'/{endpoint.model_name_plural}/{{{id_field}}}/', summary=f"{endpoint.model_name} by ID",
|
self.router.get(f'/{endpoint.model_name_plural}/{{{id_field}}}/', summary=f"{endpoint.model_name} by ID",
|
||||||
tags=[f"mapdata-{tag}"], description=schema_description(endpoint.schema),
|
tags=[f"mapdata-{tag}"], description=schema_description(endpoint.schema),
|
||||||
|
@ -195,6 +196,15 @@ mapdata_endpoints: dict[str, list[MapdataEndpoint]] = {
|
||||||
model=DynamicLocation,
|
model=DynamicLocation,
|
||||||
schema=DynamicLocationSchema,
|
schema=DynamicLocationSchema,
|
||||||
),
|
),
|
||||||
|
MapdataEndpoint(
|
||||||
|
model=DataOverlay,
|
||||||
|
schema=DataOverlaySchema,
|
||||||
|
),
|
||||||
|
MapdataEndpoint(
|
||||||
|
model=DataOverlayFeature,
|
||||||
|
schema=DataOverlayFeatureSchema,
|
||||||
|
filters=ByOverlayFilter,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
"level": [
|
"level": [
|
||||||
MapdataEndpoint(
|
MapdataEndpoint(
|
||||||
|
@ -269,35 +279,3 @@ mapdata_endpoints: dict[str, list[MapdataEndpoint]] = {
|
||||||
|
|
||||||
|
|
||||||
MapdataAPIBuilder(router=mapdata_api_router).build_all_endpoints(mapdata_endpoints)
|
MapdataAPIBuilder(router=mapdata_api_router).build_all_endpoints(mapdata_endpoints)
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
Data overlays
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# todo: this wants to move into a MapDataEndpoint
|
|
||||||
@mapdata_api_router.get('/overlays/', summary="data overlay list",
|
|
||||||
tags=["mapdata-root"], description=schema_description(DynamicLocationSchema),
|
|
||||||
response={200: list[DataOverlaySchema], **auth_responses})
|
|
||||||
@api_etag()
|
|
||||||
def dataoverlay_list(request):
|
|
||||||
return mapdata_list_endpoint(request, model=DataOverlay)
|
|
||||||
|
|
||||||
|
|
||||||
# todo: this wants to move into a MapDataEndpoint
|
|
||||||
@mapdata_api_router.get('/overlays/{overlay_id}/', summary="features for overlay by overlay ID",
|
|
||||||
tags=["mapdata-root"], description=schema_description(DynamicLocationSchema),
|
|
||||||
response={200: list[DataOverlayFeatureSchema], **API404.dict(), **auth_responses})
|
|
||||||
# @api_etag()
|
|
||||||
def dataoverlay_by_id(request, overlay_id: int):
|
|
||||||
qs = optimize_query(
|
|
||||||
DataOverlayFeature.qs_for_request(request)
|
|
||||||
)
|
|
||||||
|
|
||||||
qs = qs.filter(overlay_id=overlay_id)
|
|
||||||
|
|
||||||
# order_by
|
|
||||||
qs = qs.order_by('pk')
|
|
||||||
|
|
||||||
return qs
|
|
||||||
|
|
|
@ -21,11 +21,11 @@ class DataOverlay(TitledMixin, models.Model):
|
||||||
verbose_name=_('headers for pull http request (JSON object)'))
|
verbose_name=_('headers for pull http request (JSON object)'))
|
||||||
pull_interval = models.DurationField(blank=True, null=True, verbose_name=_('pull interval'))
|
pull_interval = models.DurationField(blank=True, null=True, verbose_name=_('pull interval'))
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Data Overlay')
|
verbose_name = _('Data Overlay')
|
||||||
verbose_name_plural = _('Data Overlays')
|
verbose_name_plural = _('Data Overlays')
|
||||||
default_related_name = 'data_overlays'
|
default_related_name = 'dataoverlays'
|
||||||
|
|
||||||
|
|
||||||
class DataOverlayFeature(TitledMixin, GeometryMixin, models.Model):
|
class DataOverlayFeature(TitledMixin, GeometryMixin, models.Model):
|
||||||
overlay = models.ForeignKey('mapdata.DataOverlay', on_delete=models.CASCADE, verbose_name=_('Overlay'), related_name='features')
|
overlay = models.ForeignKey('mapdata.DataOverlay', on_delete=models.CASCADE, verbose_name=_('Overlay'), related_name='features')
|
||||||
|
@ -45,7 +45,6 @@ class DataOverlayFeature(TitledMixin, GeometryMixin, models.Model):
|
||||||
extra_data: Optional[dict[str, str]] = SchemaField(schema=dict[str, str], blank=True, null=True, default=None,
|
extra_data: Optional[dict[str, str]] = SchemaField(schema=dict[str, str], blank=True, null=True, default=None,
|
||||||
verbose_name=_('extra data (JSON object)'))
|
verbose_name=_('extra data (JSON object)'))
|
||||||
|
|
||||||
|
|
||||||
def to_geojson(self, instance=None) -> dict:
|
def to_geojson(self, instance=None) -> dict:
|
||||||
result = {
|
result = {
|
||||||
'type': 'Feature',
|
'type': 'Feature',
|
||||||
|
@ -65,7 +64,6 @@ class DataOverlayFeature(TitledMixin, GeometryMixin, models.Model):
|
||||||
def get_geojson_key(self):
|
def get_geojson_key(self):
|
||||||
return 'dataoverlayfeature', self.id
|
return 'dataoverlayfeature', self.id
|
||||||
|
|
||||||
|
|
||||||
def _serialize(self, **kwargs):
|
def _serialize(self, **kwargs):
|
||||||
result = super()._serialize(**kwargs)
|
result = super()._serialize(**kwargs)
|
||||||
result.update({
|
result.update({
|
||||||
|
@ -84,4 +82,4 @@ class DataOverlayFeature(TitledMixin, GeometryMixin, models.Model):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
default_related_name = "overlayfeatures"
|
default_related_name = "dataoverlayfeatures"
|
||||||
|
|
|
@ -136,6 +136,23 @@ class ByOnTopOfFilter(FilterSchema):
|
||||||
return super().filter_qs(qs)
|
return super().filter_qs(qs)
|
||||||
|
|
||||||
|
|
||||||
|
class ByOverlayFilter(FilterSchema):
|
||||||
|
overlay: int = APIField(
|
||||||
|
title='filter by data overlay',
|
||||||
|
description='only show overlay features belonging to this overlay'
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate(self, request):
|
||||||
|
super().validate(request)
|
||||||
|
if self.overlay is not None:
|
||||||
|
assert_valid_value(request, Level, "pk", {self.overlay})
|
||||||
|
|
||||||
|
def filter_qs(self, qs: QuerySet) -> QuerySet:
|
||||||
|
if self.overlay is not None:
|
||||||
|
qs = qs.filter(overlay=self.overlay)
|
||||||
|
return super().filter_qs(qs)
|
||||||
|
|
||||||
|
|
||||||
class BySearchableFilter(FilterSchema):
|
class BySearchableFilter(FilterSchema):
|
||||||
searchable: bool = APIField(
|
searchable: bool = APIField(
|
||||||
False,
|
False,
|
||||||
|
|
|
@ -319,11 +319,16 @@ class DynamicLocationSchema(SpecificLocationSchema, DjangoModelSchema):
|
||||||
|
|
||||||
|
|
||||||
class DataOverlaySchema(TitledSchema, DjangoModelSchema):
|
class DataOverlaySchema(TitledSchema, DjangoModelSchema):
|
||||||
# TODO
|
"""
|
||||||
|
Represents a collection of geometries to be displayed as an optional overlay to the map.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DataOverlayFeatureSchema(TitledSchema, DjangoModelSchema):
|
class DataOverlayFeatureSchema(TitledSchema, DjangoModelSchema):
|
||||||
|
"""
|
||||||
|
A feature (any kind of geometry) to be displayed as part of a data overlay.
|
||||||
|
"""
|
||||||
geometry: AnyGeometrySchema
|
geometry: AnyGeometrySchema
|
||||||
level_id: PositiveInt
|
level_id: PositiveInt
|
||||||
stroke_color: Optional[str]
|
stroke_color: Optional[str]
|
||||||
|
@ -336,7 +341,6 @@ class DataOverlayFeatureSchema(TitledSchema, DjangoModelSchema):
|
||||||
external_url: Optional[str]
|
external_url: Optional[str]
|
||||||
extra_data: Optional[dict[str, str]]
|
extra_data: Optional[dict[str, str]]
|
||||||
# TODO
|
# TODO
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class SourceSchema(WithAccessRestrictionSchema, DjangoModelSchema):
|
class SourceSchema(WithAccessRestrictionSchema, DjangoModelSchema):
|
||||||
|
|
|
@ -2841,7 +2841,7 @@ class DataOverlay {
|
||||||
}
|
}
|
||||||
|
|
||||||
async create() {
|
async create() {
|
||||||
const features = await c3nav_api.get(`mapdata/overlays/${this.id}/`);
|
const features = await c3nav_api.get(`mapdata/dataoverlayfeatures/?overlay=${this.id}`);
|
||||||
|
|
||||||
const levels = {};
|
const levels = {};
|
||||||
for (const feature of features) {
|
for (const feature of features) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue