fix etag_add feature and overlay stuff and generated api naming thing
This commit is contained in:
parent
2063b715e7
commit
393637b6ad
3 changed files with 29 additions and 23 deletions
|
@ -49,6 +49,18 @@ def api_etag(permissions=True, quests=False, etag_func=AccessPermission.etag_fun
|
|||
raw_etag += 'all' if request.user.is_superuser else f':{','.join(request.user_permissions.quests)}'
|
||||
if base_mapdata:
|
||||
raw_etag += ':%d' % request.user_permissions.can_access_base_mapdata
|
||||
|
||||
if etag_add_key:
|
||||
etag_add_cache_key = (
|
||||
f'mapdata:etag_add:{etag_add_key[1]}:{getattr(kwargs[etag_add_key[0]], etag_add_key[1])}'
|
||||
)
|
||||
etag_add = cache.get(etag_add_cache_key, None)
|
||||
if etag_add is None:
|
||||
etag_add = int(time.time())
|
||||
cache.set(etag_add_cache_key, etag_add, 300)
|
||||
raw_etag += ':%d' % etag_add
|
||||
|
||||
|
||||
etag = quote_etag(raw_etag)
|
||||
|
||||
response = get_conditional_response(request, etag)
|
||||
|
@ -68,19 +80,9 @@ def api_etag(permissions=True, quests=False, etag_func=AccessPermission.etag_fun
|
|||
value = model_dump()
|
||||
data[name] = value
|
||||
|
||||
etag_add = ''
|
||||
if etag_add_key:
|
||||
etag_add_cache_key = (
|
||||
f'mapdata:etag_add:{etag_add_key[1]}:{getattr(kwargs[etag_add_key[0]], etag_add_key[1])}'
|
||||
)
|
||||
etag_add = cache.get(etag_add_cache_key, None)
|
||||
if etag_add is None:
|
||||
etag_add = int(time.time())
|
||||
cache.set(etag_add_cache_key, etag_add, 300)
|
||||
cache_key = 'mapdata:api:%s:%s:%s:%s' % (
|
||||
cache_key = 'mapdata:api:%s:%s:%s' % (
|
||||
request.resolver_match.route.replace('/', '-').strip('-'),
|
||||
raw_etag,
|
||||
etag_add,
|
||||
json.dumps(data, separators=(',', ':'), sort_keys=True, cls=DjangoJSONEncoder),
|
||||
)
|
||||
|
||||
|
|
|
@ -80,6 +80,12 @@ class MapdataEndpoint:
|
|||
schema: Type[BaseSchema]
|
||||
filters: Type[FilterSchema] | None = None
|
||||
no_cache: bool = False
|
||||
|
||||
# etag_add_key is a weird, limited and hacky solution to add cache/etag invalidation for data that can be changed without triggering mapupdate
|
||||
# if set, its value *must* be the name of an attribute in the filter schema, and the value of that filter will be used in the etag/cache key
|
||||
# all api endpoints that have the same etag_add_key value have shared cache/etag invalidation, i.e. if one is invalidated then all are
|
||||
# the cache is invalidated by deleting the cache key "mapdata:etag_add:<etag_add_key>:<filter-value>" where filter-value is the value of the
|
||||
# filter attribute that etag_add_key references
|
||||
etag_add_key: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
|
||||
|
@ -91,6 +97,10 @@ class MapdataEndpoint:
|
|||
def endpoint_name(self):
|
||||
return self.name if self.name is not None else self.model._meta.default_related_name
|
||||
|
||||
@property
|
||||
def endpoint_operation_name(self):
|
||||
return self.name if self.name is not None else self.model_name
|
||||
|
||||
|
||||
@dataclass
|
||||
class MapdataAPIBuilder:
|
||||
|
@ -142,7 +152,8 @@ class MapdataAPIBuilder:
|
|||
call_func=mapdata_list_endpoint,
|
||||
add_call_params={"model": endpoint.model.__name__}
|
||||
)
|
||||
list_func.__name__ = f"{endpoint.model_name}_list"
|
||||
list_func.__name__ = f"{endpoint.endpoint_operation_name}_list"
|
||||
|
||||
|
||||
if not endpoint.no_cache:
|
||||
list_func = api_etag(
|
||||
|
@ -168,7 +179,7 @@ class MapdataAPIBuilder:
|
|||
call_func=mapdata_retrieve_endpoint,
|
||||
add_call_params={"model": endpoint.model.__name__, "pk": id_field}
|
||||
)
|
||||
list_func.__name__ = f"{endpoint.model_name}_by_id"
|
||||
list_func.__name__ = f"{endpoint.endpoint_operation_name}_by_id"
|
||||
|
||||
self.router.get(f'/{endpoint.endpoint_name}/{{{id_field}}}/', summary=f"{endpoint.model_name} by ID",
|
||||
tags=[f"mapdata-{tag}"], description=schema_description(endpoint.schema),
|
||||
|
@ -243,7 +254,6 @@ mapdata_endpoints: dict[str, list[MapdataEndpoint]] = {
|
|||
model=DataOverlayFeature,
|
||||
schema=DataOverlayFeatureGeometrySchema,
|
||||
filters=ByOverlayFilter,
|
||||
etag_add_key="overlay",
|
||||
name='dataoverlayfeaturegeometries'
|
||||
),
|
||||
MapdataEndpoint(
|
||||
|
@ -325,13 +335,9 @@ mapdata_endpoints: dict[str, list[MapdataEndpoint]] = {
|
|||
MapdataAPIBuilder(router=mapdata_api_router).build_all_endpoints(mapdata_endpoints)
|
||||
|
||||
|
||||
@mapdata_api_router.post('/dataoverlayfeatures/{id}', summary="update a data overlay feature (including geometries)",
|
||||
@mapdata_api_router.post('/dataoverlayfeatures/{id}', summary="update a data overlay feature (no geometries)",
|
||||
response={204: None, **API404.dict(), **auth_permission_responses})
|
||||
def update_data_overlay_feature(request, id: int, parameters: DataOverlayFeatureUpdateSchema):
|
||||
"""
|
||||
update the data overlay feature
|
||||
"""
|
||||
|
||||
feature = get_object_or_404(DataOverlayFeature, id=id)
|
||||
|
||||
if feature.overlay.edit_access_restriction_id is None or feature.overlay.edit_access_restriction_id not in AccessPermission.get_for_request(
|
||||
|
@ -350,7 +356,7 @@ def update_data_overlay_feature(request, id: int, parameters: DataOverlayFeature
|
|||
return 204, None
|
||||
|
||||
|
||||
@mapdata_api_router.post('/dataoverlayfeatures-bulk', summary="bulk-update data overlays (including geometries)",
|
||||
@mapdata_api_router.post('/dataoverlayfeatures-bulk', summary="bulk-update data overlays (no geometries)",
|
||||
response={204: None, **API404.dict(), **auth_permission_responses})
|
||||
def update_data_overlay_features_bulk(request, parameters: DataOverlayFeatureBulkUpdateSchema):
|
||||
permissions = AccessPermission.get_for_request(request)
|
||||
|
|
|
@ -408,7 +408,6 @@ class DataOverlayFeatureUpdateSchema(BaseSchema):
|
|||
An update to a data overlay feature.
|
||||
"""
|
||||
level_id: Optional[PositiveInt] = None
|
||||
geometry: Optional[AnyGeometrySchema] = None
|
||||
stroke_color: Optional[str] = None
|
||||
stroke_width: Optional[float] = None
|
||||
stroke_opacity: Optional[float] = None
|
||||
|
@ -423,11 +422,10 @@ class DataOverlayFeatureUpdateSchema(BaseSchema):
|
|||
|
||||
class DataOverlayFeatureBulkUpdateItemSchema(BaseSchema):
|
||||
"""
|
||||
An item of a bulk update to data overlay features.
|
||||
An item of a bulk update to data overlay features (no geometries).
|
||||
"""
|
||||
id: PositiveInt
|
||||
level_id: Optional[PositiveInt] = None
|
||||
geometry: Optional[AnyGeometrySchema] = None
|
||||
stroke_color: Optional[str] = None
|
||||
stroke_width: Optional[float] = None
|
||||
stroke_opacity: Optional[float] = None
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue