add tons of mapdata endpoints, enhance documentation and operation IDs
This commit is contained in:
parent
7447537c4a
commit
f43d458fc4
12 changed files with 637 additions and 169 deletions
318
src/c3nav/mapdata/newapi/mapdata.py
Normal file
318
src/c3nav/mapdata/newapi/mapdata.py
Normal file
|
@ -0,0 +1,318 @@
|
|||
from typing import Optional, Sequence, Type
|
||||
|
||||
from django.db.models import Model
|
||||
from ninja import Query
|
||||
from ninja import Router as APIRouter
|
||||
from ninja.pagination import paginate
|
||||
|
||||
from c3nav.api.exceptions import API404
|
||||
from c3nav.mapdata.api import optimize_query
|
||||
from c3nav.mapdata.models import Area, Building, Door, Hole, Level, Space, Stair
|
||||
from c3nav.mapdata.models.access import AccessPermission
|
||||
from c3nav.mapdata.models.geometry.space import POI, Column, LineObstacle, Obstacle, Ramp
|
||||
from c3nav.mapdata.schemas.filters import ByGroupFilter, ByLevelFilter, ByOnTopOfFilter, BySpaceFilter, FilterSchema
|
||||
from c3nav.mapdata.schemas.models import (AreaSchema, BuildingSchema, ColumnSchema, DoorSchema, HoleSchema, LevelSchema,
|
||||
LineObstacleSchema, ObstacleSchema, POISchema, RampSchema, SpaceSchema,
|
||||
StairSchema)
|
||||
|
||||
mapdata_api_router = APIRouter(tags=["mapdata"])
|
||||
|
||||
|
||||
def mapdata_list_endpoint(request,
|
||||
model: Type[Model],
|
||||
filters: Optional[FilterSchema] = None,
|
||||
order_by: Sequence[str] = ('pk',)):
|
||||
# todo: request permissions based on api key
|
||||
|
||||
# todo: pagination cache?
|
||||
|
||||
# generate cache_key
|
||||
# todo: don't ignore request language
|
||||
cache_key = 'mapdata:api:%s:%s' % (model.__name__, AccessPermission.cache_key_for_request(request))
|
||||
if filters:
|
||||
for name in filters.model_fields_set: # noqa
|
||||
value = getattr(filters, name)
|
||||
if value is None:
|
||||
continue
|
||||
cache_key += ';%s,%s' % (name, value)
|
||||
|
||||
# todo: we have the cache key, this would be a great time for a shortcut
|
||||
|
||||
# validate filters
|
||||
if filters:
|
||||
filters.validate(request)
|
||||
|
||||
# get the queryset and filter it
|
||||
qs = optimize_query(
|
||||
model.qs_for_request(request) if hasattr(model, 'qs_for_request') else model.objects.all()
|
||||
)
|
||||
if filters:
|
||||
qs = filters.filter_qs(qs)
|
||||
|
||||
# order_by
|
||||
qs = qs.order_by(*order_by)
|
||||
|
||||
# todo: can access geometry… using defer?
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
def mapdata_retrieve_endpoint(request, model: Type[Model], **lookups):
|
||||
try:
|
||||
return optimize_query(
|
||||
model.qs_for_request(request) if hasattr(model, 'qs_for_request') else model.objects.all()
|
||||
).get(**lookups)
|
||||
except model.DoesNotExist:
|
||||
raise API404("%s not found" % model.__name__.lower())
|
||||
|
||||
|
||||
"""
|
||||
Levels
|
||||
"""
|
||||
|
||||
|
||||
class LevelFilters(ByGroupFilter, ByOnTopOfFilter):
|
||||
pass
|
||||
|
||||
|
||||
@mapdata_api_router.get('/levels/', response=list[LevelSchema],
|
||||
summary="Get level list")
|
||||
@paginate
|
||||
def level_list(request, filters: Query[LevelFilters]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Level, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/levels/{level_id}/', response=LevelSchema,
|
||||
summary="Get level by ID")
|
||||
def level_detail(request, level_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Level, pk=level_id)
|
||||
|
||||
|
||||
"""
|
||||
Buildings
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/buildings/', response=list[BuildingSchema],
|
||||
summary="Get building list")
|
||||
@paginate
|
||||
def building_list(request, filters: Query[ByLevelFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Building, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/buildings/{building_id}/', response=BuildingSchema,
|
||||
summary="Get building by ID")
|
||||
def building_detail(request, building_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Building, pk=building_id)
|
||||
|
||||
|
||||
"""
|
||||
Spaces
|
||||
"""
|
||||
|
||||
|
||||
class SpaceFilters(ByGroupFilter, ByLevelFilter):
|
||||
pass
|
||||
|
||||
|
||||
@mapdata_api_router.get('/spaces/', response=list[SpaceSchema],
|
||||
summary="Get space list")
|
||||
@paginate
|
||||
def space_list(request, filters: Query[SpaceFilters]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Space, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/space/{space_id}/', response=SpaceSchema,
|
||||
summary="Get space by ID")
|
||||
def space_detail(request, space_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Space, pk=space_id)
|
||||
|
||||
|
||||
"""
|
||||
Doors
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/doors/', response=list[DoorSchema],
|
||||
summary="Get door list")
|
||||
@paginate
|
||||
def door_list(request, filters: Query[ByLevelFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Door, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/doors/{door_id}/', response=DoorSchema,
|
||||
summary="Get door by ID")
|
||||
def door_detail(request, door_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Door, pk=door_id)
|
||||
|
||||
|
||||
"""
|
||||
Holes
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/holes/', response=list[HoleSchema],
|
||||
summary="Get hole list")
|
||||
@paginate
|
||||
def hole_list(request, filters: Query[BySpaceFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Hole, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/holes/{hole_id}/', response=HoleSchema,
|
||||
summary="Get hole by ID")
|
||||
def hole_detail(request, hole_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Hole, pk=hole_id)
|
||||
|
||||
|
||||
"""
|
||||
Areas
|
||||
"""
|
||||
|
||||
|
||||
class AreaFilters(ByGroupFilter, BySpaceFilter):
|
||||
pass
|
||||
|
||||
|
||||
@mapdata_api_router.get('/areas/', response=list[AreaSchema],
|
||||
summary="Get area list")
|
||||
@paginate
|
||||
def area_list(request, filters: Query[AreaFilters]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Area, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/areas/{area_id}/', response=AreaSchema,
|
||||
summary="Get area by ID")
|
||||
def area_detail(request, area_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Area, pk=area_id)
|
||||
|
||||
|
||||
"""
|
||||
Stairs
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/stairs/', response=list[StairSchema],
|
||||
summary="Get stair list")
|
||||
@paginate
|
||||
def stair_list(request, filters: Query[BySpaceFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Stair, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/stairs/{stair_id}/', response=StairSchema,
|
||||
summary="Get stair by ID")
|
||||
def stair_detail(request, stair_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Stair, pk=stair_id)
|
||||
|
||||
|
||||
"""
|
||||
Ramps
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/ramps/', response=list[RampSchema],
|
||||
summary="Get ramp list")
|
||||
@paginate
|
||||
def ramp_list(request, filters: Query[BySpaceFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Ramp, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/ramps/{ramp_id}/', response=RampSchema,
|
||||
summary="Get ramp by ID")
|
||||
def ramp_detail(request, ramp_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Ramp, pk=ramp_id)
|
||||
|
||||
|
||||
"""
|
||||
Obstacles
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/obstacles/', response=list[ObstacleSchema],
|
||||
summary="Get obstacle list")
|
||||
@paginate
|
||||
def obstacle_list(request, filters: Query[BySpaceFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Obstacle, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/obstacles/{obstacle_id}/', response=ObstacleSchema,
|
||||
summary="Get obstacle by ID")
|
||||
def obstacle_detail(request, obstacle_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Obstacle, pk=obstacle_id)
|
||||
|
||||
|
||||
"""
|
||||
LineObstacles
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/lineobstacles/', response=list[LineObstacleSchema],
|
||||
summary="Get line obstacle list")
|
||||
@paginate
|
||||
def lineobstacle_list(request, filters: Query[BySpaceFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=LineObstacle, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/lineobstacles/{lineobstacle_id}/', response=LineObstacleSchema,
|
||||
summary="Get line obstacle by ID")
|
||||
def lineobstacle_detail(request, lineobstacle_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, LineObstacle, pk=lineobstacle_id)
|
||||
|
||||
|
||||
"""
|
||||
Columns
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/columns/', response=list[ColumnSchema],
|
||||
summary="Get column list")
|
||||
@paginate
|
||||
def column_list(request, filters: Query[BySpaceFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=Column, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/columns/{column_id}/', response=ColumnSchema,
|
||||
summary="Get column by ID")
|
||||
def column_detail(request, column_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, Column, pk=column_id)
|
||||
|
||||
|
||||
"""
|
||||
POIs
|
||||
"""
|
||||
|
||||
|
||||
@mapdata_api_router.get('/pois/', response=list[POISchema],
|
||||
summary="Get POI list")
|
||||
@paginate
|
||||
def poi_list(request, filters: Query[BySpaceFilter]):
|
||||
# todo cache?
|
||||
return mapdata_list_endpoint(request, model=POI, filters=filters)
|
||||
|
||||
|
||||
@mapdata_api_router.get('/pois/{poi_id}/', response=POISchema,
|
||||
summary="Get POI by ID")
|
||||
def poi_detail(request, poi_id: int):
|
||||
# todo: access, caching, filtering, etc
|
||||
return mapdata_retrieve_endpoint(request, POI, pk=poi_id)
|
Loading…
Add table
Add a link
Reference in a new issue