Skip to content

Commit

Permalink
Merge pull request #3886 from GeotrekCE/feat_add_uuids_in_outdoor_api
Browse files Browse the repository at this point in the history
✨ [FEAT] Add UUIDs of parent and children Courses and Sites in APIv2 (refs #3569)
  • Loading branch information
Chatewgne committed Feb 9, 2024
2 parents 942174f + 9725304 commit 373865c
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 70 deletions.
14 changes: 10 additions & 4 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@ CHANGELOG
2.101.5+dev (XXXX-XX-XX)
------------------------

**Documentation**

- Improve performance in spatial intersection (zoning district and zoning city) for sql views (#3600)

**New features**

- Add UUIDs of parent and children ``Courses`` and ``Sites`` in APIv2 (#3569)

**Improvements**

- Add missing translations for fields on ``Courses`` and ``Sites`` in APIv2 (#3569)
- Allow Apidae Trek parser to handle traces not in utf-8

**Documentation**

- Improve performance in spatial intersection (zoning district and zoning city) for sql views (#3600)

2.101.5 (2024-01-11)
--------------------

**New features**

-Land: Add ``CirculationEdge`` model to manage circulation types and authorization types in the land module (#3578)
- Land: Add ``CirculationEdge`` model to manage circulation types and authorization types in the land module (#3578)
- Generalize``AccessMean`` model and add field ``access`` to ``Intervention`` (#3819)

**Improvements**
Expand Down
69 changes: 62 additions & 7 deletions geotrek/api/tests/test_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@
RESERVATION_SYSTEM_PROPERTIES_JSON_STRUCTURE = sorted(['name', 'id'])

SITE_PROPERTIES_JSON_STRUCTURE = sorted([
'accessibility', 'advice', 'ambiance', 'attachments', 'children', 'cities', 'courses', 'description', 'description_teaser', 'districts', 'eid',
'geometry', 'id', 'information_desks', 'labels', 'managers', 'name', 'orientation', 'parent', 'period', 'portal',
'practice', 'provider', 'pdf', 'ratings', 'sector', 'source', 'structure', 'themes', 'type', 'url', 'uuid',
'view_points', 'wind', 'web_links'
'accessibility', 'advice', 'ambiance', 'attachments', 'children', 'children_uuids', 'cities', 'courses', 'courses_uuids', 'description',
'description_teaser', 'districts', 'eid', 'geometry', 'id', 'information_desks', 'labels', 'managers', 'name', 'orientation', 'parent',
'parent_uuid', 'period', 'portal', 'practice', 'provider', 'pdf', 'ratings', 'sector', 'source', 'structure', 'themes', 'type', 'url', 'uuid',
'view_points', 'published', 'wind', 'web_links'
])

OUTDOORPRACTICE_PROPERTIES_JSON_STRUCTURE = sorted(['id', 'name', 'sector', 'pictogram'])
Expand All @@ -186,9 +186,9 @@

COURSE_PROPERTIES_JSON_STRUCTURE = sorted([
'accessibility', 'advice', 'cities', 'description', 'districts', 'eid', 'equipment', 'geometry', 'height', 'id',
'length', 'name', 'ratings', 'ratings_description', 'sites', 'structure',
'type', 'url', 'attachments', 'max_elevation', 'min_elevation', 'parents', 'provider',
'pdf', 'points_reference', 'children', 'duration', 'gear', 'uuid'
'length', 'name', 'ratings', 'ratings_description', 'sites', 'sites_uuids', 'structure',
'type', 'url', 'attachments', 'max_elevation', 'min_elevation', 'parents', 'parents_uuids', 'provider',
'pdf', 'points_reference', 'published', 'children', 'children_uuids', 'duration', 'gear', 'uuid'
])

COURSETYPE_PROPERTIES_JSON_STRUCTURE = sorted(['id', 'name', 'practice'])
Expand Down Expand Up @@ -4429,6 +4429,11 @@ def test_site_children_published_serializing(self):
self.assertIn(self.site_leaf_published.pk, children)
self.assertIn(self.site_leaf_published_2.pk, children)
self.assertNotIn(self.site_leaf_unpublished.pk, children)
children_uuids = response.json()['children_uuids']
self.assertEqual(2, len(children_uuids))
self.assertIn(str(self.site_leaf_published.uuid), children_uuids)
self.assertIn(str(self.site_leaf_published_2.uuid), children_uuids)
self.assertNotIn(str(self.site_leaf_unpublished.uuid), children_uuids)

def test_site_parent_unpublished_serializing(self):
response = self.get_site_detail(self.site_node_parent_unpublished.pk)
Expand All @@ -4448,8 +4453,15 @@ def test_site_parent_and_children_serializing_by_lang(self):
self.assertIn(self.site_leaf_published_fr.pk, children)
self.assertNotIn(self.site_leaf_published_not_fr.pk, children)
self.assertNotIn(self.site_leaf_unpublished_fr.pk, children)
children_uuids = site_published_fr['children_uuids']
self.assertEqual(1, len(children_uuids))
self.assertIn(str(self.site_leaf_published_fr.uuid), children_uuids)
self.assertNotIn(str(self.site_leaf_published_not_fr.uuid), children_uuids)
self.assertNotIn(str(self.site_leaf_unpublished_fr.uuid), children_uuids)
parent = site_published_fr['parent']
parent_uuid = site_published_fr['parent_uuid']
self.assertEqual(parent, self.site_root_fr.pk)
self.assertEqual(parent_uuid, str(self.site_root_fr.uuid))


class OutdoorFilterByPracticesTestCase(BaseApiTest):
Expand Down Expand Up @@ -4509,6 +4521,11 @@ def setUpTestData(cls):
cls.course = outdoor_factory.CourseFactory()
cls.course.parent_sites.set([cls.site.pk])
cls.course2 = outdoor_factory.CourseFactory()
cls.course3 = outdoor_factory.CourseFactory()
cls.course4 = outdoor_factory.CourseFactory()
outdoor_models.OrderedCourseChild.objects.create(parent=cls.course, child=cls.course2)
outdoor_models.OrderedCourseChild.objects.create(parent=cls.course, child=cls.course4, order=1)
outdoor_models.OrderedCourseChild.objects.create(parent=cls.course3, child=cls.course)
cls.information_desk = tourism_factory.InformationDeskFactory()
cls.site.information_desks.set([cls.information_desk])

Expand All @@ -4522,6 +4539,44 @@ def test_filter_courses_by_portal(self):
self.assertIn(self.course.pk, all_ids)
self.assertNotIn(self.course2.pk, all_ids)

def test_course_serialized_parent_site_and_related_courses(self):
response = self.get_course_detail(self.course.pk)
self.assertEqual(response.status_code, 200)
parent_sites_pk = response.json()['sites']
parent_sites_uuid = response.json()['sites_uuids']
parent_courses_uuid = response.json()['parents_uuids']
parent_courses_pk = response.json()['parents']
children_courses_uuid = response.json()['children_uuids']
children_courses_pk = response.json()['children']
self.assertEqual(parent_sites_pk, [self.site.pk])
self.assertEqual(parent_sites_uuid, [str(self.site.uuid)])
self.assertEqual(parent_courses_pk, [self.course3.pk])
self.assertEqual(parent_courses_uuid, [str(self.course3.uuid)])
self.assertEqual(children_courses_pk, [self.course2.pk, self.course4.pk])
self.assertEqual(children_courses_uuid, [str(self.course2.uuid), str(self.course4.uuid)])
response = self.get_course_detail(self.course.pk, params={'language': 'en'})
self.assertEqual(response.status_code, 200)
parent_sites_pk = response.json()['sites']
parent_sites_uuid = response.json()['sites_uuids']
parent_courses_uuid = response.json()['parents_uuids']
parent_courses_pk = response.json()['parents']
children_courses_uuid = response.json()['children_uuids']
children_courses_pk = response.json()['children']
self.assertEqual(parent_sites_pk, [self.site.pk])
self.assertEqual(parent_sites_uuid, [str(self.site.uuid)])
self.assertEqual(parent_courses_pk, [self.course3.pk])
self.assertEqual(parent_courses_uuid, [str(self.course3.uuid)])
self.assertEqual(children_courses_pk, [self.course2.pk, self.course4.pk])
self.assertEqual(children_courses_uuid, [str(self.course2.uuid), str(self.course4.uuid)])

def test_site_serialized_children_course(self):
response = self.get_site_detail(self.site.pk)
self.assertEqual(response.status_code, 200)
child_course_pk = response.json()['courses']
child_course_uuid = response.json()['courses_uuids']
self.assertEqual(child_course_pk, [self.course.pk])
self.assertEqual(child_course_uuid, [str(self.course.uuid)])

def test_filter_courses_by_themes(self):
response = self.get_course_list({'themes': self.theme.pk})
self.assertEqual(response.status_code, 200)
Expand Down
36 changes: 36 additions & 0 deletions geotrek/api/v2/mixins.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.conf import settings
from django.shortcuts import get_object_or_404
from django.urls import reverse
from modeltranslation.utils import build_localized_fieldname

from geotrek.common import models as common_models

Expand Down Expand Up @@ -32,3 +33,38 @@ def get_pdf_url(self, obj):
for language in settings.MODELTRANSLATION_LANGUAGES:
data[language] = self._get_pdf_url_lang(obj, language, portal)
return data


class PublishedRelatedObjectsSerializerMixin:

def get_values_on_published_related_objects(self, related_queryset, field):
"""
Retrieve values for `field` on objects from `related_queryset` only if they are published according to requested language
"""
request = self.context['request']
language = request.GET.get('language')
if language:
published_by_lang = build_localized_fieldname('published', language)
return list(related_queryset.filter(**{published_by_lang: True}).values_list(field, flat=True))
else:
all_values = []
for item in related_queryset:
if getattr(item, "any_published"):
all_values.append(getattr(item, field))
return all_values

def get_value_on_published_related_object(self, related_object, field):
"""
Retrieve value for `field` on instance `related_object` only if it is published according to requested language
"""
value = None
request = self.context['request']
language = request.GET.get('language')
if related_object:
if language:
if getattr(related_object, build_localized_fieldname('published', language)):
value = getattr(related_object, field)
else:
if related_object.published:
value = getattr(related_object, field)
return value

0 comments on commit 373865c

Please sign in to comment.