From 36ab9efd804023fc323e78028518784cd55a60b8 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Mon, 10 Feb 2025 10:46:26 +0100 Subject: [PATCH 01/14] Add mobile API endpoint for sensitive areas --- geotrek/api/mobile/serializers/sensitivity.py | 33 +++++++++++++++++++ geotrek/api/mobile/views/trekking.py | 12 ++++++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 geotrek/api/mobile/serializers/sensitivity.py diff --git a/geotrek/api/mobile/serializers/sensitivity.py b/geotrek/api/mobile/serializers/sensitivity.py new file mode 100644 index 0000000000..a4ae82c3f9 --- /dev/null +++ b/geotrek/api/mobile/serializers/sensitivity.py @@ -0,0 +1,33 @@ +from django.conf import settings +from rest_framework import serializers +from rest_framework_gis import serializers as geo_serializers + + +if 'geotrek.sensitivity' in settings.INSTALLED_APPS: + from geotrek.sensitivity import models as sensitivity_models + + class SensitiveAreaListSerializer(geo_serializers.GeoFeatureModelSerializer): + geometry = geo_serializers.GeometryField(read_only=True, precision=7, source='geom2d_transformed') + name = serializers.ReadOnlyField(source='species.name') + description = serializers.ReadOnlyField() + species_id = serializers.SerializerMethodField(source='species.pk') + practices = serializers.PrimaryKeyRelatedField(many=True, source='species.practices', read_only=True) + info_url = serializers.URLField(source='species.url') + period = serializers.SerializerMethodField() + + class Meta: + model = sensitivity_models.SensitiveArea + id_field = 'pk' + geo_field = 'geometry' + fields = ( + 'id', 'pk', 'name', 'description', 'species_id', 'practices', + 'contact', 'info_url', 'period', 'geometry', + ) + + def get_species_id(self, obj): + if obj.species.category == sensitivity_models.Species.SPECIES: + return obj.species_id + return None + + def get_period(self, obj): + return [getattr(obj.species, 'period{:02}'.format(p)) for p in range(1, 13)] diff --git a/geotrek/api/mobile/views/trekking.py b/geotrek/api/mobile/views/trekking.py index 526c604e34..c41838327a 100644 --- a/geotrek/api/mobile/views/trekking.py +++ b/geotrek/api/mobile/views/trekking.py @@ -6,7 +6,7 @@ from rest_framework.permissions import AllowAny from rest_framework_extensions.mixins import DetailSerializerMixin -from geotrek.api.mobile.serializers import trekking as api_serializers_trekking, tourism as api_serializers_tourism +from geotrek.api.mobile.serializers import trekking as api_serializers_trekking, tourism as api_serializers_tourism, sensitivity as api_serializers_sensitivity from geotrek.common.functions import StartPoint, EndPoint from geotrek.trekking import models as trekking_models @@ -71,3 +71,13 @@ def touristic_events(self, request, *args, **kwargs): qs = qs.prefetch_related('attachments').annotate(geom2d_transformed=Transform(F('geom'), settings.API_SRID)) data = api_serializers_tourism.TouristicEventListSerializer(qs, many=True, context={'root_pk': root_pk}).data return response.Response(data) + + @decorators.action(detail=True, methods=['get']) + def sensitive_areas(self, request, *args, **kwargs): + trek = self.get_object() + root_pk = self.request.GET.get('root_pk') or trek.pk + qs = trek.sensitive_areas.filter(published=True) \ + .prefetch_related('species') \ + .annotate(geom2d_transformed=Transform(F('geom'), settings.API_SRID)).order_by('pk') + data = api_serializers_sensitivity.SensitiveAreaListSerializer(qs, many=True, context={'root_pk': root_pk}).data + return response.Response(data) From ba50d64bbdda50ce2a2c2b98796714e699e58c56 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Tue, 11 Feb 2025 12:02:10 +0100 Subject: [PATCH 02/14] Add sensitive area pratices to mobile API SettingsView --- geotrek/api/mobile/serializers/common.py | 9 +++++++++ geotrek/api/mobile/views/common.py | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/geotrek/api/mobile/serializers/common.py b/geotrek/api/mobile/serializers/common.py index e4806f4fe1..d14a29432f 100644 --- a/geotrek/api/mobile/serializers/common.py +++ b/geotrek/api/mobile/serializers/common.py @@ -6,6 +6,7 @@ from geotrek.common import models as common_models from geotrek.trekking import models as trekking_models +from geotrek.sensitivity import models as sensitivity_models if 'geotrek.zoning' in settings.INSTALLED_APPS: @@ -179,6 +180,14 @@ class Meta: model = trekking_models.POIType fields = ('id', 'label', 'pictogram') +if 'geotrek.sensitivity' in settings.INSTALLED_APPS: + + class SportPracticeSerializer(serializers.ModelSerializer): + + class Meta: + model = sensitivity_models.SportPractice + fields = ('id', 'name') + class MobileMenuItemListSerializer(serializers.Serializer): diff --git a/geotrek/api/mobile/views/common.py b/geotrek/api/mobile/views/common.py index 193f0b09c0..587d2b5e8d 100644 --- a/geotrek/api/mobile/views/common.py +++ b/geotrek/api/mobile/views/common.py @@ -14,6 +14,7 @@ from geotrek.tourism.models import (InformationDesk, InformationDeskType, TouristicContentType, TouristicEventType, TouristicContentCategory) from geotrek.zoning.models import City, District +from geotrek.sensitivity.models import SportPractice class SettingsView(APIView): @@ -199,6 +200,13 @@ def get(self, request, *args, **kwargs): TouristicContentCategory.objects.all().order_by('order'), many=True, context={'request': request}).data, }, + { + 'id': 'sensitive_area_practices', + 'name': _('Sensitive area practices'), + 'values': api_serializers.SportPracticeSerializer( + SportPractice.objects.all().order_by('name'), + many=True, context={'request': request}).data, + } ] }) From 296703597ea6ca131689629de36228c24a2bf529 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Tue, 11 Feb 2025 14:59:46 +0100 Subject: [PATCH 03/14] Remove species_id from SensitiveArea's mobile API serializer --- geotrek/api/mobile/serializers/sensitivity.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/geotrek/api/mobile/serializers/sensitivity.py b/geotrek/api/mobile/serializers/sensitivity.py index a4ae82c3f9..38114eadc0 100644 --- a/geotrek/api/mobile/serializers/sensitivity.py +++ b/geotrek/api/mobile/serializers/sensitivity.py @@ -10,7 +10,6 @@ class SensitiveAreaListSerializer(geo_serializers.GeoFeatureModelSerializer): geometry = geo_serializers.GeometryField(read_only=True, precision=7, source='geom2d_transformed') name = serializers.ReadOnlyField(source='species.name') description = serializers.ReadOnlyField() - species_id = serializers.SerializerMethodField(source='species.pk') practices = serializers.PrimaryKeyRelatedField(many=True, source='species.practices', read_only=True) info_url = serializers.URLField(source='species.url') period = serializers.SerializerMethodField() @@ -20,14 +19,9 @@ class Meta: id_field = 'pk' geo_field = 'geometry' fields = ( - 'id', 'pk', 'name', 'description', 'species_id', 'practices', + 'id', 'pk', 'name', 'description', 'practices', 'contact', 'info_url', 'period', 'geometry', ) - def get_species_id(self, obj): - if obj.species.category == sensitivity_models.Species.SPECIES: - return obj.species_id - return None - def get_period(self, obj): return [getattr(obj.species, 'period{:02}'.format(p)) for p in range(1, 13)] From 6967f65b5a816c1997447b5abacab48af44002d0 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Tue, 11 Feb 2025 15:45:35 +0100 Subject: [PATCH 04/14] Fix import error when sensitivity module is deactivated --- geotrek/api/mobile/serializers/common.py | 2 +- geotrek/api/mobile/views/common.py | 235 ++++++++++++----------- geotrek/api/mobile/views/trekking.py | 24 ++- 3 files changed, 136 insertions(+), 125 deletions(-) diff --git a/geotrek/api/mobile/serializers/common.py b/geotrek/api/mobile/serializers/common.py index d14a29432f..5d9b3853d8 100644 --- a/geotrek/api/mobile/serializers/common.py +++ b/geotrek/api/mobile/serializers/common.py @@ -6,7 +6,6 @@ from geotrek.common import models as common_models from geotrek.trekking import models as trekking_models -from geotrek.sensitivity import models as sensitivity_models if 'geotrek.zoning' in settings.INSTALLED_APPS: @@ -181,6 +180,7 @@ class Meta: fields = ('id', 'label', 'pictogram') if 'geotrek.sensitivity' in settings.INSTALLED_APPS: + from geotrek.sensitivity import models as sensitivity_models class SportPracticeSerializer(serializers.ModelSerializer): diff --git a/geotrek/api/mobile/views/common.py b/geotrek/api/mobile/views/common.py index 587d2b5e8d..ce384ecb2c 100644 --- a/geotrek/api/mobile/views/common.py +++ b/geotrek/api/mobile/views/common.py @@ -14,7 +14,9 @@ from geotrek.tourism.models import (InformationDesk, InformationDeskType, TouristicContentType, TouristicEventType, TouristicContentCategory) from geotrek.zoning.models import City, District -from geotrek.sensitivity.models import SportPractice + +if 'geotrek.sensitivity' in settings.INSTALLED_APPS: + from geotrek.sensitivity.models import SportPractice class SettingsView(APIView): @@ -93,121 +95,126 @@ def get(self, request, *args, **kwargs): "showAllLabel": _("Show all routes"), "hideAllLabel": _("Hide all routes") }) + + data = [ + { + 'id': 'length', + 'name': _('Length'), + 'values': settings.MOBILE_LENGTH_INTERVALS, + }, + { + 'id': 'ascent', + 'name': _('Ascent'), + 'values': settings.MOBILE_ASCENT_INTERVALS, + }, + { + 'id': 'duration', + 'name': _('Duration'), + 'values': settings.MOBILE_DURATION_INTERVALS, + + }, + { + 'id': 'difficulty', + 'name': _('Difficulty'), + 'values': api_serializers.DifficultySerializer(DifficultyLevel.objects.filter( + pk__in=Trek.objects.existing().filter(published=True).values_list('difficulty_id', flat=True) + ).order_by('pk'), many=True, context={'request': request}).data + }, + { + 'id': 'practice', + 'name': _('Practice'), + 'values': api_serializers.PracticeSerializer(Practice.objects.filter( + pk__in=Trek.objects.existing().filter(published=True).values_list('practice_id', flat=True) + ).order_by('order', 'name'), many=True, context={'request': request}).data, + }, + { + 'id': 'accessibilities', + 'name': _('Accessibilities'), + 'values': api_serializers.AccessibilitySerializer(Accessibility.objects.filter( + pk__in=Trek.objects.existing().filter(published=True).values_list('accessibilities', flat=True) + ).order_by('name'), many=True, context={'request': request}).data, + }, + { + 'id': 'route', + 'name': _('Route'), + 'values': api_serializers.RouteSerializer(Route.objects.filter( + pk__in=Trek.objects.existing().filter(published=True).values_list('route_id', flat=True) + ).order_by('route'), many=True, context={'request': request}).data, + }, + { + 'id': 'themes', + 'name': _('Themes'), + 'values': api_serializers.ThemeSerializer(Theme.objects.filter( + pk__in=Trek.objects.existing().filter(published=True).values_list('themes', flat=True) + ).order_by('label'), many=True, context={'request': request}).data, + }, + { + 'id': 'networks', + 'name': _('Networks'), + 'values': api_serializers.NetworkSerializer(TrekNetwork.objects.filter( + pk__in=Trek.objects.existing().filter(published=True).values_list('networks', flat=True) + ).order_by('network'), many=True, context={'request': request}).data, + }, + { + 'id': 'information_desk_types', + 'name': _('Information Desks Types'), + 'values': api_serializers.InformationDeskTypeSerializer(InformationDeskType.objects.filter( + pk__in=InformationDesk.objects.all().values_list('type_id', flat=True) + ).order_by('label'), many=True, context={'request': request}).data, + }, + { + 'id': 'districts', + 'name': _('Districts'), + 'values': api_serializers.DistrictSerializer(District.objects.filter(published=True).order_by('name'), + many=True, context={'request': request}).data + }, + { + 'id': 'cities', + 'name': _('Cities'), + 'values': api_serializers.CitySerializer(City.objects.filter(published=True).order_by('name'), + many=True, context={'request': request}).data + }, + { + 'id': 'poi_types', + 'name': _('POI types'), + 'values': api_serializers.POITypeSerializer(POIType.objects.all().order_by('label'), many=True, + context={'request': request}).data, + }, + { + 'id': 'touristiccontent_types', + 'name': _('Touristic content types'), + 'values': api_serializers.TouristicContentTypeSerializer( + TouristicContentType.objects.all().order_by('label'), + many=True, context={'request': request}).data, + }, + { + 'id': 'touristicevent_types', + 'name': _('Touristic event types'), + 'values': api_serializers.TouristicEventTypeSerializer( + TouristicEventType.objects.all().order_by('type'), + many=True, context={'request': request}).data, + }, + { + 'id': 'touristiccontent_categories', + 'name': _('Touristic event types'), + 'values': api_serializers.TouristicContentCategorySerializer( + TouristicContentCategory.objects.all().order_by('order'), + many=True, context={'request': request}).data, + }, + ] + + if 'geotrek.sensitivity' in settings.INSTALLED_APPS: + data.append({ + 'id': 'sensitive_area_practices', + 'name': _('Sensitive area practices'), + 'values': api_serializers.SportPracticeSerializer( + SportPractice.objects.all().order_by('name'), + many=True, context={'request': request}).data, + }) + return response.Response({ 'filters': filters, - 'data': [ - { - 'id': 'length', - 'name': _('Length'), - 'values': settings.MOBILE_LENGTH_INTERVALS, - }, - { - 'id': 'ascent', - 'name': _('Ascent'), - 'values': settings.MOBILE_ASCENT_INTERVALS, - }, - { - 'id': 'duration', - 'name': _('Duration'), - 'values': settings.MOBILE_DURATION_INTERVALS, - - }, - { - 'id': 'difficulty', - 'name': _('Difficulty'), - 'values': api_serializers.DifficultySerializer(DifficultyLevel.objects.filter( - pk__in=Trek.objects.existing().filter(published=True).values_list('difficulty_id', flat=True) - ).order_by('pk'), many=True, context={'request': request}).data - }, - { - 'id': 'practice', - 'name': _('Practice'), - 'values': api_serializers.PracticeSerializer(Practice.objects.filter( - pk__in=Trek.objects.existing().filter(published=True).values_list('practice_id', flat=True) - ).order_by('order', 'name'), many=True, context={'request': request}).data, - }, - { - 'id': 'accessibilities', - 'name': _('Accessibilities'), - 'values': api_serializers.AccessibilitySerializer(Accessibility.objects.filter( - pk__in=Trek.objects.existing().filter(published=True).values_list('accessibilities', flat=True) - ).order_by('name'), many=True, context={'request': request}).data, - }, - { - 'id': 'route', - 'name': _('Route'), - 'values': api_serializers.RouteSerializer(Route.objects.filter( - pk__in=Trek.objects.existing().filter(published=True).values_list('route_id', flat=True) - ).order_by('route'), many=True, context={'request': request}).data, - }, - { - 'id': 'themes', - 'name': _('Themes'), - 'values': api_serializers.ThemeSerializer(Theme.objects.filter( - pk__in=Trek.objects.existing().filter(published=True).values_list('themes', flat=True) - ).order_by('label'), many=True, context={'request': request}).data, - }, - { - 'id': 'networks', - 'name': _('Networks'), - 'values': api_serializers.NetworkSerializer(TrekNetwork.objects.filter( - pk__in=Trek.objects.existing().filter(published=True).values_list('networks', flat=True) - ).order_by('network'), many=True, context={'request': request}).data, - }, - { - 'id': 'information_desk_types', - 'name': _('Information Desks Types'), - 'values': api_serializers.InformationDeskTypeSerializer(InformationDeskType.objects.filter( - pk__in=InformationDesk.objects.all().values_list('type_id', flat=True) - ).order_by('label'), many=True, context={'request': request}).data, - }, - { - 'id': 'districts', - 'name': _('Districts'), - 'values': api_serializers.DistrictSerializer(District.objects.filter(published=True).order_by('name'), - many=True, context={'request': request}).data - }, - { - 'id': 'cities', - 'name': _('Cities'), - 'values': api_serializers.CitySerializer(City.objects.filter(published=True).order_by('name'), - many=True, context={'request': request}).data - }, - { - 'id': 'poi_types', - 'name': _('POI types'), - 'values': api_serializers.POITypeSerializer(POIType.objects.all().order_by('label'), many=True, - context={'request': request}).data, - }, - { - 'id': 'touristiccontent_types', - 'name': _('Touristic content types'), - 'values': api_serializers.TouristicContentTypeSerializer( - TouristicContentType.objects.all().order_by('label'), - many=True, context={'request': request}).data, - }, - { - 'id': 'touristicevent_types', - 'name': _('Touristic event types'), - 'values': api_serializers.TouristicEventTypeSerializer( - TouristicEventType.objects.all().order_by('type'), - many=True, context={'request': request}).data, - }, - { - 'id': 'touristiccontent_categories', - 'name': _('Touristic event types'), - 'values': api_serializers.TouristicContentCategorySerializer( - TouristicContentCategory.objects.all().order_by('order'), - many=True, context={'request': request}).data, - }, - { - 'id': 'sensitive_area_practices', - 'name': _('Sensitive area practices'), - 'values': api_serializers.SportPracticeSerializer( - SportPractice.objects.all().order_by('name'), - many=True, context={'request': request}).data, - } - ] + 'data': data }) diff --git a/geotrek/api/mobile/views/trekking.py b/geotrek/api/mobile/views/trekking.py index c41838327a..17c207d1de 100644 --- a/geotrek/api/mobile/views/trekking.py +++ b/geotrek/api/mobile/views/trekking.py @@ -6,10 +6,13 @@ from rest_framework.permissions import AllowAny from rest_framework_extensions.mixins import DetailSerializerMixin -from geotrek.api.mobile.serializers import trekking as api_serializers_trekking, tourism as api_serializers_tourism, sensitivity as api_serializers_sensitivity +from geotrek.api.mobile.serializers import trekking as api_serializers_trekking, tourism as api_serializers_tourism from geotrek.common.functions import StartPoint, EndPoint from geotrek.trekking import models as trekking_models +if 'geotrek.sensitivity' in settings.INSTALLED_APPS: + from geotrek.api.mobile.serializers import sensitivity as api_serializers_sensitivity + class TrekViewSet(DetailSerializerMixin, viewsets.ReadOnlyModelViewSet): filter_backends = (DjangoFilterBackend,) @@ -72,12 +75,13 @@ def touristic_events(self, request, *args, **kwargs): data = api_serializers_tourism.TouristicEventListSerializer(qs, many=True, context={'root_pk': root_pk}).data return response.Response(data) - @decorators.action(detail=True, methods=['get']) - def sensitive_areas(self, request, *args, **kwargs): - trek = self.get_object() - root_pk = self.request.GET.get('root_pk') or trek.pk - qs = trek.sensitive_areas.filter(published=True) \ - .prefetch_related('species') \ - .annotate(geom2d_transformed=Transform(F('geom'), settings.API_SRID)).order_by('pk') - data = api_serializers_sensitivity.SensitiveAreaListSerializer(qs, many=True, context={'root_pk': root_pk}).data - return response.Response(data) + if 'geotrek.sensitivity' in settings.INSTALLED_APPS: + @decorators.action(detail=True, methods=['get']) + def sensitive_areas(self, request, *args, **kwargs): + trek = self.get_object() + root_pk = self.request.GET.get('root_pk') or trek.pk + qs = trek.sensitive_areas.filter(published=True) \ + .prefetch_related('species') \ + .annotate(geom2d_transformed=Transform(F('geom'), settings.API_SRID)).order_by('pk') + data = api_serializers_sensitivity.SensitiveAreaListSerializer(qs, many=True, context={'root_pk': root_pk}).data + return response.Response(data) From a9e1b9f088e5c8bf0fa9099b088d01a4242b23eb Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Tue, 11 Feb 2025 16:13:17 +0100 Subject: [PATCH 05/14] Update changelog --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 4f4a4155fc..6b3e56d1cf 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,7 @@ CHANGELOG **Improvements** - Officially support Ubuntu 22.04 debian package. +- Add sensitive areas to mobile API **Bug fixes** From 2e21198cdb91d028001c07113fc30cef46997ba2 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Tue, 11 Feb 2025 16:32:08 +0100 Subject: [PATCH 06/14] Fix pre-existing tests related to mobile API SettingsView --- geotrek/api/tests/test_mobile/test_api_mobile_settings.py | 2 +- geotrek/api/tests/test_mobile/test_sync_mobile.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/geotrek/api/tests/test_mobile/test_api_mobile_settings.py b/geotrek/api/tests/test_mobile/test_api_mobile_settings.py index e98604c0c8..651df95a98 100644 --- a/geotrek/api/tests/test_mobile/test_api_mobile_settings.py +++ b/geotrek/api/tests/test_mobile/test_api_mobile_settings.py @@ -17,7 +17,7 @@ SETTINGS_DATA_STRUCTURE = sorted([ 'information_desk_types', 'networks', 'route', 'practice', 'accessibilities', 'difficulty', 'themes', 'cities', 'length', 'duration', 'poi_types', 'touristiccontent_categories', 'touristiccontent_types', 'touristicevent_types', - 'ascent', 'districts' + 'ascent', 'districts', 'sensitive_area_practices' ]) diff --git a/geotrek/api/tests/test_mobile/test_sync_mobile.py b/geotrek/api/tests/test_mobile/test_sync_mobile.py index 2a2acfc7cd..e04176fb04 100644 --- a/geotrek/api/tests/test_mobile/test_sync_mobile.py +++ b/geotrek/api/tests/test_mobile/test_sync_mobile.py @@ -304,7 +304,7 @@ def test_sync_settings(self): with open(os.path.join(self.sync_directory, lang, 'settings.json'), 'r') as f: settings_json = json.load(f) self.assertEqual(len(settings_json), 2) - self.assertEqual(len(settings_json['data']), 16) + self.assertEqual(len(settings_json['data']), 17) self.assertIn('en/settings.json', output.getvalue()) @@ -322,7 +322,7 @@ def test_sync_settings_with_picto_svg(self): with open(os.path.join(self.sync_directory, lang, 'settings.json'), 'r') as f: settings_json = json.load(f) self.assertEqual(len(settings_json), 2) - self.assertEqual(len(settings_json['data']), 16) + self.assertEqual(len(settings_json['data']), 17) self.assertEqual(settings_json['data'][4]['values'][0]['pictogram'], pictogram_png) self.assertEqual(settings_json['data'][9]['values'][0]['pictogram'], pictogram_desk_png) From 1c9c748049abd84ad6790b730642c59fa8d40497 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Thu, 13 Feb 2025 11:05:59 +0100 Subject: [PATCH 07/14] Add sensitive areas to sync mobile --- geotrek/api/management/commands/sync_mobile.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/geotrek/api/management/commands/sync_mobile.py b/geotrek/api/management/commands/sync_mobile.py index 08d0c9cbad..061d229300 100644 --- a/geotrek/api/management/commands/sync_mobile.py +++ b/geotrek/api/management/commands/sync_mobile.py @@ -160,6 +160,16 @@ def sync_trek_touristic_events(self, lang, trek): name = os.path.join(lang, str(trek.pk), 'touristic_events', '{}.geojson'.format(child.pk)) self.sync_view(lang, view, name, params=params, pk=child.pk) + def sync_trek_sensitive_areas(self, lang, trek): + params = {'format': 'geojson', 'root_pk': trek.pk} + view = TrekViewSet.as_view({'get': 'sensitive_areas'}) + name = os.path.join(lang, str(trek.pk), 'sensitive_areas.geojson') + self.sync_view(lang, view, name, params=params, pk=trek.pk) + # Sync sensitive areas of children too + for child in trek.children.annotate(geom_type=GeometryType("geom")).filter(geom_type="LINESTRING"): + name = os.path.join(lang, str(trek.pk), 'sensitive_areas', '{}.geojson'.format(child.pk)) + self.sync_view(lang, view, name, params=params, pk=child.pk) + def sync_file(self, name, src_root, url, directory='', zipfile=None): url = url.strip('/') src = os.path.join(src_root, name) @@ -290,6 +300,7 @@ def sync_trekking(self, lang): self.sync_trek_pois(lang, trek) self.sync_trek_touristic_contents(lang, trek) self.sync_trek_touristic_events(lang, trek) + self.sync_trek_sensitive_areas(lang, trek) # Sync detail of children too for child in trek.children.annotate(geom_type=GeometryType("geom")).filter(geom_type="LINESTRING"): self.sync_geojson( From 1592a28063cbbb3a4ec2bd876fa42224f6d02468 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Thu, 13 Feb 2025 11:18:25 +0100 Subject: [PATCH 08/14] Update translations --- geotrek/api/locale/de/LC_MESSAGES/django.po | 5 ++++- geotrek/api/locale/en/LC_MESSAGES/django.po | 5 ++++- geotrek/api/locale/es/LC_MESSAGES/django.po | 5 ++++- geotrek/api/locale/fr/LC_MESSAGES/django.po | 5 ++++- geotrek/api/locale/it/LC_MESSAGES/django.po | 5 ++++- geotrek/api/locale/nl/LC_MESSAGES/django.po | 5 ++++- geotrek/core/locale/fr/LC_MESSAGES/django.po | 4 +++- geotrek/maintenance/locale/fr/LC_MESSAGES/django.po | 3 ++- 8 files changed, 29 insertions(+), 8 deletions(-) diff --git a/geotrek/api/locale/de/LC_MESSAGES/django.po b/geotrek/api/locale/de/LC_MESSAGES/django.po index f811693d70..97fedf791c 100644 --- a/geotrek/api/locale/de/LC_MESSAGES/django.po +++ b/geotrek/api/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-12 12:45+0000\n" +"POT-Creation-Date: 2025-02-13 10:14+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -138,6 +138,9 @@ msgstr "" msgid "Touristic event types" msgstr "" +msgid "Sensitive area practices" +msgstr "" + msgid "Sync verifications" msgstr "" diff --git a/geotrek/api/locale/en/LC_MESSAGES/django.po b/geotrek/api/locale/en/LC_MESSAGES/django.po index f811693d70..97fedf791c 100644 --- a/geotrek/api/locale/en/LC_MESSAGES/django.po +++ b/geotrek/api/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-12 12:45+0000\n" +"POT-Creation-Date: 2025-02-13 10:14+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -138,6 +138,9 @@ msgstr "" msgid "Touristic event types" msgstr "" +msgid "Sensitive area practices" +msgstr "" + msgid "Sync verifications" msgstr "" diff --git a/geotrek/api/locale/es/LC_MESSAGES/django.po b/geotrek/api/locale/es/LC_MESSAGES/django.po index f811693d70..97fedf791c 100644 --- a/geotrek/api/locale/es/LC_MESSAGES/django.po +++ b/geotrek/api/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-12 12:45+0000\n" +"POT-Creation-Date: 2025-02-13 10:14+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -138,6 +138,9 @@ msgstr "" msgid "Touristic event types" msgstr "" +msgid "Sensitive area practices" +msgstr "" + msgid "Sync verifications" msgstr "" diff --git a/geotrek/api/locale/fr/LC_MESSAGES/django.po b/geotrek/api/locale/fr/LC_MESSAGES/django.po index c9becb7b16..5a02d74230 100644 --- a/geotrek/api/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/api/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-12 12:45+0000\n" +"POT-Creation-Date: 2025-02-13 10:14+0000\n" "PO-Revision-Date: 2020-10-20 16:33+0000\n" "Last-Translator: Bastien Potiron \n" "Language-Team: French \n" "Language-Team: LANGUAGE \n" @@ -138,6 +138,9 @@ msgstr "" msgid "Touristic event types" msgstr "" +msgid "Sensitive area practices" +msgstr "" + msgid "Sync verifications" msgstr "" diff --git a/geotrek/api/locale/nl/LC_MESSAGES/django.po b/geotrek/api/locale/nl/LC_MESSAGES/django.po index f811693d70..97fedf791c 100644 --- a/geotrek/api/locale/nl/LC_MESSAGES/django.po +++ b/geotrek/api/locale/nl/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-12 12:45+0000\n" +"POT-Creation-Date: 2025-02-13 10:14+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -138,6 +138,9 @@ msgstr "" msgid "Touristic event types" msgstr "" +msgid "Sensitive area practices" +msgstr "" + msgid "Sync verifications" msgstr "" diff --git a/geotrek/core/locale/fr/LC_MESSAGES/django.po b/geotrek/core/locale/fr/LC_MESSAGES/django.po index 014f2c8ee5..79aab1686d 100644 --- a/geotrek/core/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/core/locale/fr/LC_MESSAGES/django.po @@ -323,7 +323,9 @@ msgid "The marker was not dropped on a path." msgstr "Le marqueur n'a pas été déposé sur un tronçon." msgid "No routing found for this marker. Please move or delete it." -msgstr "Aucun routage n'a été trouvé pour ce marqueur. Veuillez le déplacer ou le supprimer." +msgstr "" +"Aucun routage n'a été trouvé pour ce marqueur. Veuillez le déplacer ou le " +"supprimer." msgid "No certification" msgstr "Aucune labellisation" diff --git a/geotrek/maintenance/locale/fr/LC_MESSAGES/django.po b/geotrek/maintenance/locale/fr/LC_MESSAGES/django.po index 4828e3619f..2777ddebe3 100644 --- a/geotrek/maintenance/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/maintenance/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-03 09:36+0100\n" +"POT-Creation-Date: 2025-02-13 10:14+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -122,6 +122,7 @@ msgstr "Date de fin" msgid "Mandays" msgstr "Jours-Hommes" +#, python-format msgid "On: %(target)s" msgstr "Sur : %(target)s" From 2a275cba77a08a42b4275b12438b6bc11a339cda Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Thu, 13 Feb 2025 19:35:26 +0100 Subject: [PATCH 09/14] Add unit tests for sensitive areas in mobile API --- .../api/tests/test_mobile/test_api_mobile.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/geotrek/api/tests/test_mobile/test_api_mobile.py b/geotrek/api/tests/test_mobile/test_api_mobile.py index 63590a395e..84f401aa4e 100644 --- a/geotrek/api/tests/test_mobile/test_api_mobile.py +++ b/geotrek/api/tests/test_mobile/test_api_mobile.py @@ -8,6 +8,7 @@ from geotrek.tourism.tests import factories as tourism_factory from geotrek.tourism import models as tourism_models from geotrek.zoning.tests import factories as zoning_factory +from geotrek.sensitivity.tests import factories as sensitivity_factory GEOJSON_STRUCTURE = sorted([ @@ -58,6 +59,10 @@ 'pictures', 'type1', 'type2', 'approved', 'reservation_id', 'reservation_system', 'name', ]) +SENSITIVE_AREA_LIST_PROPERTIES_GEOJSON_STRUCTURE = sorted([ + 'id', 'description', 'name', 'practices', 'contact', 'info_url', 'period' +]) + class BaseApiTest(TestCase): """ @@ -112,6 +117,11 @@ def setUpTestData(cls): cls.touristic_event = tourism_factory.TouristicEventFactory(geom=cls.treks[0].published_pois.first().geom, name_fr='Coucou_Event', description_fr="Sisi_Event", description_teaser_fr="mini", published_fr=True) + + trek_geom_envelope = cls.trek.geom.envelope + cls.sensitive_area_species = sensitivity_factory.SensitiveAreaFactory(geom=trek_geom_envelope, published=True) + cls.sensitive_area_regulatory = sensitivity_factory.SensitiveAreaFactory(geom=trek_geom_envelope, published=True) + cls.district = zoning_factory.DistrictFactory(geom=MultiPolygon(Polygon.from_bbox(cls.treks[0].geom.extent))) cls.district2 = zoning_factory.DistrictFactory(geom=MultiPolygon(Polygon.from_bbox(cls.treks[0].geom.extent)), published=False) bigger_extent = (cls.treks[0].geom.extent[0] - 1, cls.treks[0].geom.extent[1] - 1, @@ -136,6 +146,9 @@ def get_touristic_event_list(self, id_trek, lang, params=None): return self.client.get(reverse('apimobile:treks-touristic-events', args=(id_trek, )), params, headers={"accept-language": lang}) + def get_sensitive_area_list(self, id_trek, lang, params=None): + return self.client.get(reverse('apimobile:treks-sensitive-areas', args=(id_trek, )), params, headers={"accept-language": lang}) + class APIAccessTestCase(BaseApiTest): """ @@ -362,6 +375,30 @@ def test_touristic_content_list(self): self.assertEqual(json_response.get('features')[0].get('properties')['description'], "Sisi") + def test_sensitive_area_list(self): + response = self.get_sensitive_area_list(self.trek.pk, 'fr') + # test response code + self.assertEqual(response.status_code, 200) + + # json collection structure is ok + json_response = response.json() + self.assertEqual(sorted(json_response.keys()), GEOJSON_STRUCTURE) + + # sensitive areas count by trek is ok + self.assertEqual(len(json_response.get('features')), + self.trek.published_sensitive_areas.count()) + + for feature in json_response.get('features'): + # test dim 2 ok + self.assertEqual(len(feature.get('geometry').get('coordinates')[0][0]), 2) + self.assertEqual(sorted(feature.keys()), DETAIL_GEOJSON_STRUCTURE) + self.assertEqual(sorted(feature.get('properties').keys()), + SENSITIVE_AREA_LIST_PROPERTIES_GEOJSON_STRUCTURE) + sensitive_area_obj = self.trek.published_sensitive_areas.get(pk=feature.get('id')) + for i, month in enumerate(['period{:02}'.format(p) for p in range(1, 13)]): + self.assertEqual(getattr(sensitive_area_obj.species, month), + feature.get('properties').get('period')[i]) + class APISwaggerTestCase(BaseApiTest): """ From 1137b9b91e9c23170c8c7613a469fb8267c1da11 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Thu, 13 Feb 2025 19:36:08 +0100 Subject: [PATCH 10/14] Fix unit tests for POIs, touristic contents and touristic events in mobile API --- .../api/tests/test_mobile/test_api_mobile.py | 71 ++++++------------- 1 file changed, 23 insertions(+), 48 deletions(-) diff --git a/geotrek/api/tests/test_mobile/test_api_mobile.py b/geotrek/api/tests/test_mobile/test_api_mobile.py index 84f401aa4e..e4d0db97e5 100644 --- a/geotrek/api/tests/test_mobile/test_api_mobile.py +++ b/geotrek/api/tests/test_mobile/test_api_mobile.py @@ -6,7 +6,6 @@ from geotrek.trekking.tests import factories as trek_factory from geotrek.trekking import models as trek_models from geotrek.tourism.tests import factories as tourism_factory -from geotrek.tourism import models as tourism_models from geotrek.zoning.tests import factories as zoning_factory from geotrek.sensitivity.tests import factories as sensitivity_factory @@ -110,11 +109,11 @@ def setUpTestData(cls): trek_models.OrderedTrekChild(parent=cls.trek_parent_not_published, child=cls.trek_child_not_published_2, order=1).save() - cls.touristic_content = tourism_factory.TouristicContentFactory(geom=cls.treks[0].published_pois.first().geom, + cls.touristic_content = tourism_factory.TouristicContentFactory(geom=cls.trek.published_pois.first().geom, name_fr='Coucou_Content', description_fr="Sisi", description_teaser_fr="mini", published_fr=True) - cls.touristic_event = tourism_factory.TouristicEventFactory(geom=cls.treks[0].published_pois.first().geom, + cls.touristic_event = tourism_factory.TouristicEventFactory(geom=cls.trek.published_pois.first().geom, name_fr='Coucou_Event', description_fr="Sisi_Event", description_teaser_fr="mini", published_fr=True) @@ -122,10 +121,10 @@ def setUpTestData(cls): cls.sensitive_area_species = sensitivity_factory.SensitiveAreaFactory(geom=trek_geom_envelope, published=True) cls.sensitive_area_regulatory = sensitivity_factory.SensitiveAreaFactory(geom=trek_geom_envelope, published=True) - cls.district = zoning_factory.DistrictFactory(geom=MultiPolygon(Polygon.from_bbox(cls.treks[0].geom.extent))) - cls.district2 = zoning_factory.DistrictFactory(geom=MultiPolygon(Polygon.from_bbox(cls.treks[0].geom.extent)), published=False) - bigger_extent = (cls.treks[0].geom.extent[0] - 1, cls.treks[0].geom.extent[1] - 1, - cls.treks[0].geom.extent[2] + 1, cls.treks[0].geom.extent[3] + 1) + cls.district = zoning_factory.DistrictFactory(geom=MultiPolygon(Polygon.from_bbox(cls.trek.geom.extent))) + cls.district2 = zoning_factory.DistrictFactory(geom=MultiPolygon(Polygon.from_bbox(cls.trek.geom.extent)), published=False) + bigger_extent = (cls.trek.geom.extent[0] - 1, cls.trek.geom.extent[1] - 1, + cls.trek.geom.extent[2] + 1, cls.trek.geom.extent[3] + 1) cls.city = zoning_factory.CityFactory(geom=MultiPolygon(Polygon.from_bbox(bigger_extent))) cls.city2 = zoning_factory.CityFactory(geom=MultiPolygon(Polygon.from_bbox(bigger_extent)), published=False) @@ -288,55 +287,39 @@ def test_poi_list(self): # json collection structure is ok json_response = response.json() - # poi count by treks is ok + self.assertEqual(sorted(json_response.keys()), GEOJSON_STRUCTURE) + + # poi count by trek is ok self.assertEqual(len(json_response.get('features')), self.trek.published_pois.count()) # test dim 2 ok - - self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), - 2) - - self.assertEqual(sorted(json_response.keys()), - GEOJSON_STRUCTURE) - - self.assertEqual(len(json_response.get('features')), - trek_models.POI.objects.all().count()) - self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), - 2) - self.assertEqual(sorted(json_response.get('features')[0].keys()), DETAIL_GEOJSON_STRUCTURE) + self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), + 2) self.assertEqual(sorted(json_response.get('features')[0].get('properties').keys()), POI_LIST_PROPERTIES_GEOJSON_STRUCTURE) def test_touristic_event_list(self): - response = self.get_touristic_event_list(trek_models.Trek.objects.first().pk, 'fr') + response = self.get_touristic_event_list(self.trek.pk, 'fr') # test response code self.assertEqual(response.status_code, 200) # json collection structure is ok json_response = response.json() + self.assertEqual(sorted(json_response.keys()), GEOJSON_STRUCTURE) - # poi count by treks is ok + # touristic events count by trek is ok self.assertEqual(len(json_response.get('features')), - trek_models.Trek.objects.order_by('?').last().published_touristic_events.count()) + self.trek.published_touristic_events.count()) # test dim 2 ok - self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), - 2) - - self.assertEqual(sorted(json_response.keys()), - GEOJSON_STRUCTURE) - - self.assertEqual(len(json_response.get('features')), - tourism_models.TouristicEvent.objects.all().count()) - self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), - 2) - self.assertEqual(sorted(json_response.get('features')[0].keys()), DETAIL_GEOJSON_STRUCTURE) + self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), + 2) self.assertEqual(sorted(json_response.get('features')[0].get('properties').keys()), TOURISTIC_EVENT_LIST_PROPERTIES_GEOJSON_STRUCTURE) @@ -344,31 +327,23 @@ def test_touristic_event_list(self): "Sisi_Event") def test_touristic_content_list(self): - response = self.get_touristic_content_list(trek_models.Trek.objects.first().pk, 'fr') + response = self.get_touristic_content_list(self.trek.pk, 'fr') # test response code self.assertEqual(response.status_code, 200) # json collection structure is ok json_response = response.json() + self.assertEqual(sorted(json_response.keys()), GEOJSON_STRUCTURE) - # poi count by treks is ok + # touristic contents count by trek is ok self.assertEqual(len(json_response.get('features')), - trek_models.Trek.objects.order_by('?').last().published_touristic_contents.count()) + self.trek.published_touristic_contents.count()) # test dim 2 ok - self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), - 2) - - self.assertEqual(sorted(json_response.keys()), - GEOJSON_STRUCTURE) - - self.assertEqual(len(json_response.get('features')), - tourism_models.TouristicContent.objects.all().count()) - self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), - 2) - self.assertEqual(sorted(json_response.get('features')[0].keys()), DETAIL_GEOJSON_STRUCTURE) + self.assertEqual(len(json_response.get('features')[0].get('geometry').get('coordinates')), + 2) self.assertEqual(sorted(json_response.get('features')[0].get('properties').keys()), TOURISTIC_CONTENT_LIST_PROPERTIES_GEOJSON_STRUCTURE) From d4ba6f68b0d81f93534180d79beebe409a2ffc05 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Fri, 14 Feb 2025 11:31:14 +0100 Subject: [PATCH 11/14] Add unit test for sensitive area in mobile sync --- geotrek/api/tests/test_mobile/test_sync_mobile.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/geotrek/api/tests/test_mobile/test_sync_mobile.py b/geotrek/api/tests/test_mobile/test_sync_mobile.py index e04176fb04..a57232073d 100644 --- a/geotrek/api/tests/test_mobile/test_sync_mobile.py +++ b/geotrek/api/tests/test_mobile/test_sync_mobile.py @@ -31,6 +31,7 @@ InformationDeskTypeFactory, TouristicContentFactory, TouristicEventFactory) +from geotrek.sensitivity.tests.factories import SensitiveAreaFactory from geotrek.trekking.models import OrderedTrekChild, Trek from geotrek.trekking.tests.factories import (PracticeFactory, TrekFactory, TrekWithPublishedPOIsFactory) @@ -373,6 +374,11 @@ def setUpTestData(cls): published=True, portals=[cls.portal_b]) cls.touristic_event_portal_b = TouristicEventFactory(geom='SRID=%s;POINT(700001 6600001)' % settings.SRID, published=True, portals=[cls.portal_b]) + + trek1_geom_envelope = cls.trek_1.geom.envelope + cls.sensitive_area_species = SensitiveAreaFactory(geom=trek1_geom_envelope, published=True) + cls.sensitive_area_regulatory = SensitiveAreaFactory(geom=trek1_geom_envelope, published=True) + cls.attachment_content_1 = AttachmentImageFactory.create(content_object=cls.touristic_content) cls.attachment_event_1 = AttachmentImageFactory.create(content_object=cls.touristic_event) @@ -435,6 +441,15 @@ def test_sync_pois_by_treks(self): self.assertEqual(len(trek_geojson['features']), 6) self.assertIn('en/{pk}/pois.geojson'.format(pk=str(self.trek_1.pk)), output.getvalue()) + def test_sync_sensitive_areas_by_treks(self): + output = StringIO() + management.call_command('sync_mobile', self.sync_directory, url='http://localhost:8000', + skip_tiles=True, verbosity=2, stdout=output) + with open(os.path.join(self.sync_directory, 'en', str(self.trek_1.pk), 'sensitive_areas.geojson'), 'r') as f: + sensitive_areas_geojson = json.load(f) + self.assertEqual(len(sensitive_areas_geojson['features']), 2) + self.assertIn('en/{pk}/sensitive_areas.geojson'.format(pk=str(self.trek_1.pk)), output.getvalue()) + def test_medias_treks(self): output = StringIO() management.call_command('sync_mobile', self.sync_directory, url='http://localhost:8000', From acdce9d302689998d1182db3ca2e28df8e009045 Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Fri, 14 Feb 2025 11:33:33 +0100 Subject: [PATCH 12/14] Update changelog --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6b3e56d1cf..a483be0107 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,7 +8,7 @@ CHANGELOG **Improvements** - Officially support Ubuntu 22.04 debian package. -- Add sensitive areas to mobile API +- Add sensitive areas to mobile API and sync **Bug fixes** From bd18979f4934f398506194fd2b9ea06277b7a49e Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Fri, 14 Feb 2025 11:36:11 +0100 Subject: [PATCH 13/14] Fix translation --- geotrek/api/locale/fr/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geotrek/api/locale/fr/LC_MESSAGES/django.po b/geotrek/api/locale/fr/LC_MESSAGES/django.po index 5a02d74230..1681bf6ab2 100644 --- a/geotrek/api/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/api/locale/fr/LC_MESSAGES/django.po @@ -140,7 +140,7 @@ msgid "Touristic event types" msgstr "Types d'événements touristiques" msgid "Sensitive area practices" -msgstr "Pratiques en zones sensibles" +msgstr "Pratiques en zone sensible" msgid "Sync verifications" msgstr "Vérification de la synchronisation" From 9cb15df4a21ec4bad4bd39001118b8a07101f20e Mon Sep 17 00:00:00 2001 From: Justine Fricou Date: Fri, 14 Feb 2025 12:49:37 +0100 Subject: [PATCH 14/14] Improve unit tests for mobile API and sync --- .../api/tests/test_mobile/test_api_mobile.py | 5 +++-- .../api/tests/test_mobile/test_sync_mobile.py | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/geotrek/api/tests/test_mobile/test_api_mobile.py b/geotrek/api/tests/test_mobile/test_api_mobile.py index e4d0db97e5..45f9df5563 100644 --- a/geotrek/api/tests/test_mobile/test_api_mobile.py +++ b/geotrek/api/tests/test_mobile/test_api_mobile.py @@ -8,6 +8,7 @@ from geotrek.tourism.tests import factories as tourism_factory from geotrek.zoning.tests import factories as zoning_factory from geotrek.sensitivity.tests import factories as sensitivity_factory +from geotrek.sensitivity.models import SensitiveArea GEOJSON_STRUCTURE = sorted([ @@ -365,11 +366,11 @@ def test_sensitive_area_list(self): for feature in json_response.get('features'): # test dim 2 ok - self.assertEqual(len(feature.get('geometry').get('coordinates')[0][0]), 2) self.assertEqual(sorted(feature.keys()), DETAIL_GEOJSON_STRUCTURE) + self.assertEqual(len(feature.get('geometry').get('coordinates')[0][0]), 2) self.assertEqual(sorted(feature.get('properties').keys()), SENSITIVE_AREA_LIST_PROPERTIES_GEOJSON_STRUCTURE) - sensitive_area_obj = self.trek.published_sensitive_areas.get(pk=feature.get('id')) + sensitive_area_obj = SensitiveArea.objects.get(pk=feature.get('id')) for i, month in enumerate(['period{:02}'.format(p) for p in range(1, 13)]): self.assertEqual(getattr(sensitive_area_obj.species, month), feature.get('properties').get('period')[i]) diff --git a/geotrek/api/tests/test_mobile/test_sync_mobile.py b/geotrek/api/tests/test_mobile/test_sync_mobile.py index a57232073d..b66fbccd3f 100644 --- a/geotrek/api/tests/test_mobile/test_sync_mobile.py +++ b/geotrek/api/tests/test_mobile/test_sync_mobile.py @@ -375,9 +375,9 @@ def setUpTestData(cls): cls.touristic_event_portal_b = TouristicEventFactory(geom='SRID=%s;POINT(700001 6600001)' % settings.SRID, published=True, portals=[cls.portal_b]) - trek1_geom_envelope = cls.trek_1.geom.envelope - cls.sensitive_area_species = SensitiveAreaFactory(geom=trek1_geom_envelope, published=True) - cls.sensitive_area_regulatory = SensitiveAreaFactory(geom=trek1_geom_envelope, published=True) + treks_1_4_envelope = MultiLineString(cls.trek_1.geom, cls.trek_4.geom).envelope + cls.sensitive_area_species = SensitiveAreaFactory(geom=treks_1_4_envelope, published=True) + cls.sensitive_area_regulatory = SensitiveAreaFactory(geom=treks_1_4_envelope, published=True) cls.attachment_content_1 = AttachmentImageFactory.create(content_object=cls.touristic_content) cls.attachment_event_1 = AttachmentImageFactory.create(content_object=cls.touristic_event) @@ -445,10 +445,18 @@ def test_sync_sensitive_areas_by_treks(self): output = StringIO() management.call_command('sync_mobile', self.sync_directory, url='http://localhost:8000', skip_tiles=True, verbosity=2, stdout=output) - with open(os.path.join(self.sync_directory, 'en', str(self.trek_1.pk), 'sensitive_areas.geojson'), 'r') as f: + # Check results for trek_1 as a simple Trek: + filepath_trek_data = os.path.join('en', str(self.trek_1.pk), 'sensitive_areas.geojson') + with open(os.path.join(self.sync_directory, filepath_trek_data), 'r') as f: sensitive_areas_geojson = json.load(f) self.assertEqual(len(sensitive_areas_geojson['features']), 2) - self.assertIn('en/{pk}/sensitive_areas.geojson'.format(pk=str(self.trek_1.pk)), output.getvalue()) + self.assertIn(filepath_trek_data, output.getvalue()) + # Check results for trek_1 as a parent Trek and trek_4 as its child: + filepath_child_trek_data = os.path.join('en', str(self.trek_1.pk), 'sensitive_areas', '{pk}.geojson'.format(pk=str(self.trek_4.pk))) + with open(os.path.join(self.sync_directory, filepath_child_trek_data), 'r') as f: + sensitive_areas_geojson = json.load(f) + self.assertEqual(len(sensitive_areas_geojson['features']), 2) + self.assertIn(filepath_child_trek_data, output.getvalue()) def test_medias_treks(self): output = StringIO()