diff --git a/.env.example b/.env.example index 03c339fb..3b9acf6d 100644 --- a/.env.example +++ b/.env.example @@ -25,6 +25,7 @@ export SENDER_EMAIL= # Workouts # export TILE_SERVER_URL= +# export STATICMAP_SUBDOMAINS= # export MAP_ATTRIBUTION= # export DEFAULT_STATICMAP=False # export WEATHER_API_KEY= diff --git a/fittrackee/config.py b/fittrackee/config.py index 2ac1a81b..4f5ffd6e 100644 --- a/fittrackee/config.py +++ b/fittrackee/config.py @@ -45,6 +45,7 @@ class BaseConfig: 'DEFAULT_STATICMAP': ( os.environ.get('DEFAULT_STATICMAP', 'false').lower() == 'true' ), + 'STATICMAP_SUBDOMAINS': os.environ.get('STATICMAP_SUBDOMAINS', ''), } TRANSLATIONS_FOLDER = os.path.join( current_app.root_path, 'emails/translations' diff --git a/fittrackee/tests/fixtures/fixtures_app.py b/fittrackee/tests/fixtures/fixtures_app.py index c8a9f9bf..de722864 100644 --- a/fittrackee/tests/fixtures/fixtures_app.py +++ b/fittrackee/tests/fixtures/fixtures_app.py @@ -81,6 +81,8 @@ def app(monkeypatch: pytest.MonkeyPatch) -> Generator: monkeypatch.setenv('WEATHER_API_KEY', '') if os.getenv('TILE_SERVER_URL'): monkeypatch.delenv('TILE_SERVER_URL') + if os.getenv('STATICMAP_SUBDOMAINS'): + monkeypatch.delenv('STATICMAP_SUBDOMAINS') if os.getenv('MAP_ATTRIBUTION'): monkeypatch.delenv('MAP_ATTRIBUTION') if os.getenv('DEFAULT_STATICMAP'): diff --git a/fittrackee/tests/workouts/test_utils/test_maps.py b/fittrackee/tests/workouts/test_utils/test_maps.py new file mode 100644 index 00000000..33aa09d4 --- /dev/null +++ b/fittrackee/tests/workouts/test_utils/test_maps.py @@ -0,0 +1,63 @@ +from unittest.mock import patch + +import pytest + +from fittrackee.workouts.utils.maps import get_static_map_tile_server_url + + +class TestGetStaticMapTileServerUrl: + @pytest.mark.parametrize( + 'input_tile_server_url,input_tile_server_subdomains,' + 'expected_tile_server_url', + [ + ( + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + None, + 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + ), + ( + 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + 'a', + 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png', + ), + ( + 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + None, + 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + ), + ( + 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + 'a', + 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + ), + ], + ) + def test_it_returns_tile_server_url( + self, + input_tile_server_url: str, + input_tile_server_subdomains: str, + expected_tile_server_url: str, + ) -> None: + tile_config = { + 'URL': input_tile_server_url, + 'STATICMAP_SUBDOMAINS': input_tile_server_subdomains, + } + + assert ( + get_static_map_tile_server_url(tile_config) + == expected_tile_server_url + ) + + def test_it_returns_tile_server_url_with_random_submain_when_multiple_provided( # noqa + self, + ) -> None: + tile_config = { + 'URL': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + 'STATICMAP_SUBDOMAINS': 'a,b,c', + } + + with patch('random.choice', return_value='b'): + assert ( + get_static_map_tile_server_url(tile_config) + == 'https://b.tile.openstreetmap.org/{z}/{x}/{y}.png' + ) diff --git a/fittrackee/workouts/utils/maps.py b/fittrackee/workouts/utils/maps.py index 57cec069..7022078b 100644 --- a/fittrackee/workouts/utils/maps.py +++ b/fittrackee/workouts/utils/maps.py @@ -1,5 +1,6 @@ import hashlib -from typing import List +import random +from typing import Dict, List from flask import current_app from staticmap import Line, StaticMap @@ -8,6 +9,15 @@ from fittrackee import VERSION from fittrackee.files import get_absolute_file_path +def get_static_map_tile_server_url(tile_server_config: Dict) -> str: + if tile_server_config['STATICMAP_SUBDOMAINS']: + subdomains = tile_server_config['STATICMAP_SUBDOMAINS'].split(',') + subdomain = f'{random.choice(subdomains)}.' # nosec + else: + subdomain = '' + return tile_server_config['URL'].replace('{s}.', subdomain) + + def generate_map(map_filepath: str, map_data: List) -> None: """ Generate and save map image from map data @@ -15,8 +25,8 @@ def generate_map(map_filepath: str, map_data: List) -> None: m = StaticMap(400, 225, 10) m.headers = {'User-Agent': f'FitTrackee v{VERSION}'} if not current_app.config['TILE_SERVER']['DEFAULT_STATICMAP']: - m.url_template = current_app.config['TILE_SERVER']['URL'].replace( - '{s}.', '' + m.url_template = get_static_map_tile_server_url( + current_app.config['TILE_SERVER'] ) line = Line(map_data, '#3388FF', 4) m.add_line(line)