From 93f70fa0b8d618926a023190947e2d4c90d0e2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Sun, 3 Dec 2023 19:25:44 +0100 Subject: [PATCH] add fetch_updates api v2 endpoint --- src/c3nav/api/ninja.py | 7 ++- src/c3nav/api/urls.py | 2 + src/c3nav/mapdata/newapi/updates.py | 71 +++++++++++++++++++++++++++++ src/c3nav/mapdata/utils/user.py | 4 +- 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/c3nav/mapdata/newapi/updates.py diff --git a/src/c3nav/api/ninja.py b/src/c3nav/api/ninja.py index ed0d4813..879cb87b 100644 --- a/src/c3nav/api/ninja.py +++ b/src/c3nav/api/ninja.py @@ -57,14 +57,17 @@ ninja_api = c3navAPI( auth=APITokenAuth(), openapi_extra={ - - "tags": [ { "name": "auth", "x-displayName": "Authentication", "description": "Get and manage API access", }, + { + "name": "updates", + "x-displayName": "Updates", + "description": "Get regular updates", + }, { "name": "map", "x-displayName": "Map access", diff --git a/src/c3nav/api/urls.py b/src/c3nav/api/urls.py index f55bffc4..bb91fd9f 100644 --- a/src/c3nav/api/urls.py +++ b/src/c3nav/api/urls.py @@ -21,6 +21,7 @@ from c3nav.mapdata.api import (AccessRestrictionGroupViewSet, AccessRestrictionV SpaceViewSet, StairViewSet, UpdatesViewSet) from c3nav.mapdata.newapi.map import map_api_router from c3nav.mapdata.newapi.mapdata import mapdata_api_router +from c3nav.mapdata.newapi.updates import updates_api_router from c3nav.mapdata.utils.user import can_access_editor from c3nav.mesh.newapi import mesh_api_router from c3nav.routing.api import RoutingViewSet @@ -31,6 +32,7 @@ from c3nav.routing.newapi.routing import routing_api_router new API (v2) """ ninja_api.add_router("/auth/", auth_api_router) +ninja_api.add_router("/updates/", updates_api_router) ninja_api.add_router("/map/", map_api_router) ninja_api.add_router("/routing/", routing_api_router) ninja_api.add_router("/positioning/", positioning_api_router) diff --git a/src/c3nav/mapdata/newapi/updates.py b/src/c3nav/mapdata/newapi/updates.py new file mode 100644 index 00000000..8eecff8c --- /dev/null +++ b/src/c3nav/mapdata/newapi/updates.py @@ -0,0 +1,71 @@ +from typing import Optional +from urllib.parse import urlparse + +from django.http import HttpResponse +from ninja import Router as APIRouter +from ninja import Schema +from pydantic import PositiveInt + +from c3nav.api.newauth import auth_responses +from c3nav.api.utils import NonEmptyStr +from c3nav.mapdata.models import MapUpdate +from c3nav.mapdata.newapi.base import newapi_etag +from c3nav.mapdata.schemas.responses import BoundsSchema +from c3nav.mapdata.utils.cache.stats import increment_cache_key +from c3nav.mapdata.utils.user import get_user_data +from c3nav.mapdata.views import set_tile_access_cookie + +updates_api_router = APIRouter(tags=["updates"]) + + +class UserDataSchema(Schema): + logged_in: bool + allow_editor: bool + allow_control_panel: bool + has_positions: bool + title: NonEmptyStr + subtitle: NonEmptyStr + permissions: list[PositiveInt] + + +class FetchUpdatesResponseSchema(Schema): + last_site_update: PositiveInt + last_map_update: NonEmptyStr + user: Optional[UserDataSchema] = None + + +@updates_api_router.get('/fetch/', summary="fetch updates", + description="get regular updates.\n\n" + "this endpoint also sets/updates the tile access cookie." + "if not called regularly, the tileserver will ignore your access permissions.\n\n" + "this endpoint can be called cross-origin, but it will have no user data then.", + response={200: FetchUpdatesResponseSchema, **auth_responses}) +@newapi_etag(permissions=False) +def fetch_updates(request, response: HttpResponse): + cross_origin = request.META.get('HTTP_ORIGIN') + if cross_origin is not None: + try: + if request.META['HTTP_HOST'] == urlparse(cross_origin).hostname: + cross_origin = None + except ValueError: + pass + + increment_cache_key('api_updates_fetch_requests%s' % ('_cross_origin' if cross_origin is not None else '')) + + from c3nav.site.models import SiteUpdate + + result = { + 'last_site_update': SiteUpdate.last_update(), + 'last_map_update': MapUpdate.current_processed_cache_key(), + } + if cross_origin is None: + result.update({ + 'user': get_user_data(request), + }) + + if cross_origin is not None: + response['Access-Control-Allow-Origin'] = cross_origin + response['Access-Control-Allow-Credentials'] = 'true' + set_tile_access_cookie(request, response) + + return response diff --git a/src/c3nav/mapdata/utils/user.py b/src/c3nav/mapdata/utils/user.py index 2e5d402d..55c7b01d 100644 --- a/src/c3nav/mapdata/utils/user.py +++ b/src/c3nav/mapdata/utils/user.py @@ -17,13 +17,13 @@ def get_user_data(request): } if permissions: result.update({ - 'title': _('not logged in'), + 'title': str(_('not logged in')), 'subtitle': ngettext_lazy('%d area unlocked', '%d areas unlocked', len(permissions)) % len(permissions), 'permissions': tuple(permissions), }) else: result.update({ - 'title': _('Login'), + 'title': str(_('Login')), 'subtitle': None, 'permissions': (), })