add editor API stubs

This commit is contained in:
Laura Klünder 2023-12-01 22:59:57 +01:00
parent 9738ea23ba
commit bf2dd3b33b
6 changed files with 231 additions and 0 deletions

View file

@ -54,6 +54,10 @@ ninja_api = c3navAPI(
"name": "mapdata",
"description": "Access the raw map data",
},
{
"name": "editor",
"description": "Endpoints for the editor and to interface with the editor",
},
{
"name": "mesh",
"description": "Manage the location node mesh network",

View file

@ -36,6 +36,16 @@ class LineStringSchema(Schema):
)
class LineSchema(Schema):
"""
A GeoJSON LineString with only two points
"""
type: Literal["LineString"]
coordinates: tuple[tuple[float, float], tuple[float, float]] = APIField(
example=[[1.5, 1.5], [5, 8.7]]
)
class PointSchema(Schema):
"""
A GeoJSON Point

View file

@ -12,6 +12,7 @@ from c3nav.api.api import SessionViewSet
from c3nav.api.newapi import auth_api_router
from c3nav.api.ninja import ninja_api
from c3nav.editor.api import ChangeSetViewSet, EditorViewSet
from c3nav.editor.newapi.endpoints import editor_api_router
from c3nav.mapdata.api import (AccessRestrictionGroupViewSet, AccessRestrictionViewSet, AreaViewSet, BuildingViewSet,
ColumnViewSet, CrossDescriptionViewSet, DoorViewSet, DynamicLocationPositionViewSet,
HoleViewSet, LeaveDescriptionViewSet, LevelViewSet, LineObstacleViewSet,
@ -34,6 +35,7 @@ ninja_api.add_router("/map/", map_api_router)
ninja_api.add_router("/routing/", routing_api_router)
ninja_api.add_router("/positioning/", positioning_api_router)
ninja_api.add_router("/mapdata/", mapdata_api_router)
ninja_api.add_router("/editor/", editor_api_router)
ninja_api.add_router("/mesh/", mesh_api_router)

View file

View file

@ -0,0 +1,111 @@
from datetime import datetime
from typing import Annotated, Optional, Literal, Union
from django.db import IntegrityError, transaction
from ninja import Field as APIField
from ninja import Query
from ninja import Router as APIRouter
from ninja import Schema, UploadedFile
from ninja.pagination import paginate
from pydantic import PositiveInt, field_validator
from c3nav.api.exceptions import API404, APIConflict, APIRequestValidationFailed
from c3nav.api.newauth import APITokenAuth, auth_permission_responses, auth_responses, validate_responses
from c3nav.api.schema import GeometrySchema, LineSchema
from c3nav.api.utils import NonEmptyStr
from c3nav.editor.newapi.schemas import GeometryStylesSchema, EditorID, EditorSpaceGeometriesElemSchema, \
EditorLevelGeometriesElemSchema, UpdateCacheKey
from c3nav.mapdata.models import Source
from c3nav.mapdata.newapi.base import newapi_etag
from c3nav.mapdata.schemas.responses import BoundsSchema
from c3nav.mesh.dataformats import BoardType, ChipType, FirmwareImage
from c3nav.mesh.messages import MeshMessageType
from c3nav.mesh.models import FirmwareBuild, FirmwareVersion, NodeMessage
editor_api_router = APIRouter(tags=["editor"], auth=APITokenAuth(permissions={"editor_access"}))
@editor_api_router.get('/bounds/', summary="Get editor map boundaries",
response={200: BoundsSchema, **auth_permission_responses})
@newapi_etag()
def bounds(request):
return {
"bounds": Source.max_bounds(),
}
@editor_api_router.get('/geometrystyles/', summary="get the default colors for each geometry type",
response={200: GeometryStylesSchema, **auth_permission_responses})
@newapi_etag(permissions=False)
def geometrystyles():
return {
'building': '#aaaaaa',
'space': '#eeeeee',
'hole': 'rgba(255, 0, 0, 0.3)',
'door': '#ffffff',
'area': '#55aaff',
'stair': '#a000a0',
'ramp': 'rgba(160, 0, 160, 0.2)',
'obstacle': '#999999',
'lineobstacle': '#999999',
'column': 'rgba(0, 0, 50, 0.3)',
'poi': '#4488cc',
'shadow': '#000000',
'graphnode': '#009900',
'graphedge': '#00CC00',
'altitudemarker': '#0000FF',
'wifimeasurement': '#DDDD00',
'rangingbeacon': '#CC00CC',
}
@editor_api_router.get('/geometries/space/{space_id}/', summary="get the geometries to display for a space",
response={200: list[EditorSpaceGeometriesElemSchema], **API404.dict(),
**auth_permission_responses})
@newapi_etag() # todo: correct?
def space_geometries(space_id: EditorID, update_cache_key: UpdateCacheKey = None):
"""
look. this is a complex mess. there will hopefully be more documentation soon. or a better endpoint.
"""
raise NotImplementedError
@editor_api_router.get('/geometries/level/{level_id}/', summary="get the geometries to display for a level",
response={200: list[EditorLevelGeometriesElemSchema], **API404.dict(),
**auth_permission_responses})
@newapi_etag() # todo: correct?
def level_geometries(level_id: EditorID, update_cache_key: UpdateCacheKey = None):
"""
look. this is a complex mess. there will hopefully be more documentation soon. or a better endpoint.
"""
raise NotImplementedError
# todo: need a way to pass the changeset if it's not a session API key
@editor_api_router.get('/{path:path}/', summary="access the editor UI programmatically",
response={200: dict, **API404.dict(), **auth_permission_responses})
@newapi_etag() # todo: correct?
def view_as_api(path: str):
"""
get editor views rendered as JSON instead of HTML.
`path` is the path after /editor/.
this is a mess. good luck. if you actually want to use this, poke us so we might add better documentation.
"""
raise NotImplementedError
@editor_api_router.post('/{path:path}/', summary="access the editor UI programmatically",
response={200: dict, **API404.dict(), **auth_permission_responses})
@newapi_etag() # todo: correct?
def view_as_api(path: str):
"""
get editor views rendered as JSON instead of HTML.
`path` is the path after /editor/.
this is a mess. good luck. if you actually want to use this, poke us so we might add better documentation.
"""
raise NotImplementedError

View file

@ -0,0 +1,104 @@
from typing import Annotated, Union, Literal, Optional
from ninja import Schema
from pydantic import Field as APIField, PositiveInt
from c3nav.api.schema import LineSchema, GeometrySchema
from c3nav.api.utils import NonEmptyStr
GeometryStylesSchema = Annotated[
dict[
Annotated[str, APIField(title="feature type")],
Annotated[str, APIField(title="color")]
],
APIField(description="mapping with a color for each feature type")
]
EditorID = Union[
Annotated[PositiveInt, APIField(title="an existing object that might have been modified in this changeset")],
Annotated[str, APIField(pattern="^c:[0-9]+$", title="an object that was created in this changeset")],
]
EditorGeometriesUpdateCacheKeyElem = Annotated[
tuple[
Literal["update_cache_key"],
Annotated[NonEmptyStr, APIField(title="the new cache key")],
],
APIField(
title="new cache key", # todo better explanation
description="the first element of the list, it informs you of the cache key to store these geometries under"
)
]
EditorGeometriesCacheReferenceElem = Annotated[
tuple[
Annotated[NonEmptyStr, APIField(title="geometry type")],
Annotated[EditorID, APIField(title="geometry id")], # this could be an editor id, right?
],
APIField(
title="reference to a cached geometry", # todo better explanation
description="replaces an element that has not changed from the cache key you supplied. get it from your cache."
)
]
class BaseEditorGeometriesPropertiesSchema(Schema):
id: EditorID
type: NonEmptyStr
bounds: bool = False
color: Optional[str] = None
opacity: Optional[float] = None # todo: range
class EditorGeometriesGraphEdgePropertiesSchema(Schema):
id: EditorID
type: Literal["graphedge"]
from_node: EditorID
to_node: EditorID
class EditorSpaceGeometriesPropertiesSchema(BaseEditorGeometriesPropertiesSchema):
space: EditorID
class EditorLevelGeometriesPropertiesSchema(BaseEditorGeometriesPropertiesSchema):
level: EditorID
class EditorGeometriesGraphEdgeElemSchema(Schema):
type: Literal["Feature"]
properties: EditorGeometriesGraphEdgePropertiesSchema
geometry: LineSchema
class BaseEditorGeometriesGeometryElemSchema(Schema):
type: Literal["Feature"]
geometry: GeometrySchema = APIField(description="geometry, potentially modified for displaying")
original_geometry: Optional[GeometrySchema] = APIField(
default=None,
description="original unchanged geometry, not modified, original(??)", # todo: more precise
)
class EditorSpaceGeometriesGeometryElemSchema(BaseEditorGeometriesGeometryElemSchema):
properties: EditorSpaceGeometriesPropertiesSchema
class EditorLevelGeometriesGeometryElemSchema(BaseEditorGeometriesGeometryElemSchema):
properties: EditorLevelGeometriesPropertiesSchema
EditorSpaceGeometriesElemSchema = Union[
EditorGeometriesUpdateCacheKeyElem,
Annotated[EditorSpaceGeometriesGeometryElemSchema, APIField(title="a geometry object")],
Annotated[EditorGeometriesGraphEdgeElemSchema, APIField(title="a graph edge")],
EditorGeometriesCacheReferenceElem,
]
EditorLevelGeometriesElemSchema = Union[
EditorGeometriesUpdateCacheKeyElem,
Annotated[EditorLevelGeometriesGeometryElemSchema, APIField(title="a geometry object")],
Annotated[EditorGeometriesGraphEdgeElemSchema, APIField(title="a graph edge")],
EditorGeometriesCacheReferenceElem,
]
UpdateCacheKey = Annotated[
Optional[NonEmptyStr],
APIField(default=None, pattern="^c:[0-9]+$", title="the cache key under which you have cached objects"),
]