diff --git a/src/api/urls.py b/src/api/urls.py index 021b15c2824e580104570fce3ea18d7d3925368e..d10c632e9ea06adbb8e5905bf619a5fbd03f60ee 100644 --- a/src/api/urls.py +++ b/src/api/urls.py @@ -41,6 +41,7 @@ urlpatterns = [ path('event/<uuid:pk>/', events.EventDetail.as_view(), name='event-detail'), path('event/<uuid:pk>/schedule', schedule.EventSchedule.as_view(), name='event-schedule'), # integration with other components + path('integration/c3nav', maps.C3NavExportView.as_view(), name='c3nav'), path('integration/is_angel/<str:username>', conferencemember.AngelView.as_view(), name='user-angel'), ] diff --git a/src/api/views/maps.py b/src/api/views/maps.py index 509deb13888d41ad24139ebf3fd72948a9aa15e8..6b90e250eed73460783ffa3f4f4392591744713c 100644 --- a/src/api/views/maps.py +++ b/src/api/views/maps.py @@ -1,6 +1,7 @@ import abc import json +from rest_framework.response import Response from rest_framework.views import APIView from django.contrib.gis.gdal import CoordTransform, SpatialReference @@ -9,6 +10,7 @@ from core.models.assemblies import Assembly from core.models.conference import ConferenceExportCache from core.models.map import MapPOI +from ..permissions import IsConferenceService, IsSuperUser from .mixins import ConferenceSlugMixin _cts = {} # cache of CoordTransforms (if needed) @@ -83,7 +85,7 @@ class AssembliesExportView(ConferenceSlugMixin, APIView, metaclass=abc.ABCMeta): 'features': features, } - for assembly in self.get_queryset().prefetch_related('parent').all(): + for assembly in self.get_queryset().select_related('parent').all(): geometry = self.get_geometry_field(assembly) if geometry is None: continue @@ -124,3 +126,50 @@ class AssembliesPoiExportView(AssembliesExportView): class AssembliesAreasExportView(AssembliesExportView): geometry_field = 'location_boundaries' + + +class C3NavExportView(ConferenceSlugMixin, APIView): + permission_classes = [IsConferenceService | IsSuperUser] + required_service_classes = ['c3nav'] + + def get(self, request, *args, **kwargs): + from core.templatetags.hub_absolute import hub_absolute + + data = [] + + exportable_states = [*Assembly.PLACED_STATES, Assembly.State.HIDDEN] + qs = self.conference.assemblies.filter(state_assembly__in=exportable_states) + if request.GET.get('all') != '1': + qs = qs.exclude(location_point=None, location_boundaries=None) + for assembly in qs: # type: Assembly + data.append( + { + 'type': 'assembly', + 'id': str(assembly.pk), + 'slug': assembly.slug, + 'name': assembly.name, + 'is_official': assembly.is_official, + 'description': {'de': assembly.description_de, 'en': assembly.description_en}, + 'public_url': hub_absolute('plainui:assembly', assembly_slug=assembly.slug), + 'parent_id': assembly.parent_id, + 'children': assembly.children.filter(state_assembly__in=exportable_states).values_list('slug', flat=True) if assembly.is_cluster else None, + 'floor': assembly.get_location_floor_index(), + 'location': assembly.get_location_point_xy(), + 'polygons': assembly.get_location_boundaries_xy(), + } + ) + + for poi in self.conference.pois.filter(visible=True): # type: MapPOI + data.append( + { + 'type': 'poi', + 'id': str(poi.pk), + 'name': {'de': poi.name_de, 'en': poi.name_en}, + 'is_official': poi.is_official, + 'description': {'de': poi.description_de, 'en': poi.description_en}, + 'floor': poi.get_location_floor_index(), + 'location': poi.get_location_point_xy(), + } + ) + + return Response(data) diff --git a/src/core/models/assemblies.py b/src/core/models/assemblies.py index 866511090032e889af6f766569ac43a678844d15..529b912d57583a36c7dbd7488a628de636ab2ace 100644 --- a/src/core/models/assemblies.py +++ b/src/core/models/assemblies.py @@ -535,21 +535,28 @@ class Assembly(TaggedItemMixin, models.Model): def get_location_floor_index(self): return self.location_floor.index if self.location_floor else None - def get_location_point_as_json(self): + def get_location_point_xy(self): + """Get the location_point's X/Y coordinate as array of (two) floats, if it's a valid coordinate - return None otherwise.""" if not self.location_point or not self.location_point.valid: - return '' + return None - return json.dumps([self.location_point.x, self.location_point.y]) + return [self.location_point.x, self.location_point.y] - def get_location_boundaries_as_json(self): + def get_location_point_as_json(self): + return json.dumps(self.get_location_point_xy() or '') + + def get_location_boundaries_xy(self): if not self.location_boundaries or not self.location_boundaries.valid: - return '' + return None polygons = [] for multipolygon in self.location_boundaries: for polygon in multipolygon: - polygons.append(polygon.array) - return json.dumps(polygons) + polygons.append(list([x[0], x[1]] for x in polygon.array)) + return polygons + + def get_location_boundaries_as_json(self): + return json.dumps(self.get_location_boundaries_xy() or '') def log_activity(self, user: Optional[PlatformUser], kind: str, message: Optional[str] = None, changes: Optional[dict] = None): self.logentries.create(user=user, kind=kind, comment=message, changes=changes) diff --git a/src/core/models/map.py b/src/core/models/map.py index aa991af12997e4a00233dc6cd8c6ac14045cc786..84c329866d33b05d59ea0eff08a18dbe64366258 100644 --- a/src/core/models/map.py +++ b/src/core/models/map.py @@ -84,8 +84,12 @@ class MapPOI(models.Model): def get_location_floor_index(self): return self.location_floor.index if self.location_floor else None - def get_location_point_as_json(self): + def get_location_point_xy(self): + """Get the location_point's X/Y coordinate as array of (two) floats, if it's a valid coordinate - return None otherwise.""" if not self.location_point or not self.location_point.valid: - return '' + return None + + return [self.location_point.x, self.location_point.y] - return json.dumps([self.location_point.x, self.location_point.y]) + def get_location_point_as_json(self): + return json.dumps(self.get_location_point_xy() or '')