diff options
-rw-r--r-- | development.ini | 1 | ||||
-rw-r--r-- | fietsboek/__init__.py | 9 | ||||
-rw-r--r-- | fietsboek/locale/fietslog.pot | 102 | ||||
-rw-r--r-- | fietsboek/routes.py | 3 | ||||
-rw-r--r-- | fietsboek/static/osm-monkeypatch.js | 352 | ||||
-rw-r--r-- | fietsboek/templates/layout.jinja2 | 3 | ||||
-rw-r--r-- | fietsboek/views/tileproxy.py | 72 | ||||
-rw-r--r-- | poetry.lock | 214 | ||||
-rw-r--r-- | pylint.toml | 2 | ||||
-rw-r--r-- | pyproject.toml | 2 |
10 files changed, 705 insertions, 55 deletions
diff --git a/development.ini b/development.ini index eb33586..3259d3b 100644 --- a/development.ini +++ b/development.ini @@ -18,6 +18,7 @@ pyramid.includes = pyramid_debugtoolbar sqlalchemy.url = sqlite:///%(here)s/fietsboek.sqlite +redis.url = redis://localhost/ fietsboek.data_dir = %(here)s/data retry.attempts = 3 diff --git a/fietsboek/__init__.py b/fietsboek/__init__.py index a727230..6dc435a 100644 --- a/fietsboek/__init__.py +++ b/fietsboek/__init__.py @@ -2,8 +2,10 @@ For more information, see the README or the included documentation. """ +import importlib.metadata from pathlib import Path +import redis from pyramid.config import Configurator from pyramid.session import SignedCookieSessionFactory from pyramid.csrf import CookieCSRFStoragePolicy @@ -16,6 +18,9 @@ from .pages import Pages from . import jinja2 as fiets_jinja2 +__VERSION__ = importlib.metadata.version('fietsboek') + + def locale_negotiator(request): """Negotiates the right locale to use. @@ -57,6 +62,9 @@ def main(global_config, **settings): data_dir = request.registry.settings["fietsboek.data_dir"] return DataManager(Path(data_dir)) + def redis_(request): + return redis.from_url(request.registry.settings["redis.url"]) + settings['enable_account_registration'] = asbool( settings.get('enable_account_registration', 'false')) settings['available_locales'] = aslist( @@ -90,6 +98,7 @@ def main(global_config, **settings): config.set_locale_negotiator(locale_negotiator) config.add_request_method(data_manager, reify=True) config.add_request_method(pages, reify=True) + config.add_request_method(redis_, name="redis", reify=True) jinja2_env = config.get_jinja2_environment() jinja2_env.filters['format_decimal'] = fiets_jinja2.filter_format_decimal diff --git a/fietsboek/locale/fietslog.pot b/fietsboek/locale/fietslog.pot index 91390c8..abb2bfc 100644 --- a/fietsboek/locale/fietslog.pot +++ b/fietsboek/locale/fietslog.pot @@ -8,14 +8,14 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2022-08-10 13:36+0200\n" +"POT-Creation-Date: 2022-11-15 23:42+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.11.0\n" #: fietsboek/util.py:282 msgid "password_constraint.mismatch" @@ -153,43 +153,43 @@ msgstr "" msgid "page.browse.synthetic_tooltip" msgstr "" -#: fietsboek/templates/browse.jinja2:132 fietsboek/templates/details.jinja2:88 +#: fietsboek/templates/browse.jinja2:132 fietsboek/templates/details.jinja2:90 msgid "page.details.date" msgstr "" -#: fietsboek/templates/browse.jinja2:134 fietsboek/templates/details.jinja2:102 +#: fietsboek/templates/browse.jinja2:134 fietsboek/templates/details.jinja2:104 msgid "page.details.length" msgstr "" -#: fietsboek/templates/browse.jinja2:139 fietsboek/templates/details.jinja2:93 +#: fietsboek/templates/browse.jinja2:139 fietsboek/templates/details.jinja2:95 msgid "page.details.start_time" msgstr "" -#: fietsboek/templates/browse.jinja2:141 fietsboek/templates/details.jinja2:97 +#: fietsboek/templates/browse.jinja2:141 fietsboek/templates/details.jinja2:99 msgid "page.details.end_time" msgstr "" -#: fietsboek/templates/browse.jinja2:146 fietsboek/templates/details.jinja2:106 +#: fietsboek/templates/browse.jinja2:146 fietsboek/templates/details.jinja2:108 msgid "page.details.uphill" msgstr "" -#: fietsboek/templates/browse.jinja2:148 fietsboek/templates/details.jinja2:110 +#: fietsboek/templates/browse.jinja2:148 fietsboek/templates/details.jinja2:112 msgid "page.details.downhill" msgstr "" -#: fietsboek/templates/browse.jinja2:153 fietsboek/templates/details.jinja2:115 +#: fietsboek/templates/browse.jinja2:153 fietsboek/templates/details.jinja2:117 msgid "page.details.moving_time" msgstr "" -#: fietsboek/templates/browse.jinja2:155 fietsboek/templates/details.jinja2:119 +#: fietsboek/templates/browse.jinja2:155 fietsboek/templates/details.jinja2:121 msgid "page.details.stopped_time" msgstr "" -#: fietsboek/templates/browse.jinja2:159 fietsboek/templates/details.jinja2:123 +#: fietsboek/templates/browse.jinja2:159 fietsboek/templates/details.jinja2:125 msgid "page.details.max_speed" msgstr "" -#: fietsboek/templates/browse.jinja2:161 fietsboek/templates/details.jinja2:127 +#: fietsboek/templates/browse.jinja2:161 fietsboek/templates/details.jinja2:129 msgid "page.details.avg_speed" msgstr "" @@ -293,40 +293,40 @@ msgstr "" msgid "page.details.delete.close" msgstr "" -#: fietsboek/templates/details.jinja2:69 +#: fietsboek/templates/details.jinja2:70 msgid "page.details.tags" msgstr "" -#: fietsboek/templates/details.jinja2:78 fietsboek/templates/edit.jinja2:10 +#: fietsboek/templates/details.jinja2:80 fietsboek/templates/edit.jinja2:10 #: fietsboek/templates/finish_upload.jinja2:10 msgid "page.noscript" msgstr "" -#: fietsboek/templates/details.jinja2:83 +#: fietsboek/templates/details.jinja2:85 msgid "page.details.download" msgstr "" -#: fietsboek/templates/details.jinja2:172 +#: fietsboek/templates/details.jinja2:174 msgid "page.details.comments" msgstr "" -#: fietsboek/templates/details.jinja2:176 +#: fietsboek/templates/details.jinja2:178 msgid "page.details.comments.author" msgstr "" -#: fietsboek/templates/details.jinja2:193 +#: fietsboek/templates/details.jinja2:195 msgid "page.details.comments.new.title" msgstr "" -#: fietsboek/templates/details.jinja2:196 +#: fietsboek/templates/details.jinja2:198 msgid "page.details.comments.new.input_title" msgstr "" -#: fietsboek/templates/details.jinja2:197 +#: fietsboek/templates/details.jinja2:199 msgid "page.details.comments.new.input_comment" msgstr "" -#: fietsboek/templates/details.jinja2:200 +#: fietsboek/templates/details.jinja2:202 msgid "page.details.comments.new.submit" msgstr "" @@ -394,40 +394,40 @@ msgstr "" msgid "page.track.form.tags" msgstr "" -#: fietsboek/templates/edit_form.jinja2:43 +#: fietsboek/templates/edit_form.jinja2:50 msgid "page.track.form.add_tag" msgstr "" -#: fietsboek/templates/edit_form.jinja2:48 +#: fietsboek/templates/edit_form.jinja2:55 msgid "page.track.form.tagged_people" msgstr "" -#: fietsboek/templates/edit_form.jinja2:63 +#: fietsboek/templates/edit_form.jinja2:70 msgid "page.track.form.add_friend" msgstr "" -#: fietsboek/templates/edit_form.jinja2:83 +#: fietsboek/templates/edit_form.jinja2:90 msgid "page.track.form.badges" msgstr "" -#: fietsboek/templates/edit_form.jinja2:94 +#: fietsboek/templates/edit_form.jinja2:101 msgid "page.track.form.description" msgstr "" -#: fietsboek/templates/edit_form.jinja2:101 -#: fietsboek/templates/edit_form.jinja2:115 +#: fietsboek/templates/edit_form.jinja2:108 +#: fietsboek/templates/edit_form.jinja2:122 msgid "page.track.form.remove_image" msgstr "" -#: fietsboek/templates/edit_form.jinja2:110 +#: fietsboek/templates/edit_form.jinja2:117 msgid "page.track.form.select_images" msgstr "" -#: fietsboek/templates/edit_form.jinja2:126 +#: fietsboek/templates/edit_form.jinja2:133 msgid "page.track.form.image_description_modal" msgstr "" -#: fietsboek/templates/edit_form.jinja2:133 +#: fietsboek/templates/edit_form.jinja2:140 msgid "page.track.form.image_description_modal.save" msgstr "" @@ -457,43 +457,43 @@ msgstr "" msgid "page.navbar.toggle" msgstr "" -#: fietsboek/templates/layout.jinja2:46 +#: fietsboek/templates/layout.jinja2:51 msgid "page.navbar.home" msgstr "" -#: fietsboek/templates/layout.jinja2:49 +#: fietsboek/templates/layout.jinja2:54 msgid "page.navbar.browse" msgstr "" -#: fietsboek/templates/layout.jinja2:53 +#: fietsboek/templates/layout.jinja2:58 msgid "page.navbar.upload" msgstr "" -#: fietsboek/templates/layout.jinja2:57 +#: fietsboek/templates/layout.jinja2:67 msgid "page.navbar.user" msgstr "" -#: fietsboek/templates/layout.jinja2:61 +#: fietsboek/templates/layout.jinja2:71 msgid "page.navbar.welcome_user" msgstr "" -#: fietsboek/templates/layout.jinja2:64 +#: fietsboek/templates/layout.jinja2:74 msgid "page.navbar.logout" msgstr "" -#: fietsboek/templates/layout.jinja2:67 +#: fietsboek/templates/layout.jinja2:77 msgid "page.navbar.profile" msgstr "" -#: fietsboek/templates/layout.jinja2:71 +#: fietsboek/templates/layout.jinja2:81 msgid "page.navbar.admin" msgstr "" -#: fietsboek/templates/layout.jinja2:77 +#: fietsboek/templates/layout.jinja2:87 msgid "page.navbar.login" msgstr "" -#: fietsboek/templates/layout.jinja2:81 +#: fietsboek/templates/layout.jinja2:91 msgid "page.navbar.create_account" msgstr "" @@ -645,43 +645,43 @@ msgstr "" msgid "flash.badge_deleted" msgstr "" -#: fietsboek/views/default.py:75 +#: fietsboek/views/default.py:96 msgid "flash.invalid_credentials" msgstr "" -#: fietsboek/views/default.py:79 +#: fietsboek/views/default.py:100 msgid "flash.account_not_verified" msgstr "" -#: fietsboek/views/default.py:82 +#: fietsboek/views/default.py:103 msgid "flash.logged_in" msgstr "" -#: fietsboek/views/default.py:96 +#: fietsboek/views/default.py:117 msgid "flash.logged_out" msgstr "" -#: fietsboek/views/default.py:127 +#: fietsboek/views/default.py:148 msgid "flash.reset_invalid_email" msgstr "" -#: fietsboek/views/default.py:132 +#: fietsboek/views/default.py:153 msgid "flash.password_token_generated" msgstr "" -#: fietsboek/views/default.py:137 +#: fietsboek/views/default.py:158 msgid "page.password_reset.email.subject" msgstr "" -#: fietsboek/views/default.py:141 +#: fietsboek/views/default.py:162 msgid "page.password_reset.email.body" msgstr "" -#: fietsboek/views/default.py:168 +#: fietsboek/views/default.py:189 msgid "flash.email_verified" msgstr "" -#: fietsboek/views/default.py:182 +#: fietsboek/views/default.py:203 msgid "flash.password_updated" msgstr "" diff --git a/fietsboek/routes.py b/fietsboek/routes.py index ab1eabf..9286f13 100644 --- a/fietsboek/routes.py +++ b/fietsboek/routes.py @@ -54,3 +54,6 @@ def includeme(config): config.add_route('delete-friend', '/me/delete-friend') config.add_route('accept-friend', '/me/accept-friend') config.add_route('json-friends', '/me/friends.json') + + config.add_route('tile-proxy', + '/tile/{provider}/{z:\\d+}/{x:\\d+}/{y:\\d+}') diff --git a/fietsboek/static/osm-monkeypatch.js b/fietsboek/static/osm-monkeypatch.js new file mode 100644 index 0000000..203a4ca --- /dev/null +++ b/fietsboek/static/osm-monkeypatch.js @@ -0,0 +1,352 @@ +/* We want to override JB.Map to add our own maps instead. + * We do this by (ab)using the JS property system to override the setter, so + * that JB.Map won't actually set the new function. This means we don't have to + * source-patch the gmutils.js file. + */ +"use strict"; + +(() => { + let ourMap = function(makemap) { + var dieses = this; + var id = makemap.id; + var mapcanvas = makemap.mapdiv; + dieses.id = id; + dieses.makemap = makemap; + dieses.mapcanvas = mapcanvas; + this.cluster_zoomhistory = []; + + // Map anlegen + + const mycp = '<a href="https://www.j-berkemeier.de/GPXViewer" title="GPX Viewer '+JB.GPX2GM.ver+'">GPXViewer</a> | '; + + this.baseLayers = {}; + + this.baseLayers["OSM"] = L.tileLayer(BASE_URL + 'tile/osm/{z}/{x}/{y}', { + maxZoom: 19, + attribution: mycp+'Map data © <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank">CC-BY-SA</a>' + }); + + this.baseLayers["Satellit"] = L.tileLayer(BASE_URL + 'tile/satellite/{z}/{x}/{y}', { + maxZoom: 21, + attribution: mycp+'Map data © <a href="https://www.esri.com/">Esri</a>, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' + }); + + this.baseLayers["OSMDE"] = L.tileLayer(BASE_URL + 'tile/osmde/{z}/{x}/{y}', { + maxZoom: 19, + attribution: mycp+'Map data © <a href="https://www.openstreetmap.org/" target="_blank">OpenStreetMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank">CC-BY-SA</a>' + }); + + this.baseLayers["Open Topo"] = L.tileLayer(BASE_URL + 'tile/opentopo/{z}/{x}/{y}', { + maxZoom: 17, + attribution: mycp+'Kartendaten: © OpenStreetMap-Mitwirkende, SRTM | Kartendarstellung: © <a href="https://opentopomap.org/about">OpenTopoMap</a> (CC-BY-SA)' + }); + + this.baseLayers["TopPlusOpen"] = L.tileLayer(BASE_URL + 'tile/topplusopen/{z}/{x}/{y}', { + maxZoom: 18, + attribution: mycp+'Kartendaten: © <a href="https://www.bkg.bund.de/SharedDocs/Produktinformationen/BKG/DE/P-2017/170922-TopPlus-Web-Open.html" target==_blank"">Bundesamt für Kartographie und Geodäsie</a>' + }); + + // https://tileserver.4umaps.com/${z}/${x}/${y}.png + // zoomlevel 16 + // https://www.4umaps.com/ + + if(JB.GPX2GM.OSM_Cycle_Api_Key && JB.GPX2GM.OSM_Cycle_Api_Key.length>0) { + this.baseLayers["Cycle"] = L.tileLayer('https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey='+JB.GPX2GM.OSM_Cycle_Api_Key, { + maxZoom: 22, + attribution: mycp+'Map data © <a href="https://www.thunderforest.com/" target="_blank">OpenCycleMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank">CC-BY-SA</a>' + }); + } + + if(JB.GPX2GM.OSM_Landscape_Api_Key && JB.GPX2GM.OSM_Landscape_Api_Key.length>0) { + this.baseLayers["Landscape"] = L.tileLayer('https://{s}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey='+JB.GPX2GM.OSM_Landscape_Api_Key, { + maxZoom: 22, + attribution: mycp+'Map data © <a href="https://www.thunderforest.com/" target="_blank">OpenLandscapeMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank">CC-BY-SA</a>' + }); + } + + if(JB.GPX2GM.OSM_Outdoors_Api_Key && JB.GPX2GM.OSM_Outdoors_Api_Key.length>0) { + this.baseLayers["Outdoors"] = L.tileLayer('https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey='+JB.GPX2GM.OSM_Outdoors_Api_Key, { + maxZoom: 22, + attribution: mycp+'Map data © <a href="https://www.thunderforest.com/" target="_blank">OpenOutdoorsMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank">CC-BY-SA</a>' + }); + } + + this.baseLayers[JB.GPX2GM.strings[JB.GPX2GM.parameters.doclang].noMap]= L.tileLayer(JB.GPX2GM.Path+"Icons/Grau256x256.png", { + maxZoom: 22, + attribution: mycp + }); + + this.overlayLayers = {}; + + this.overlayLayers["Open Sea"] = L.tileLayer(BASE_URL + 'tile/opensea/{z}/{x}/{y}', { + attribution: 'Kartendaten: © <a href="http://www.openseamap.org">OpenSeaMap</a> contributors' + }); + + this.overlayLayers["Hiking"] = L.tileLayer(BASE_URL + 'tile/hiking/{z}/{x}/{y}', { + attribution: '© <a href="http://waymarkedtrails.org">Sarah Hoffmann</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)', + }); + + this.overlayLayers["Cycling"] = L.tileLayer(BASE_URL + 'tile/cycling/{z}/{x}/{y}', { + attribution: '© <a href="http://waymarkedtrails.org">Sarah Hoffmann</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)', + }); + + this.layerNameTranslate = { + satellit: "Satellit", + satellite: "Satellit", + osm: "OSM", + osmde: "OSMDE", + opentopo: "Open Topo", + topplusopen: "TopPlusOpen", + cycle: "Cycle", + landscape: "Landscape", + outdoors: "Outdoors", + keinekarte: "Keine Karte", + pasdecarte: "Pas de carte", + nomap: "No Map", + ning\u00FAnmapa: "Ning\u00FAn Mapa", + nessunamappa: "Nessuna mappa", + opensea: "Open Sea", + hiking: "Hiking", + cycling: "Cycling", + } + + // ['hiking', 'cycling', 'mtb', 'skating', 'slopes', 'riding']; + + var genugplatz = JB.platzgenug(makemap.mapdiv); + + this.map = L.map(mapcanvas, { + // layers: osm, + closePopupOnClick: false, + scrollWheelZoom: genugplatz & makemap.parameters.scrollwheelzoom, + tap: genugplatz, + keyboard: genugplatz, + touchZoom: true, + dragging: true, + } ); + + JB.handle_touch_action(dieses,genugplatz); + + if(makemap.parameters.unit=="si") L.control.scale({imperial:false}).addTo(this.map); // Mit Maßstab km + else L.control.scale({metric:false}).addTo(this.map); // Mit Maßstab ml + + var ctrl_layer = null; + var showmaptypecontroll_save = makemap.parameters.showmaptypecontroll; + JB.onresize(mapcanvas,function(w,h) { + makemap.parameters.showmaptypecontroll = (w>200 && h>190 && showmaptypecontroll_save); + if(makemap.parameters.showmaptypecontroll) { + if(!ctrl_layer) ctrl_layer = L.control.layers(dieses.baseLayers, dieses.overlayLayers).addTo(dieses.map); + } + else { + if(ctrl_layer) { + ctrl_layer.remove(); + ctrl_layer = null; + } + } + },true); + + // Button für Full Screen / normale Größe + var fullscreen = false; + if(makemap.parameters.fullscreenbutton) { + var fsb = document.createElement("button"); + fsb.style.backgroundColor = "transparent"; + fsb.style.border = "none"; + fsb.style.padding = "7px 7px 7px 0"; + fsb.style.cursor = "pointer"; + var fsbim = document.createElement("img"); + fsbim.width = 31; + fsbim.height = 31; + fsbim.src = JB.GPX2GM.Path+"Icons/fullscreen_p.svg"; + fsb.title = fsbim.title = fsbim.alt = JB.GPX2GM.strings[JB.GPX2GM.parameters.doclang].fullScreen; + fsbim.large = false; + var ele = mapcanvas.parentNode; + fsb.onclick = function() { + this.blur(); + if(fsbim.large) { + document.body.style.overflow = ""; + fsbim.src = JB.GPX2GM.Path+"Icons/fullscreen_p.svg"; + fsb.title = fsbim.title = fsbim.alt = JB.GPX2GM.strings[JB.GPX2GM.parameters.doclang].fullScreen; + ele.style.left = ele.oleft + "px"; + ele.style.top = ele.otop + "px"; + ele.style.width = ele.owidth + "px"; + ele.style.height = ele.oheight + "px"; + ele.style.margin = ele.omargin; + ele.style.padding = ele.opadding; + window.setTimeout(function() { + JB.removeClass("JBfull",ele); + ele.style.position = ele.sposition; + ele.style.left = ele.sleft; + ele.style.top = ele.stop; + ele.style.width = ele.swidth; + ele.style.height = ele.sheight; + //ele.style.zIndex = ele.szindex; + },1000); + JB.handle_touch_action(dieses,genugplatz); + fullscreen = false; + } + else { + document.body.style.overflow = "hidden"; + fsbim.src = JB.GPX2GM.Path+"Icons/fullscreen_m.svg"; + fsb.title = fsbim.title = fsbim.alt = JB.GPX2GM.strings[JB.GPX2GM.parameters.doclang].normalSize; + var scrollY = 0; + if(document.documentElement.scrollTop && document.documentElement.scrollTop!=0) scrollY = document.documentElement.scrollTop; + else if(document.body.scrollTop && document.body.scrollTop!=0) scrollY = document.body.scrollTop; + else if(window.scrollY) scrollY = window.scrollY; + else if(window.pageYOffset) scrollY = window.pageYOffset; + var rect = JB.getRect(ele); + ele.oleft = rect.left; + ele.otop = rect.top - scrollY; + ele.owidth = rect.width; + ele.oheight = rect.height; + //ele.szindex = ele.style.zIndex; + ele.sposition = ele.style.position; + ele.omargin = ele.style.margin; + ele.opadding = ele.style.padding; + ele.sleft = ele.style.left; + ele.stop = ele.style.top; + ele.swidth = ele.style.width; + ele.sheight = ele.style.height; + ele.style.position = "fixed"; + ele.style.left = ele.oleft+"px"; + ele.style.top = ele.otop+"px"; + ele.style.width = ele.owidth+"px"; + ele.style.height = ele.oheight+"px"; + //ele.style.zIndex = "1001"; + window.setTimeout(function() { + JB.addClass("JBfull",ele); + ele.style.width = "100%"; + ele.style.height = "100%"; + ele.style.left = "0px"; + ele.style.top = "0px"; + ele.style.margin = "0px"; + ele.style.padding = "0px"; + },100); + dieses.map.scrollWheelZoom.enable(); + JB.handle_touch_action(dieses,true); + makemap.mapdiv.focus(); + fullscreen = true; + } + fsbim.large = !fsbim.large; + }; + fsb.appendChild(fsbim); + fsb.index = 0; + L.Control.Fsbutton = L.Control.extend({ + onAdd: function(map) { + return fsb; + } + }); + var fsbutton = new L.Control.Fsbutton({ position: 'topright' }); + fsbutton.addTo(this.map); + } // fullscreenbutton + + // Button für Traffic-Layer + if(makemap.parameters.trafficbutton) { + console.warn("Traffic-Layer wird unter Leaflet (noch) nicht unterstützt."); + } + + // Button für Anzeige aktuelle Position + if(makemap.parameters.currentlocationbutton) { + var clb = document.createElement("button"); + clb.style.backgroundColor = "white"; + clb.style.border = "none"; + clb.style.width = "28px"; + clb.style.height = "28px"; + clb.style.margin = "10px 10px 0 0"; + clb.style.borderRadius = "2px"; + clb.style.cursor = "pointer"; + clb.title = JB.GPX2GM.strings[JB.GPX2GM.parameters.doclang].showCurrentLocation; + var clbimg = document.createElement("img"); + clbimg.style.position = "absolute"; + clbimg.style.top = "50%"; + clbimg.style.left = "50%"; + clbimg.style.transform = "translate(-50%, -50%)"; + clbimg.src = JB.GPX2GM.Path+"Icons/whereami.svg"; + var wpid = -1, marker = null, first; + clb.onclick = function() { + this.blur(); + if (navigator.geolocation) { + var geolocpos = function(position) { + var lat = position.coords.latitude; + var lon = position.coords.longitude; + marker.setLatLng([lat,lon]); + if(first) { + dieses.map.setView([lat,lon]); + first = false; + } + } + var geolocerror = function(error) { + var errorCodes = ["Permission Denied","Position unavailible","Timeout"]; + var errorString = (error.code<=3)?errorCodes[error.code-1]:"Error code: "+error.code; + JB.Debug_Info("Geolocation-Dienst fehlgeschlagen!",errorString+". "+error.message,true); + } + first = true; + if(!marker) marker = dieses.Marker({lat:0,lon:0},JB.icons.CL)[0]; + if ( wpid == -1 ) { + clb.title = JB.GPX2GM.strings[JB.GPX2GM.parameters.doclang].hideCurrentLocation; + wpid = navigator.geolocation.watchPosition(geolocpos,geolocerror,{enableHighAccuracy:true, timeout: 5000, maximumAge: 60000}); + marker.addTo(dieses.map); + JB.Debug_Info("","Geolocation-Dienst wird eingerichtet.",false); + } + else { + clb.title = JB.GPX2GM.strings[JB.GPX2GM.parameters.doclang].showCurrentLocation; + navigator.geolocation.clearWatch(wpid); + wpid = -1; + marker.remove(); + JB.Debug_Info("","Geolocation-Dienst wird abgeschaltet.",false); + } + } + else JB.Debug_Info("geolocation","Geolocation wird nicht unterstützt!",true); + } // click-Handler + clb.appendChild(clbimg); + L.Control.Clbutton = L.Control.extend({ + onAdd: function(map) { + return clb; + } + }); + var clbutton = new L.Control.Clbutton({ position: 'topright' }); + clbutton.addTo(this.map); + } // currentlocationbutton + + // Scalieren nach MAP-Resize + dieses.zoomstatus = {}; + dieses.zoomstatus.iszoomed = false; + dieses.zoomstatus.zoom_changed = function() { + dieses.zoomstatus.iszoomed = true; + dieses.zoomstatus.level = dieses.map.getZoom(); + dieses.zoomstatus.w = mapcanvas.offsetWidth; + dieses.zoomstatus.h = mapcanvas.offsetHeight; + } + dieses.zoomstatus.move_end = function() { + dieses.zoomstatus.iszoomed = true; + dieses.mapcenter = dieses.map.getCenter(); + } + dieses.map.on("moveend", dieses.zoomstatus.move_end); + JB.onresize(mapcanvas,function(w,h) { + if(w*h==0) return; + dieses.map.invalidateSize(); + dieses.map.setView(dieses.mapcenter); + dieses.map.off("zoomend", dieses.zoomstatus.zoom_changed); + if(dieses.zoomstatus.iszoomed) { + var dz = Math.round(Math.min(Math.log(w/dieses.zoomstatus.w)/Math.LN2,Math.log(h/dieses.zoomstatus.h)/Math.LN2)); + dieses.map.setZoom(dieses.zoomstatus.level+dz); + } + else { + if(dieses.bounds) { + dieses.map.fitBounds(dieses.bounds,{padding:[20,20]}); + dieses.map.setView(dieses.mapcenter); + dieses.zoomstatus.level = dieses.map.getZoom(); + dieses.zoomstatus.w = w; + dieses.zoomstatus.h = h; + } + } + if(!fullscreen) { + genugplatz = JB.platzgenug(makemap.mapdiv); + JB.handle_touch_action(dieses,genugplatz); + } + }); + }; + window.JB = window.JB || {}; + Object.defineProperty(window.JB, "Map", { + get() { return ourMap; }, + set(_) {}, + }); +})(); diff --git a/fietsboek/templates/layout.jinja2 b/fietsboek/templates/layout.jinja2 index 7371052..bbd84f8 100644 --- a/fietsboek/templates/layout.jinja2 +++ b/fietsboek/templates/layout.jinja2 @@ -20,6 +20,7 @@ <script> const FRIENDS_URL = {{ request.route_url('json-friends') | tojson }}; +const BASE_URL = {{ request.route_url('home') | tojson }}; const LOCALE = {{ request.localizer.locale_name.replace('_', '-') | tojson }}; {% if request.registry.settings.get("thunderforest.api_key") %} {% set api_key = request.registry.settings.get("thunderforest.api_key") %} @@ -112,6 +113,8 @@ window.JB.GPX2GM.OSM_Outdoors_Api_Key = {{ api_key | tojson }}; ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="{{request.static_url('fietsboek:static/bootstrap.bundle.min.js')}}"></script> + <!-- Our patch to the GPX viewer, load before the actual GPX viewer --> + <script src="{{request.static_url('fietsboek:static/osm-monkeypatch.js')}}"></script> <!-- Jürgen Berkemeier's GPX viewer --> <script src="{{request.static_url('fietsboek:static/GM_Utils/GPX2GM.js')}}"></script> <script src="{{request.static_url('fietsboek:static/fietsboek.js')}}"></script> diff --git a/fietsboek/views/tileproxy.py b/fietsboek/views/tileproxy.py new file mode 100644 index 0000000..16fd4c5 --- /dev/null +++ b/fietsboek/views/tileproxy.py @@ -0,0 +1,72 @@ +"""Tile proxying layer. + +While this might slow down the initial load (as we now load everything through +fietsboek), we can cache the OSM tiles per instance, and we can provide better +access control for services like thunderforest.com. + +Additionally, this protects the users' IP, as only fietsboek can see it. +""" +import datetime +import random + +from pyramid.view import view_config +from pyramid.response import Response +from pyramid.httpexceptions import HTTPBadRequest + +import requests + +from .. import __VERSION__ + + +TILE_SOURCES = { + # Main base layers + 'osm': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + 'osmde': 'https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', + 'opentopo': 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', + 'topplusopen': 'https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/' + '1.0.0/web/default/WEBMERCATOR/{z}/{y}/{x}.png', + 'satellite': 'https://server.arcgisonline.com/ArcGIS/rest/services/' + 'World_Imagery/MapServer/tile/{z}/{y}/{x}', + + # Overlay layers + 'opensea': 'https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png', + 'hiking': 'https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png', + 'cycling': 'https://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png', +} + +TTL = datetime.timedelta(days=7) + + +@view_config(route_name='tile-proxy', http_cache=3600) +def tile_proxy(request): + """Requests the given tile from the proxy. + + :param request: The Pyramid request. + :type request: pyramid.request.Request + :return: The HTTP response. + :rtype: pyramid.response.Response + """ + provider = request.matchdict['provider'] + if provider not in TILE_SOURCES: + return HTTPBadRequest("Invalid provider") + + x, y, z = (int(request.matchdict['x']), int(request.matchdict['y']), + int(request.matchdict['z'])) + cache_key = f"tile-{provider}-{x}-{y}-{z}" + content_type = "image/png" + + cached = request.redis.get(cache_key) + if cached is not None: + return Response(cached, content_type=content_type) + + url = TILE_SOURCES[provider].format(x=x, y=y, z=z, s=random.choice("abc")) + headers = { + "user-agent": f"Fietsboek-Tile-Proxy/{__VERSION__}", + } + from_mail = request.registry.settings.get('email.from') + if from_mail: + headers["from"] = from_mail + + resp = requests.get(url, headers=headers) + request.redis.set(cache_key, resp.content, ex=TTL) + return Response(resp.content, content_type=resp.headers.get("Content-type", content_type)) diff --git a/poetry.lock b/poetry.lock index d9fb521..fc38406 100644 --- a/poetry.lock +++ b/poetry.lock @@ -16,6 +16,17 @@ SQLAlchemy = ">=1.3.0" tz = ["python-dateutil"] [[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} + +[[package]] name = "attrs" version = "22.1.0" description = "Classes Without Boilerplate" @@ -72,6 +83,14 @@ css = ["tinycss2 (>=1.1.0,<1.2)"] dev = ["Sphinx (==4.3.2)", "black (==22.3.0)", "build (==0.8.0)", "flake8 (==4.0.1)", "hashin (==0.17.0)", "mypy (==0.961)", "pip-tools (==6.6.2)", "pytest (==7.1.2)", "tox (==3.25.0)", "twine (==4.0.1)", "wheel (==0.37.1)"] [[package]] +name = "certifi" +version = "2022.9.24" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." @@ -83,6 +102,17 @@ python-versions = "*" pycparser = "*" [[package]] +name = "charset-normalizer" +version = "2.1.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +unicode-backport = ["unicodedata2"] + +[[package]] name = "click" version = "8.1.3" description = "Composable command line interface toolkit" @@ -136,6 +166,20 @@ ssh = ["bcrypt (>=3.1.5)"] test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] [[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] + +[[package]] name = "exceptiongroup" version = "1.0.4" description = "Backport of PEP 654 (exception groups)" @@ -179,6 +223,14 @@ docs = ["Sphinx", "pylons-sphinx-themes", "watchdog"] testing = ["mock", "pytest", "pytest-cov", "watchdog"] [[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] name = "importlib-metadata" version = "5.0.0" description = "Read metadata from Python packages" @@ -276,7 +328,7 @@ name = "packaging" version = "21.3" description = "Core utilities for Python packages" category = "main" -optional = true +optional = false python-versions = ">=3.6" [package.dependencies] @@ -367,7 +419,7 @@ name = "pyparsing" version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" -optional = true +optional = false python-versions = ">=3.6.8" [package.extras] @@ -525,6 +577,25 @@ optional = false python-versions = "*" [[package]] +name = "redis" +version = "4.3.4" +description = "Python client for Redis database and key-value store" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +async-timeout = ">=4.0.2" +deprecated = ">=1.2.3" +importlib-metadata = {version = ">=1.0", markers = "python_version < \"3.8\""} +packaging = ">=20.4" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] name = "repoze-lru" version = "0.7" description = "A tiny LRU cache implementation and decorator" @@ -537,6 +608,24 @@ docs = ["Sphinx"] testing = ["coverage", "nose"] [[package]] +name = "requests" +version = "2.28.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] name = "setuptools" version = "65.5.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" @@ -642,6 +731,19 @@ optional = false python-versions = ">=3.7" [[package]] +name = "urllib3" +version = "1.26.12" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] name = "venusian" version = "3.0.0" description = "A library for deferring decorator actions" @@ -703,6 +805,14 @@ docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.8)"] tests = ["PasteDeploy", "WSGIProxy2", "coverage", "pyquery", "pytest", "pytest-cov"] [[package]] +name = "wrapt" +version = "1.14.1" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] name = "zipp" version = "3.10.0" description = "Backport of pathlib-compatible object wrapper for zip files" @@ -768,13 +878,17 @@ testing = ["WebTest", "pytest", "pytest-cov"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "5452a4dee7949b3ed0f47ddae85defaef989f8ffc06b77cfea1e0f3116e6a40c" +content-hash = "ef5a076f811b957b45dfbac68ef2012ddb94c13aa89e229bf53b3dc0fa6d7cca" [metadata.files] alembic = [ {file = "alembic-1.8.1-py3-none-any.whl", hash = "sha256:0a024d7f2de88d738d7395ff866997314c837be6104e90c5724350313dee4da4"}, {file = "alembic-1.8.1.tar.gz", hash = "sha256:cd0b5e45b14b706426b833f06369b9a6d5ee03f826ec3238723ce8caaf6e5ffa"}, ] +async-timeout = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] attrs = [ {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, @@ -791,6 +905,10 @@ bleach = [ {file = "bleach-5.0.1-py3-none-any.whl", hash = "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a"}, {file = "bleach-5.0.1.tar.gz", hash = "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c"}, ] +certifi = [ + {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, + {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, +] cffi = [ {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, @@ -857,6 +975,10 @@ cffi = [ {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, ] +charset-normalizer = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +] click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, @@ -945,6 +1067,10 @@ cryptography = [ {file = "cryptography-38.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:785e4056b5a8b28f05a533fab69febf5004458e20dad7e2e13a3120d8ecec75a"}, {file = "cryptography-38.0.3.tar.gz", hash = "sha256:bfbe6ee19615b07a98b1d2287d6a6073f734735b49ee45b11324d85efc4d5cbd"}, ] +deprecated = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, +] exceptiongroup = [ {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"}, {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"}, @@ -1018,6 +1144,10 @@ hupper = [ {file = "hupper-1.10.3-py2.py3-none-any.whl", hash = "sha256:f683850d62598c02faf3c7cdaaa727d8cbe3c5a2497a5737a8358386903b2601"}, {file = "hupper-1.10.3.tar.gz", hash = "sha256:cd6f51b72c7587bc9bce8a65ecd025a1e95f1b03284519bfe91284d010316cd9"}, ] +idna = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] importlib-metadata = [ {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, @@ -1152,10 +1282,18 @@ pytz = [ {file = "pytz-2022.6-py2.py3-none-any.whl", hash = "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427"}, {file = "pytz-2022.6.tar.gz", hash = "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"}, ] +redis = [ + {file = "redis-4.3.4-py3-none-any.whl", hash = "sha256:a52d5694c9eb4292770084fa8c863f79367ca19884b329ab574d5cb2036b3e54"}, + {file = "redis-4.3.4.tar.gz", hash = "sha256:ddf27071df4adf3821c4f2ca59d67525c3a82e5f268bed97b813cb4fabf87880"}, +] repoze-lru = [ {file = "repoze.lru-0.7-py3-none-any.whl", hash = "sha256:f77bf0e1096ea445beadd35f3479c5cff2aa1efe604a133e67150bc8630a62ea"}, {file = "repoze.lru-0.7.tar.gz", hash = "sha256:0429a75e19380e4ed50c0694e26ac8819b4ea7851ee1fc7583c8572db80aff77"}, ] +requests = [ + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, +] setuptools = [ {file = "setuptools-65.5.1-py3-none-any.whl", hash = "sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31"}, {file = "setuptools-65.5.1.tar.gz", hash = "sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f"}, @@ -1227,6 +1365,10 @@ typing-extensions = [ {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, ] +urllib3 = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, +] venusian = [ {file = "venusian-3.0.0-py3-none-any.whl", hash = "sha256:06e7385786ad3a15c70740b2af8d30dfb063a946a851dcb4159f9e2a2302578f"}, {file = "venusian-3.0.0.tar.gz", hash = "sha256:f6842b7242b1039c0c28f6feef29016e7e7dd3caaeb476a193acf737db31ee38"}, @@ -1247,6 +1389,72 @@ webtest = [ {file = "WebTest-3.0.0-py3-none-any.whl", hash = "sha256:2a001a9efa40d2a7e5d9cd8d1527c75f41814eb6afce2c3d207402547b1e5ead"}, {file = "WebTest-3.0.0.tar.gz", hash = "sha256:54bd969725838d9861a9fa27f8d971f79d275d94ae255f5c501f53bb6d9929eb"}, ] +wrapt = [ + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, +] zipp = [ {file = "zipp-3.10.0-py3-none-any.whl", hash = "sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1"}, {file = "zipp-3.10.0.tar.gz", hash = "sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"}, diff --git a/pylint.toml b/pylint.toml index 7495cf7..9e3a63c 100644 --- a/pylint.toml +++ b/pylint.toml @@ -149,7 +149,7 @@ function-naming-style = "snake_case" # function-rgx = # Good variable names which should always be accepted, separated by a comma. -good-names = ["i", "j", "k", "ex", "Run", "_", "id"] +good-names = ["i", "j", "k", "ex", "Run", "_", "id", "x", "y", "z"] # Good variable names regexes, separated by a comma. If names match any regex, # they will always be accepted diff --git a/pyproject.toml b/pyproject.toml index 9fab1a6..3504164 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ SQLAlchemy = "^1.4" alembic = "^1.8" transaction = "^3" "zope.sqlalchemy" = "^1.6" +redis = "^4.3.4" importlib_resources = "^5.10" Babel = "^2.11" @@ -45,6 +46,7 @@ gpxpy = "^1.5" markdown = "^3.4" bleach = "^5" Click = "^8.1" +requests = "^2.28.1" WebTest = {version = "^3", optional = true} pytest = {version = "^7.2", optional = true} |