aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fietsboek/config.py2
-rw-r--r--fietsboek/jinja2.py4
-rw-r--r--fietsboek/views/tileproxy.py282
3 files changed, 132 insertions, 156 deletions
diff --git a/fietsboek/config.py b/fietsboek/config.py
index d95469c..9949198 100644
--- a/fietsboek/config.py
+++ b/fietsboek/config.py
@@ -127,7 +127,7 @@ class TileLayerConfig(BaseModel):
layer_type: LayerType = Field(LayerType.BASE, alias="type")
"""Type of the layer."""
- zoom: int = 22
+ zoom: typing.Optional[int] = 22
"""Maximum zoom factor of the layer."""
attribution: str = ""
diff --git a/fietsboek/jinja2.py b/fietsboek/jinja2.py
index 6e5e7b6..07c9087 100644
--- a/fietsboek/jinja2.py
+++ b/fietsboek/jinja2.py
@@ -99,13 +99,13 @@ def global_embed_tile_layers(request):
if request.config.disable_tile_proxy:
def _url(source):
- return source.url_template
+ return source.url
else:
def _url(source):
return (
- request.route_url("tile-proxy", provider=source.key, x="{x}", y="{y}", z="{z}")
+ request.route_url("tile-proxy", provider=source.layer_id, x="{x}", y="{y}", z="{z}")
.replace("%7Bx%7D", "{x}")
.replace("%7By%7D", "{y}")
.replace("%7Bz%7D", "{z}")
diff --git a/fietsboek/views/tileproxy.py b/fietsboek/views/tileproxy.py
index 61747d4..1ec609b 100644
--- a/fietsboek/views/tileproxy.py
+++ b/fietsboek/views/tileproxy.py
@@ -9,10 +9,11 @@ Additionally, this protects the users' IP, as only fietsboek can see it.
import datetime
import random
import logging
-from typing import NamedTuple, Optional
+from typing import List
from itertools import chain
from pyramid.view import view_config
+from pyramid.request import Request
from pyramid.response import Response
from pyramid.httpexceptions import HTTPBadRequest, HTTPGatewayTimeout
@@ -20,26 +21,7 @@ import requests
from requests.exceptions import ReadTimeout
from .. import __VERSION__
-from ..config import LayerType, LayerAccess
-
-
-class TileSource(NamedTuple):
- """Represents a remote server that can provide tiles to us."""
-
- key: str
- """Key to indicate this source in URLs."""
- name: str
- """Human-readable name of the source."""
- url_template: str
- """URL with placeholders."""
- layer_type: LayerType
- """Type of this layer."""
- zoom: Optional[int]
- """Max zoom of this layer."""
- access: LayerAccess
- """Access restrictions to use this layer."""
- attribution: str
- """Attribution string."""
+from ..config import Config, LayerType, LayerAccess, TileLayerConfig
LOGGER = logging.getLogger(__name__)
@@ -54,14 +36,14 @@ _jb_copy = _href("https://www.j-berkemeier.de/GPXViewer", "GPXViewer")
DEFAULT_TILE_LAYERS = [
# Main base layers
- TileSource(
- "osm",
- "OSM",
- "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
- LayerType.BASE,
- 19,
- LayerAccess.PUBLIC,
- "".join(
+ TileLayerConfig(
+ layer_id="osm",
+ name="OSM",
+ url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
+ layer_type=LayerType.BASE,
+ zoom=19,
+ access=LayerAccess.PUBLIC,
+ attribution="".join(
[
_jb_copy,
" | Map data © ",
@@ -71,15 +53,15 @@ DEFAULT_TILE_LAYERS = [
]
),
),
- TileSource(
- "satellite",
- "Satellit",
- "https://server.arcgisonline.com/ArcGIS/rest/services/"
+ TileLayerConfig(
+ layer_id="satellite",
+ name="Satellit",
+ url="https://server.arcgisonline.com/ArcGIS/rest/services/"
"World_Imagery/MapServer/tile/{z}/{y}/{x}",
- LayerType.BASE,
- 21,
- LayerAccess.PUBLIC,
- "".join(
+ layer_type=LayerType.BASE,
+ zoom=21,
+ access=LayerAccess.PUBLIC,
+ attribution="".join(
[
_jb_copy,
" | Map data © ",
@@ -89,14 +71,14 @@ DEFAULT_TILE_LAYERS = [
]
),
),
- TileSource(
- "osmde",
- "OSMDE",
- "https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png",
- LayerType.BASE,
- 19,
- LayerAccess.PUBLIC,
- "".join(
+ TileLayerConfig(
+ layer_id="osmde",
+ name="OSMDE",
+ url="https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png",
+ layer_type=LayerType.BASE,
+ zoom=19,
+ access=LayerAccess.PUBLIC,
+ attribution="".join(
[
_jb_copy,
" | Map data © ",
@@ -106,14 +88,14 @@ DEFAULT_TILE_LAYERS = [
]
),
),
- TileSource(
- "opentopo",
- "Open Topo",
- "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
- LayerType.BASE,
- 17,
- LayerAccess.PUBLIC,
- "".join(
+ TileLayerConfig(
+ layer_id="opentopo",
+ name="Open Topo",
+ url="https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
+ layer_type=LayerType.BASE,
+ zoom=17,
+ access=LayerAccess.PUBLIC,
+ attribution="".join(
[
_jb_copy,
" | Kartendaten: © OpenStreetMap-Mitwirkende, SRTM | Kartendarstellung: © ",
@@ -122,15 +104,15 @@ DEFAULT_TILE_LAYERS = [
]
),
),
- TileSource(
- "topplusopen",
- "TopPlusOpen",
- "https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/"
+ TileLayerConfig(
+ layer_id="topplusopen",
+ name="TopPlusOpen",
+ url="https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/"
"1.0.0/web/default/WEBMERCATOR/{z}/{y}/{x}.png",
- LayerType.BASE,
- 18,
- LayerAccess.PUBLIC,
- "".join(
+ layer_type=LayerType.BASE,
+ zoom=18,
+ access=LayerAccess.PUBLIC,
+ attribution="".join(
[
_jb_copy,
" | Kartendaten: © ",
@@ -143,73 +125,85 @@ DEFAULT_TILE_LAYERS = [
),
),
# Overlay layers
- TileSource(
- "opensea",
- "OpenSea",
- "https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png",
- LayerType.OVERLAY,
- None,
- LayerAccess.PUBLIC,
- 'Kartendaten: © <a href="http://www.openseamap.org">OpenSeaMap</a> contributors',
+ TileLayerConfig(
+ layer_id="opensea",
+ name="OpenSea",
+ url="https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png",
+ layer_type=LayerType.OVERLAY,
+ zoom=None,
+ access=LayerAccess.PUBLIC,
+ attribution=(
+ 'Kartendaten: © <a href="http://www.openseamap.org">OpenSeaMap</a> contributors'
+ ),
),
- TileSource(
- "hiking",
- "Hiking",
- "https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png",
- LayerType.OVERLAY,
- None,
- LayerAccess.PUBLIC,
- f'&copy; {_href("http://waymarkedtrails.org", "Sarah Hoffmann")} '
- f'({_href("https://creativecommons.org/licenses/by-sa/3.0/", "CC-BY-SA")})',
+ TileLayerConfig(
+ layer_id="hiking",
+ name="Hiking",
+ url="https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png",
+ layer_type=LayerType.OVERLAY,
+ zoom=None,
+ access=LayerAccess.PUBLIC,
+ attribution=(
+ f'&copy; {_href("http://waymarkedtrails.org", "Sarah Hoffmann")} '
+ f'({_href("https://creativecommons.org/licenses/by-sa/3.0/", "CC-BY-SA")})'
+ ),
),
- TileSource(
- "cycling",
- "Cycling",
- "https://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png",
- LayerType.OVERLAY,
- None,
- LayerAccess.PUBLIC,
- f'&copy; {_href("http://waymarkedtrails.org", "Sarah Hoffmann")} '
- f'({_href("https://creativecommons.org/licenses/by-sa/3.0/", "CC-BY-SA")})',
+ TileLayerConfig(
+ layer_id="cycling",
+ name="Cycling",
+ url="https://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png",
+ layer_type=LayerType.OVERLAY,
+ zoom=None,
+ access=LayerAccess.PUBLIC,
+ attribution=(
+ f'&copy; {_href("http://waymarkedtrails.org", "Sarah Hoffmann")} '
+ f'({_href("https://creativecommons.org/licenses/by-sa/3.0/", "CC-BY-SA")})'
+ ),
),
]
STAMEN_LAYERS = [
- TileSource(
- "stamen-toner",
- "Stamen Toner",
- "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png",
- LayerType.BASE,
- 12,
- LayerAccess.PUBLIC,
- f'{_jb_copy} | Map tiles by <a href="http://stamen.com">Stamen Design</a>, '
- 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
- 'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under '
- '<a href="http://www.openstreetmap.org/copyright">ODbL</a>.',
+ TileLayerConfig(
+ layer_id="stamen-toner",
+ name="Stamen Toner",
+ url="https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png",
+ layer_type=LayerType.BASE,
+ zoom=12,
+ access=LayerAccess.PUBLIC,
+ attribution=(
+ f'{_jb_copy} | Map tiles by <a href="http://stamen.com">Stamen Design</a>, '
+ 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
+ 'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under '
+ '<a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
+ ),
),
- TileSource(
- "stamen-terrain",
- "Stamen Terrain",
- "https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png",
- LayerType.BASE,
- 12,
- LayerAccess.PUBLIC,
- f'{_jb_copy} | Map tiles by <a href="http://stamen.com">Stamen Design</a>, '
- 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
- 'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under '
- '<a href="http://www.openstreetmap.org/copyright">ODbL</a>.',
+ TileLayerConfig(
+ layer_id="stamen-terrain",
+ name="Stamen Terrain",
+ url="https://stamen-tiles.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png",
+ layer_type=LayerType.BASE,
+ zoom=12,
+ access=LayerAccess.PUBLIC,
+ attribution=(
+ f'{_jb_copy} | Map tiles by <a href="http://stamen.com">Stamen Design</a>, '
+ 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
+ 'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under '
+ '<a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
+ ),
),
- TileSource(
- "stamen-watercolor",
- "Stamen Watercolor",
- "https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png",
- LayerType.BASE,
- 12,
- LayerAccess.PUBLIC,
- f'{_jb_copy} | Map tiles by <a href="http://stamen.com">Stamen Design</a>, '
- 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
- 'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under '
- '<a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.',
+ TileLayerConfig(
+ layer_id="stamen-watercolor",
+ name="Stamen Watercolor",
+ url="https://stamen-tiles.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png",
+ layer_type=LayerType.BASE,
+ zoom=12,
+ access=LayerAccess.PUBLIC,
+ attribution=(
+ f'{_jb_copy} | Map tiles by <a href="http://stamen.com">Stamen Design</a>, '
+ 'under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. '
+ 'Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under '
+ '<a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.'
+ ),
),
]
@@ -239,7 +233,7 @@ def tile_proxy(request):
raise HTTPBadRequest("Tile proxying is disabled")
provider = request.matchdict["provider"]
- tile_sources = {source.key: source for source in sources_for(request)}
+ tile_sources = {source.layer_id: source for source in sources_for(request)}
if provider not in tile_sources:
raise HTTPBadRequest("Invalid provider")
@@ -262,7 +256,7 @@ def tile_proxy(request):
LOGGER.debug("Aborted attempt to contact %s due to previous timeouts", provider)
raise HTTPGatewayTimeout(f"Avoiding request to {provider}")
- url = tile_sources[provider].url_template.format(x=x, y=y, z=z, s=random.choice("abc"))
+ url = tile_sources[provider].url.format(x=x, y=y, z=z, s=random.choice("abc"))
headers = {
"user-agent": f"Fietsboek-Tile-Proxy/{__VERSION__}",
}
@@ -287,13 +281,11 @@ def tile_proxy(request):
return Response(resp.content, content_type=resp.headers.get("Content-type", content_type))
-def sources_for(request):
+def sources_for(request: Request) -> List[TileLayerConfig]:
"""Returns all eligible tile sources for the given request.
:param request: The Pyramid request.
- :type request: pyramid.request.Request
:return: A list of tile sources.
- :rtype: list[TileSource]
"""
return [
source
@@ -301,7 +293,7 @@ def sources_for(request):
(
default_layer
for default_layer in DEFAULT_TILE_LAYERS
- if default_layer.key in request.config.default_tile_layers
+ if default_layer.layer_id in request.config.default_tile_layers
),
extract_tile_layers(request.config),
)
@@ -309,18 +301,16 @@ def sources_for(request):
]
-def extract_tile_layers(config):
+def extract_tile_layers(config: Config) -> List[TileLayerConfig]:
"""Extract all defined tile layers from the settings.
:param config: The fietsboek config.
- :type config: fietsboek.config.Config
:return: A list of extracted tile sources.
- :rtype: list[TileSource]
"""
layers = []
layers.extend(_extract_thunderforest(config))
layers.extend(_extract_stamen(config))
- layers.extend(_extract_user_layers(config))
+ layers.extend(config.tile_layers)
return layers
@@ -341,32 +331,18 @@ def _extract_thunderforest(config):
f"https://tile.thunderforest.com/{tf_map}/"
f"{{z}}/{{x}}/{{y}}.png?apikey={tf_api_key}"
)
- yield TileSource(
- f"tf-{tf_map}",
- f"TF {tf_map.title()}",
- url,
- LayerType.BASE,
- 22,
- tf_access,
- tf_attribution,
+ yield TileLayerConfig(
+ layer_id=f"tf-{tf_map}",
+ name=f"TF {tf_map.title()}",
+ url=url,
+ layer_type=LayerType.BASE,
+ zoom=22,
+ access=tf_access,
+ attribution=tf_attribution,
)
def _extract_stamen(config):
- layers = {layer.key: layer for layer in STAMEN_LAYERS}
+ layers = {layer.layer_id: layer for layer in STAMEN_LAYERS}
for name in config.stamen_maps:
yield layers[f"stamen-{name}"]
-
-
-def _extract_user_layers(config):
- # Any other custom maps
- for layer in config.tile_layers:
- yield TileSource(
- layer.layer_id,
- layer.name,
- layer.url,
- layer.layer_type,
- layer.zoom,
- layer.access,
- layer.attribution,
- )