Skip to content

Commit

Permalink
✨ [FEAT] Add CirkwiParser to retrieve Treks and Touristic Contents (r…
Browse files Browse the repository at this point in the history
…efs #3947)
  • Loading branch information
Chatewgne committed Feb 29, 2024
1 parent ad0eb9d commit 5173b63
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CHANGELOG

- Add `include_externals` filter to Cirkwi trek exports, to allow excluding treks with an external id (eid) (#3947)
- Tourism : add price to TouristicEvent model - ref #3587
- Add `CirkwiParser` to retrieve Treks and Touristic Contents from Cirkwi (refs #3947)

**Improvments**

Expand Down
161 changes: 161 additions & 0 deletions geotrek/cirkwi/parsers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
from django.conf import settings
from django.contrib.gis.geos import Point
from django.utils.translation import gettext as _

Check warning on line 3 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L1-L3

Added lines #L1 - L3 were not covered by tests

from geotrek.common.parsers import AttachmentParserMixin, XmlParser
from geotrek.tourism.models import TouristicContent, TouristicContentType1
from geotrek.trekking.models import Trek
from geotrek.trekking.parsers import ApidaeTrekParser

Check warning on line 8 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L5-L8

Added lines #L5 - L8 were not covered by tests


class CirkwiParser(AttachmentParserMixin, XmlParser):
eid = 'eid'
field_options = {

Check warning on line 13 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L11-L13

Added lines #L11 - L13 were not covered by tests
"geom": {"required": True},
"name": {"required": True},
}
constant_fields = {

Check warning on line 17 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L17

Added line #L17 was not covered by tests
'published': True,
}

def get_part(self, dst, src, val):
if val is None:
return None

Check warning on line 23 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L21-L23

Added lines #L21 - L23 were not covered by tests
# Recursively extract XML attributes
if '@@' in src and src[:2] != '@@':
part, attrib = src.split('@@', 1)
return self.get_part(dst, f"@@{attrib}", val.find(part))

Check warning on line 27 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L25-L27

Added lines #L25 - L27 were not covered by tests
# Extract XML attributes
elif src[:2] == '@@':
return val.attrib[src[2:]]

Check warning on line 30 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L29-L30

Added lines #L29 - L30 were not covered by tests
else:
# Return a list of XML elements
if src[-2:] == '/*':
return val.findall(src[:-2])

Check warning on line 34 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L33-L34

Added lines #L33 - L34 were not covered by tests
# Return inner text if XML element exists
if val.find(src) is None:
return None
return val.find(src).text

Check warning on line 38 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L36-L38

Added lines #L36 - L38 were not covered by tests

def filter_description(self, src, val):
descr, compl_title, compl_descr = val
if compl_title and compl_descr:
return f"{descr}\n\n\n{compl_title}: {compl_descr}"
return descr

Check warning on line 44 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L40-L44

Added lines #L40 - L44 were not covered by tests

def filter_attachments(self, src, val):
attachments = []
for attachment in val:
legend = attachment.find('legende')
if legend is not None:
legend = legend.text
url = attachment.find('url').text
author = attachment.find('credit')
if author is not None:
author = author.text
attachments.append([url, legend, author])
return attachments

Check warning on line 57 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L46-L57

Added lines #L46 - L57 were not covered by tests


class CirkwiTrekParserFr(CirkwiParser):
default_language = 'fr'
model = Trek
url = "https://demo-admin.geotrek.fr/static/circkwi.xml"
results_path = 'circuit'
fields = {

Check warning on line 65 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L60-L65

Added lines #L60 - L65 were not covered by tests
"eid": "@@id_circuit",
"name": f"informations/information[@langue='{default_language}']/titre",
"description": (f"informations/information[@langue='{default_language}']/description",
f"informations/information[@langue='{default_language}']/informations_complementaires/information_complementaire/titre",
f"informations/information[@langue='{default_language}']/informations_complementaires/information_complementaire/description"),
"geom": "sens_circuit/fichier_trace@@url",
}
constant_fields = {

Check warning on line 73 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L73

Added line #L73 was not covered by tests
'practice': "Pédestre"
}
non_fields = {

Check warning on line 76 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L76

Added line #L76 was not covered by tests
'attachments': f"informations/information[@langue='{default_language}']/medias/images/image/*"
}
natural_keys = {

Check warning on line 79 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L79

Added line #L79 was not covered by tests
'practice': 'name'
}

def filter_geom(self, src, val):
response = self.request_or_retry(url=val)
return ApidaeTrekParser._get_geom_from_gpx(response.content)

Check warning on line 85 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L83-L85

Added lines #L83 - L85 were not covered by tests


class CirkwiTouristicContentParserFr(CirkwiParser):
default_language = 'fr'
model = TouristicContent
url = "https://demo-admin.geotrek.fr/static/poicirkwi.xml"
results_path = 'poi'
fields = {

Check warning on line 93 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L88-L93

Added lines #L88 - L93 were not covered by tests
"eid": "@@id_poi",
"name": f"informations/information[@langue='{default_language}']/titre",
"description": (f"informations/information[@langue='{default_language}']/description",
f"informations/information[@langue='{default_language}']/informations_complementaires/information_complementaire/titre",
f"informations/information[@langue='{default_language}']/informations_complementaires/information_complementaire/description"),
"geom": ("adresse/position/lng", "adresse/position/lat"),
"practical_info": ("adresse/num", "adresse/rue", "adresse/cp", "adresse/ville", f"informations/information[@langue='{default_language}']/informations_complementaires/information_complementaire/*"),
"category": "categories/categorie/*",
}
m2m_fields = {

Check warning on line 103 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L103

Added line #L103 was not covered by tests
"type1": "categories/categorie/*",
}
non_fields = {

Check warning on line 106 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L106

Added line #L106 was not covered by tests
'attachments': f"informations/information[@langue='{default_language}']/medias/images/image/*"
}
field_options = {

Check warning on line 109 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L109

Added line #L109 was not covered by tests
"geom": {"required": True},
"name": {"required": True},
'category': {'create': True},
'type1': {'create': True},
}
natural_keys = {

Check warning on line 115 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L115

Added line #L115 was not covered by tests
'category': 'label',
'type1': 'label',
}

def filter_practical_info(self, src, val):
num, street, code, city, other_infos = val
infos = ''
if (num and street) or (code and city):
infos += '<strong>Adresse : </strong><br>'
if num and street:
infos += f"{num} {street}<br>"
if code and city:
infos += f"{code} {city}<br>"
for other_info in other_infos:
infos += f"<br><strong>{other_info.find('titre').text} : </strong><br>"
infos += f"{other_info.find('description').text}<br>"
if not infos:
return None
return infos

Check warning on line 134 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L120-L134

Added lines #L120 - L134 were not covered by tests

def filter_category(self, src, val):
if val is None:
return None
name = val[0].attrib["nom"]
return self.apply_filter('category', src, name)

Check warning on line 140 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L136-L140

Added lines #L136 - L140 were not covered by tests

def filter_type1(self, src, val):
if val is None or len(val) < 2:
return None
label = val[1].attrib["nom"]
if self.field_options["type1"]["create"]:
type1, __ = TouristicContentType1.objects.get_or_create(category=self.obj.category, label=label)

Check warning on line 147 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L142-L147

Added lines #L142 - L147 were not covered by tests
else:
try:
type1 = TouristicContentType1.objects.get(category=self.obj.category, label=label)
except TouristicContentType1.DoesNotExist:
self.add_warning(

Check warning on line 152 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L149-L152

Added lines #L149 - L152 were not covered by tests
_("Type 1 '{type}' does not exist for category '{cat}'. Please add it").format(
type=label, cat=self.obj.category.label))
return [type1]

Check warning on line 155 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L155

Added line #L155 was not covered by tests

def filter_geom(self, src, val):
lng, lat = val
geom = Point(float(lng), float(lat), srid=4326) # WGS84
geom.transform(settings.SRID)
return geom

Check warning on line 161 in geotrek/cirkwi/parsers.py

View check run for this annotation

Codecov / codecov/patch

geotrek/cirkwi/parsers.py#L157-L161

Added lines #L157 - L161 were not covered by tests

0 comments on commit 5173b63

Please sign in to comment.