diff --git a/src/api/urls.py b/src/api/urls.py index 134284a302458cd31184e8db3835cfe7ccc0827d..52c110c8e372dc43740ec9b4575be67e1ed5c5d0 100644 --- a/src/api/urls.py +++ b/src/api/urls.py @@ -3,7 +3,7 @@ from rest_framework.urlpatterns import format_suffix_patterns from rest_framework.authtoken import views as authtoken_views from .views import api_root -from .views import assemblies, badges, bbb, conferencemember, conferences, events, rooms, schedule, users, workadventure +from .views import assemblies, badges, bbb, conferencemember, conferences, events, maps, rooms, schedule, users, workadventure app_name = 'api' @@ -29,6 +29,8 @@ urlpatterns = [ path('c/<slug:conference>/assembly/<slug:assembly>/rooms', assemblies.ConferenceAssemblyRoomList.as_view(), name='assembly-rooms'), path('c/<slug:conference>/assembly/<slug:assembly>/schedule', schedule.AssemblySchedule.as_view(), name='assembly-schedule'), path('c/<slug:conference>/assembly/<slug:assembly>/badges/new_redeem_token', badges.create_redeem_token, name='create-badge-redeem'), + path('c/<slug:conference>/map/assemblies/poi.json', maps.AssembliesPoiExportView.as_view(), name='map-assemblies-poi'), + path('c/<slug:conference>/map/assemblies/areas.json', maps.AssembliesAreasExportView.as_view(), name='map-assemblies-areas'), path('c/<slug:conference>/badges/redeem_token', badges.redeem_badge_token, name='badge-redeem'), path('c/<slug:conference>/badges/redeem_map_token', badges.RedeemBadgeMapTokenView.as_view(), name='badge-map-redeem'), path('c/<slug:conference>/rooms', rooms.ConferenceRoomList.as_view(), name='room-list'), diff --git a/src/api/views/maps.py b/src/api/views/maps.py new file mode 100644 index 0000000000000000000000000000000000000000..0ec3153cffce8a79039ba392097e87ef71edb410 --- /dev/null +++ b/src/api/views/maps.py @@ -0,0 +1,81 @@ +import abc +import json + +from django.contrib.gis.gdal import SpatialReference, CoordTransform +from rest_framework.views import APIView + +from core.models.assemblies import Assembly +from core.models.conference import ConferenceExportCache +from .mixins import ConferenceSlugMixin + + +class AssembliesExportView(ConferenceSlugMixin, APIView, metaclass=abc.ABCMeta): + geometry_field = None + _cts = {} # cache of CoordTransforms (if needed) + + def get_queryset(self): + return Assembly.objects.filter(conference=self.conference, state_assembly__in=Assembly.PLACED_STATES) + + @staticmethod + def get_field_geojson(value, srid: int, ct_cache: dict = None): + if value.srid != srid: + if ct_cache is None: + ct_cache = {} + if value.srid not in ct_cache: + srs = SpatialReference(srid) + ct_cache[value.srid] = CoordTransform(value.srs, srs) + value.transform(ct_cache[value.srid]) + return json.loads(value.geojson) + + def get_geometry_field(self, obj): + return getattr(obj, self.geometry_field) + + def get_geojson(self): + srid = 4326 # RFC7946 mandates WGS84 + ct_cache = {} + features = [] + result = { + 'type': 'FeatureCollection', + # 'crs': {'type': 'name', 'properties': {'name': f'EPSG:{srid}'}}, # deprecated, not in RFC7946 + 'features': features, + } + + for assembly in self.get_queryset().prefetch_related('parent').all(): + geometry = self.get_geometry_field(assembly) + if geometry is None: + continue + + feature = { + 'type': 'Feature', + 'id': assembly.slug, + 'geometry': self.get_field_geojson(geometry, srid=srid, ct_cache=ct_cache), + 'properties': { + 'name': assembly.name, + 'official': assembly.is_official, + 'cluster': assembly.is_cluster, + 'parent': assembly.parent.slug if assembly.parent else None, + }, + } + features.append(feature) + + return result + + def get(self, request, *args, **kwargs): + cache_id = 'geojson-' + self.geometry_field + + return ConferenceExportCache.handle_http_request( + request=request, + conference=self.conference, + type=ConferenceExportCache.Type.MAP, + ident=cache_id, + content_type='application/geo+json', + result_func=lambda: json.dumps(self.get_geojson()), + ) + + +class AssembliesPoiExportView(AssembliesExportView): + geometry_field = 'location_point' + + +class AssembliesAreasExportView(AssembliesExportView): + geometry_field = 'location_boundaries'