diff --git a/.gitignore b/.gitignore
index 705b30ebe..897462bbc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,7 +50,7 @@ nosetests.xml
coverage.xml
# Translations
-*.mo
+# *.mo # (We DO track these, as we don't want to compile translations for every installation.)
*.pot
# Django stuff:
diff --git a/Dockerfile.mediator b/Dockerfile.mediator
index 3b8c33967..cd7281cac 100644
--- a/Dockerfile.mediator
+++ b/Dockerfile.mediator
@@ -24,11 +24,11 @@ RUN pip3 install -r requirements.txt
# TODO: this is just a temporary solution, use pip for production as soon as geometalab.osmaxx is published there
ADD ./osmaxx $HOME/osmaxx
-ADD ./osmaxx_conversion_service $HOME/osmaxx_conversion_service
+ADD ./conversion_service $HOME/conversion_service
# Expose modules:
ENV PYTHONPATH=PYTHONPATH:$HOME
-ENV DJANGO_SETTINGS_MODULE=osmaxx_conversion_service.config.settings.production
+ENV DJANGO_SETTINGS_MODULE=conversion_service.config.settings.production
RUN mkdir -p $HOME/docker_entrypoint/osmaxx/conversion_service $HOME/entrypoint
COPY ./docker_entrypoint/osmaxx/conversion_service $HOME/entrypoint
diff --git a/Dockerfile.worker b/Dockerfile.worker
index 7fc61b517..f6d70f97a 100644
--- a/Dockerfile.worker
+++ b/Dockerfile.worker
@@ -104,10 +104,12 @@ RUN apt-get clean && apt-get update && \
WORKDIR /root/osm2pgsql
# OSM2PGSQL
+ENV OSM2PGSQL_VERSION=0.92.0
RUN mkdir src &&\
cd src &&\
GIT_SSL_NO_VERIFY=true git clone https://github.com/openstreetmap/osm2pgsql.git &&\
cd osm2pgsql &&\
+ git checkout ${OSM2PGSQL_VERSION} &&\
mkdir build &&\
cd build &&\
cmake ..&&\
@@ -166,11 +168,11 @@ RUN pip3 install -r requirements.txt
# TODO: this is just a temporary solution, use pip for production as soon as geometalab.osmaxx is published there
ADD ./osmaxx $HOME/osmaxx
-ADD ./osmaxx_conversion_service $HOME/osmaxx_conversion_service
+ADD ./conversion_service $HOME/conversion_service
# expose modules
ENV PYTHONPATH=PYTHONPATH:$HOME
-ENV DJANGO_SETTINGS_MODULE=osmaxx_conversion_service.config.settings.worker
+ENV DJANGO_SETTINGS_MODULE=conversion_service.config.settings.worker
ENV WORKER_QUEUES default high
ENTRYPOINT ["/home/py/entrypoint/entrypoint.sh"]
diff --git a/conversion_service/Procfile.mediator.dev b/conversion_service/Procfile.mediator.dev
new file mode 100644
index 000000000..474a6d7c1
--- /dev/null
+++ b/conversion_service/Procfile.mediator.dev
@@ -0,0 +1,2 @@
+mediator: python3 ./conversion_service/manage.py runserver_plus ${APP_HOST}:${APP_PORT}
+harvester: python3 ./conversion_service/manage.py result_harvester
diff --git a/conversion_service/Procfile.mediator.prod b/conversion_service/Procfile.mediator.prod
new file mode 100644
index 000000000..e7e59ed08
--- /dev/null
+++ b/conversion_service/Procfile.mediator.prod
@@ -0,0 +1,2 @@
+mediator: gunicorn --workers ${NUM_WORKERS} conversion_service.config.wsgi --bind ${APP_HOST}:${APP_PORT}
+harvester: python3 ./conversion_service/manage.py result_harvester
diff --git a/conversion_service/Procfile.worker b/conversion_service/Procfile.worker
new file mode 100644
index 000000000..77935082c
--- /dev/null
+++ b/conversion_service/Procfile.worker
@@ -0,0 +1 @@
+worker: ${HOME}/entrypoint/wait-for-it.sh localhost:5432 -t 30 && python3 ./conversion_service/manage.py rqworker ${WORKER_QUEUES:-default high}
diff --git a/osmaxx/utilities/__init__.py b/conversion_service/config/__init__.py
similarity index 100%
rename from osmaxx/utilities/__init__.py
rename to conversion_service/config/__init__.py
diff --git a/osmaxx_conversion_service/config/__init__.py b/conversion_service/config/settings/__init__.py
similarity index 100%
rename from osmaxx_conversion_service/config/__init__.py
rename to conversion_service/config/settings/__init__.py
diff --git a/osmaxx_conversion_service/config/settings/common.py b/conversion_service/config/settings/common.py
similarity index 98%
rename from osmaxx_conversion_service/config/settings/common.py
rename to conversion_service/config/settings/common.py
index dd757e349..4dc1f8e9b 100644
--- a/osmaxx_conversion_service/config/settings/common.py
+++ b/conversion_service/config/settings/common.py
@@ -43,7 +43,6 @@
LOCAL_APPS = (
'osmaxx.version',
'osmaxx.clipping_area',
- 'osmaxx.conversion_api',
'osmaxx.conversion',
)
@@ -190,10 +189,10 @@
# URL Configuration
# ------------------------------------------------------------------------------
-ROOT_URLCONF = 'osmaxx_conversion_service.config.urls'
+ROOT_URLCONF = 'conversion_service.config.urls'
# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
-WSGI_APPLICATION = 'osmaxx_conversion_service.config.wsgi.application'
+WSGI_APPLICATION = 'conversion_service.config.wsgi.application'
CACHES = {
'default': {
diff --git a/osmaxx_conversion_service/config/settings/local.py b/conversion_service/config/settings/local.py
similarity index 100%
rename from osmaxx_conversion_service/config/settings/local.py
rename to conversion_service/config/settings/local.py
diff --git a/osmaxx_conversion_service/config/settings/production.py b/conversion_service/config/settings/production.py
similarity index 100%
rename from osmaxx_conversion_service/config/settings/production.py
rename to conversion_service/config/settings/production.py
diff --git a/osmaxx_conversion_service/config/settings/worker.py b/conversion_service/config/settings/worker.py
similarity index 100%
rename from osmaxx_conversion_service/config/settings/worker.py
rename to conversion_service/config/settings/worker.py
diff --git a/osmaxx_conversion_service/config/urls.py b/conversion_service/config/urls.py
similarity index 100%
rename from osmaxx_conversion_service/config/urls.py
rename to conversion_service/config/urls.py
diff --git a/osmaxx_conversion_service/config/wsgi.py b/conversion_service/config/wsgi.py
similarity index 81%
rename from osmaxx_conversion_service/config/wsgi.py
rename to conversion_service/config/wsgi.py
index cf05ba6a3..5ac4decff 100644
--- a/osmaxx_conversion_service/config/wsgi.py
+++ b/conversion_service/config/wsgi.py
@@ -12,7 +12,7 @@
from whitenoise.django import DjangoWhiteNoise
from django.core.wsgi import get_wsgi_application
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "osmaxx_conversion_service.config.settings.production")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "conversion_service.config.settings.production")
application = get_wsgi_application()
application = Sentry(DjangoWhiteNoise(application))
diff --git a/osmaxx_conversion_service/manage.py b/conversion_service/manage.py
similarity index 71%
rename from osmaxx_conversion_service/manage.py
rename to conversion_service/manage.py
index 1b021a6e4..84fa0c294 100755
--- a/osmaxx_conversion_service/manage.py
+++ b/conversion_service/manage.py
@@ -5,7 +5,7 @@
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "osmaxx_conversion_service.config.settings.local")
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "conversion_service.config.settings.local")
from django.core.management import execute_from_command_line
diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml
index b3462b4e0..46880a2e7 100644
--- a/docker-compose-dev.yml
+++ b/docker-compose-dev.yml
@@ -13,7 +13,7 @@ services:
volumes:
- ./osmaxx:/home/py/osmaxx
- ./web_frontend:/home/py/web_frontend
- - ./osmaxx_conversion_service:/home/py/osmaxx_conversion_service
+ - ./conversion_service:/home/py/conversion_service
ports:
- "8000:8000"
command: [honcho, -f, ./web_frontend/Procfile.django.dev, start]
@@ -42,11 +42,11 @@ services:
volumes:
- ./osmaxx:/home/py/osmaxx
- ./web_frontend:/home/py/web_frontend
- - ./osmaxx_conversion_service:/home/py/osmaxx_conversion_service
- command: [honcho, -f, ./osmaxx_conversion_service/Procfile.mediator.dev, start]
+ - ./conversion_service:/home/py/conversion_service
+ command: [honcho, -f, ./conversion_service/Procfile.mediator.dev, start]
environment:
- DJANGO_SECRET_KEY=insecure!2
- - DJANGO_SETTINGS_MODULE=osmaxx_conversion_service.config.settings.local
+ - DJANGO_SETTINGS_MODULE=conversion_service.config.settings.local
logging:
driver: "json-file"
options:
@@ -55,7 +55,7 @@ services:
volumes:
- ./osmaxx:/home/py/osmaxx
- ./web_frontend:/home/py/web_frontend
- - ./osmaxx_conversion_service:/home/py/osmaxx_conversion_service
+ - ./conversion_service:/home/py/conversion_service
build:
context: .
dockerfile: Dockerfile.worker
@@ -69,7 +69,7 @@ services:
volumes:
- ./osmaxx:/home/py/osmaxx
- ./web_frontend:/home/py/web_frontend
- - ./osmaxx_conversion_service:/home/py/osmaxx_conversion_service
+ - ./conversion_service:/home/py/conversion_service
build:
context: .
dockerfile: Dockerfile.worker
diff --git a/docker-compose.yml b/docker-compose.yml
index ac734648c..2ea6a329c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -60,7 +60,7 @@ services:
extends:
file: docker-compose-common.yml
service: conversionbase
- command: [honcho, -f, ./osmaxx_conversion_service/Procfile.mediator.prod, start]
+ command: [honcho, -f, ./conversion_service/Procfile.mediator.prod, start]
expose:
- "8901"
volumes:
@@ -77,7 +77,7 @@ services:
- REDIS_HOST=redis
- REDIS_PORT=6379
# comma separated list, no brackets, e.g. localhost,dev.myhost.com
- - DJANGO_SETTINGS_MODULE=osmaxx_conversion_service.config.settings.production
+ - DJANGO_SETTINGS_MODULE=conversion_service.config.settings.production
- NUM_WORKERS=5
depends_on:
- conversionserviceredis
@@ -89,7 +89,7 @@ services:
extends:
file: docker-compose-common.yml
service: conversionbase
- command: [honcho, -f, ./osmaxx_conversion_service/Procfile.worker, start]
+ command: [honcho, -f, ./conversion_service/Procfile.worker, start]
volumes:
- osm_data:/var/data/osm-planet
- worker-data:/data/media/job_result_files
@@ -101,7 +101,7 @@ services:
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- - DJANGO_SETTINGS_MODULE=osmaxx_conversion_service.config.settings.worker
+ - DJANGO_SETTINGS_MODULE=conversion_service.config.settings.worker
depends_on:
- conversionserviceredis
- osmboundaries-database
@@ -113,7 +113,7 @@ services:
extends:
file: docker-compose-common.yml
service: conversionbase
- command: [honcho, -f, ./osmaxx_conversion_service/Procfile.worker, start]
+ command: [honcho, -f, ./conversion_service/Procfile.worker, start]
volumes:
- osm_data:/var/data/osm-planet
- worker-data:/data/media/job_result_files
@@ -125,7 +125,7 @@ services:
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- - DJANGO_SETTINGS_MODULE=osmaxx_conversion_service.config.settings.worker
+ - DJANGO_SETTINGS_MODULE=conversion_service.config.settings.worker
# only listens for jobs in this specific queue
- WORKER_QUEUES=high
depends_on:
diff --git a/docker_entrypoint/osmaxx/conversion_service/entrypoint.sh b/docker_entrypoint/osmaxx/conversion_service/entrypoint.sh
index d2dd08319..d3a174d1a 100755
--- a/docker_entrypoint/osmaxx/conversion_service/entrypoint.sh
+++ b/docker_entrypoint/osmaxx/conversion_service/entrypoint.sh
@@ -4,7 +4,7 @@ set -e
# wait for at most 30s for the db to be up
${HOME}/entrypoint/wait-for-it.sh ${DATABASE_HOST}:${DATABASE_PORT} -t 30
-python3 osmaxx_conversion_service/manage.py migrate --no-input && \
-python3 osmaxx_conversion_service/manage.py collectstatic --noinput && \
+python3 conversion_service/manage.py migrate --no-input && \
+python3 conversion_service/manage.py collectstatic --noinput && \
python3 entrypoint/create_user_entrypoint.py && \
exec "$@"
diff --git a/docs/development/releasing.md b/docs/development/releasing.md
index 98820cbdd..276b0eacd 100644
--- a/docs/development/releasing.md
+++ b/docs/development/releasing.md
@@ -22,7 +22,7 @@ The steps execute in the script in a nutshell are:
- `git flow release publish `
- `adapt in osmaxx/__init__.py`
- `python ./web_frontend/manage.py makemessages -l de_CH -l en -l en_UK -l en_US`
-- `python ./osmaxx_conversion_service/manage.py makemessages -l de_CH -l en -l en_UK -l en_US`
+- `python ./conversion_service/manage.py makemessages -l de_CH -l en -l en_UK -l en_US`
- `git flow release finish `
- `git push`
- `git push --tags`
diff --git a/osmaxx/__init__.py b/osmaxx/__init__.py
index 9e9401fc8..40d84aee8 100644
--- a/osmaxx/__init__.py
+++ b/osmaxx/__init__.py
@@ -1,4 +1,4 @@
-__version__ = 'v3.5.0'
+__version__ = 'v3.10.0'
__all__ = [
'__version__',
diff --git a/osmaxx/contrib/auth/frontend_permissions.py b/osmaxx/contrib/auth/frontend_permissions.py
index 46db2bace..b652a46d7 100644
--- a/osmaxx/contrib/auth/frontend_permissions.py
+++ b/osmaxx/contrib/auth/frontend_permissions.py
@@ -1,4 +1,4 @@
-from django.contrib.auth.decorators import login_required, user_passes_test
+from django.contrib.auth.decorators import user_passes_test
from django.core.urlresolvers import reverse_lazy
from django.utils.decorators import method_decorator
from rest_framework import permissions
@@ -6,14 +6,6 @@
from osmaxx.profile.models import Profile
-def _may_user_access_osmaxx_frontend(user):
- """
- Actual test to check if the user is in the frontend user group,
- to give access or deny it. Note: Admins have superpowers.
- """
- return user.has_perm('excerptexport.add_extractionorder')
-
-
def _may_user_access_this_excerpt(user, excerpt):
return excerpt.is_public or excerpt.owner == user
@@ -30,21 +22,6 @@ def _user_has_validated_email(user):
return profile.has_validated_email()
-def frontend_access_required(function=None):
- """
- Decorator for views that checks that the user has the correct access rights,
- redirecting to the information page if necessary.
- """
- access_denied_info_url = reverse_lazy('excerptexport:access_denied')
- actual_decorator = user_passes_test(
- _may_user_access_osmaxx_frontend,
- login_url=access_denied_info_url
- )
- if function:
- return actual_decorator(function)
- return actual_decorator
-
-
def validated_email_required(function=None):
"""
Decorator for views that checks that the user has set a validated email,
@@ -60,24 +37,6 @@ def validated_email_required(function=None):
return actual_decorator
-class LoginRequiredMixin(object):
- """
- Login required Mixin for Class Based Views.
- """
- @method_decorator(login_required)
- def dispatch(self, *args, **kwargs):
- return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
-
-
-class FrontendAccessRequiredMixin(object):
- """
- Frontend Access Check Mixin for Class Based Views.
- """
- @method_decorator(frontend_access_required)
- def dispatch(self, *args, **kwargs):
- return super(FrontendAccessRequiredMixin, self).dispatch(*args, **kwargs)
-
-
class EmailRequiredMixin(object):
"""
Frontend Access Check Mixin for Class Based Views.
@@ -89,11 +48,11 @@ def dispatch(self, *args, **kwargs):
class AuthenticatedAndAccessPermission(permissions.BasePermission):
"""
- Allows access only to authenticated users with frontend permissions.
+ Allows access only to authenticated users with confirmed email address.
"""
def has_permission(self, request, view):
- return request.user.is_authenticated and _may_user_access_osmaxx_frontend(request.user)
+ return request.user.is_authenticated and _user_has_validated_email(request.user)
class HasBBoxAccessPermission(permissions.BasePermission):
diff --git a/osmaxx/conversion/__init__.py b/osmaxx/conversion/__init__.py
index cbb44626e..df64b7849 100644
--- a/osmaxx/conversion/__init__.py
+++ b/osmaxx/conversion/__init__.py
@@ -1 +1,5 @@
+from .constants import output_format
+
default_app_config = 'osmaxx.conversion.apps.ConversionConfig'
+
+__all__ = ['default_app_config', 'output_format']
diff --git a/osmaxx_conversion_service/config/settings/__init__.py b/osmaxx/conversion/constants/__init__.py
similarity index 100%
rename from osmaxx_conversion_service/config/settings/__init__.py
rename to osmaxx/conversion/constants/__init__.py
diff --git a/osmaxx/conversion_api/coordinate_reference_systems.py b/osmaxx/conversion/constants/coordinate_reference_systems.py
similarity index 100%
rename from osmaxx/conversion_api/coordinate_reference_systems.py
rename to osmaxx/conversion/constants/coordinate_reference_systems.py
diff --git a/osmaxx/conversion_api/formats.py b/osmaxx/conversion/constants/output_format.py
similarity index 60%
rename from osmaxx/conversion_api/formats.py
rename to osmaxx/conversion/constants/output_format.py
index 92d01b69c..b3daafe35 100644
--- a/osmaxx/conversion_api/formats.py
+++ b/osmaxx/conversion/constants/output_format.py
@@ -1,62 +1,45 @@
import uuid
-from collections import OrderedDict
+from collections import OrderedDict, namedtuple
-from django.utils.translation import gettext as _
+from django.utils.translation import gettext_lazy as _
FGDB, SHAPEFILE, GPKG, SPATIALITE, GARMIN, PBF = 'fgdb', 'shapefile', 'gpkg', 'spatialite', 'garmin', 'pbf'
-class OutputFormat:
- def __init__(
- self, *, long_identifier, verbose_name, archive_file_name_identifier, abbreviations, is_white_box,
- layer_filename_extension=None
- ):
- self._long_identifier = long_identifier
- self._verbose_name = verbose_name
- self._archive_file_name_identifier = archive_file_name_identifier
- self._abbreviations = abbreviations
- self._is_white_box = is_white_box
- self._layer_filename_extension = layer_filename_extension
+_OutputFormatBase = namedtuple(
+ 'OutputFormatBase',
+ [
+ 'long_identifier',
+ 'verbose_name',
+ 'archive_file_name_identifier',
+ 'abbreviations',
+ 'is_white_box',
+ 'layer_filename_extension',
+ ]
+)
+_OutputFormatBase.__new__.__defaults__ = (None,) # This makes the last field (i.e. layer_filename_extension) optional.
- @property
- def long_identifier(self):
- return self._long_identifier
-
- @property
- def verbose_name(self):
- return self._verbose_name
-
- @property
- def archive_file_name_identifier(self):
- return self._archive_file_name_identifier
-
- @property
- def abbreviations(self):
- return self._abbreviations
-
- @property
- def layer_filename_extension(self):
- return self._layer_filename_extension
+class OutputFormat(_OutputFormatBase):
@property
def qgis_datasource_separator(self):
"""
The string used to separate the dataset path (collections of layers) from the individual layer in a QGIS project
file's ```` element referring to data in this format.
"""
- return '/' if self._layer_filename_extension is not None else '|layername='
+ return '/' if self.layer_filename_extension is not None else '|layername='
def unique_archive_name(self):
return "{}_{}.zip".format(uuid.uuid4(), self.archive_file_name_identifier)
def crs_change_available(self):
- return self._is_white_box
+ return self.is_white_box
def detail_level_available(self):
- return self._is_white_box
+ return self.is_white_box
-FORMAT_DEFINITIONS = OrderedDict([
+DEFINITIONS = OrderedDict([
(FGDB, OutputFormat(
long_identifier='Esri File Geodatabase',
verbose_name=_('Esri File Geodatabase'),
@@ -102,4 +85,5 @@ def detail_level_available(self):
)),
])
-FORMAT_CHOICES = tuple((key, definition.verbose_name) for key, definition in FORMAT_DEFINITIONS.items())
+CHOICES = tuple((key, definition.verbose_name) for key, definition in DEFINITIONS.items())
+ALL = DEFINITIONS.keys()
diff --git a/osmaxx/conversion_api/statuses.py b/osmaxx/conversion/constants/statuses.py
similarity index 100%
rename from osmaxx/conversion_api/statuses.py
rename to osmaxx/conversion/constants/statuses.py
diff --git a/osmaxx/conversion/converters/converter.py b/osmaxx/conversion/converters/converter.py
index d7b433c62..b59f0588b 100644
--- a/osmaxx/conversion/converters/converter.py
+++ b/osmaxx/conversion/converters/converter.py
@@ -1,68 +1,20 @@
-from osmaxx.conversion.converters.converter_garmin.garmin import Garmin
-from osmaxx.conversion.converters.converter_gis.gis import GISConverter
-from osmaxx.conversion.converters.converter_pbf.to_pbf import produce_pbf
+from osmaxx.conversion import output_format
+from osmaxx.conversion.converters import converter_garmin
+from osmaxx.conversion.converters import converter_gis
+from osmaxx.conversion.converters import converter_pbf
from osmaxx.conversion.job_dispatcher.rq_dispatcher import rq_enqueue_with_settings
-from osmaxx.conversion_api.formats import FGDB, SHAPEFILE, GPKG, SPATIALITE, GARMIN, PBF
+from osmaxx.utils.frozendict import frozendict
-
-class Conversion(object):
- def __init__(
- self,
- *,
- conversion_format,
- area_name,
- osmosis_polygon_file_string,
- output_zip_file_path,
- filename_prefix,
- detail_level,
- out_srs=None
- ):
- self._conversion_format = conversion_format
- self._output_zip_file_path = output_zip_file_path
- self._area_name = area_name
- self._polyfile_string = osmosis_polygon_file_string
- self._name_prefix = filename_prefix
- self._out_srs = out_srs
- self._detail_level = detail_level
-
- _format_process = {
- GARMIN: self._create_garmin_export,
- PBF: self._create_pbf,
- FGDB: self._extract_postgis_format,
- SHAPEFILE: self._extract_postgis_format,
- GPKG: self._extract_postgis_format,
- SPATIALITE: self._extract_postgis_format,
- }
- self._conversion_process = _format_process[conversion_format]
-
- def start_format_extraction(self):
- self._conversion_process()
-
- def _extract_postgis_format(self):
- gis = GISConverter(
- conversion_format=self._conversion_format,
- out_zip_file_path=self._output_zip_file_path,
- base_file_name=self._name_prefix,
- out_srs=self._out_srs,
- polyfile_string=self._polyfile_string,
- detail_level=self._detail_level
- )
- gis.create_gis_export()
-
- def _create_garmin_export(self):
- garmin = Garmin(
- out_zip_file_path=self._output_zip_file_path,
- area_name=self._area_name,
- polyfile_string=self._polyfile_string,
- )
- garmin.create_garmin_export()
-
- def _create_pbf(self):
- produce_pbf(
- out_zip_file_path=self._output_zip_file_path,
- area_name=self._area_name,
- polyfile_string=self._polyfile_string,
- )
+_format_converter = frozendict(
+ {
+ output_format.GARMIN: converter_garmin,
+ output_format.PBF: converter_pbf,
+ output_format.FGDB: converter_gis,
+ output_format.SHAPEFILE: converter_gis,
+ output_format.GPKG: converter_gis,
+ output_format.SPATIALITE: converter_gis,
+ }
+)
def convert(
@@ -87,6 +39,6 @@ def convert(
queue_name=queue_name,
**params
).id
- conversion = Conversion(**params)
- conversion.start_format_extraction()
+ converter = _format_converter[conversion_format]
+ converter.perform_export(**params)
return None
diff --git a/osmaxx/conversion/converters/converter_garmin/__init__.py b/osmaxx/conversion/converters/converter_garmin/__init__.py
index e69de29bb..6076ff857 100644
--- a/osmaxx/conversion/converters/converter_garmin/__init__.py
+++ b/osmaxx/conversion/converters/converter_garmin/__init__.py
@@ -0,0 +1,3 @@
+from .garmin import perform_export
+
+__all__ = ['perform_export']
diff --git a/osmaxx/conversion/converters/converter_garmin/garmin.py b/osmaxx/conversion/converters/converter_garmin/garmin.py
index 052e7ea66..9d1690c17 100644
--- a/osmaxx/conversion/converters/converter_garmin/garmin.py
+++ b/osmaxx/conversion/converters/converter_garmin/garmin.py
@@ -1,5 +1,4 @@
import shutil
-import subprocess
import os
import tempfile
@@ -7,8 +6,19 @@
from rq import get_current_job
from osmaxx.conversion._settings import CONVERSION_SETTINGS, odb_license, copying_notice, creative_commons_license
+from osmaxx.conversion.converters.converter_pbf.to_pbf import cut_pbf_along_polyfile
+
+from osmaxx.conversion.converters.utils import zip_folders_relative, recursive_getsize, logged_check_call
+
+
+def perform_export(*, output_zip_file_path, area_name, osmosis_polygon_file_string, **__):
+ garmin = Garmin(
+ output_zip_file_path=output_zip_file_path,
+ area_name=area_name,
+ polyfile_string=osmosis_polygon_file_string,
+ )
+ garmin.create_garmin_export()
-from osmaxx.conversion.converters.utils import zip_folders_relative, recursive_getsize
_path_to_commandline_utils = os.path.join(os.path.dirname(__file__), 'command_line_utils')
_path_to_bounds_zip = os.path.join(CONVERSION_SETTINGS['SEA_AND_BOUNDS_ZIP_DIRECTORY'], 'bounds.zip')
@@ -17,8 +27,8 @@
class Garmin:
- def __init__(self, *, out_zip_file_path, area_name, polyfile_string):
- self._resulting_zip_file_path = out_zip_file_path
+ def __init__(self, *, output_zip_file_path, area_name, polyfile_string):
+ self._resulting_zip_file_path = output_zip_file_path
self._map_description = area_name
self._osmosis_polygon_file = tempfile.NamedTemporaryFile(suffix='.poly', mode='w')
self._osmosis_polygon_file.write(polyfile_string)
@@ -26,6 +36,7 @@ def __init__(self, *, out_zip_file_path, area_name, polyfile_string):
self._polyfile_path = self._osmosis_polygon_file.name
self._start_time = None
self._unzipped_result_size = None
+ self._area_polyfile_string = polyfile_string
def create_garmin_export(self):
self._start_time = timezone.now()
@@ -47,7 +58,9 @@ def _to_garmin(self):
def _split(self, workdir):
memory_option = '-Xmx7000m'
_splitter_path = os.path.abspath(os.path.join(_path_to_commandline_utils, 'splitter', 'splitter.jar'))
- subprocess.check_call([
+ _pbf_file_path = os.path.join('/tmp', 'pbf_cutted.pbf')
+ cut_pbf_along_polyfile(self._area_polyfile_string, _pbf_file_path)
+ logged_check_call([
'java',
memory_option,
'-jar', _splitter_path,
@@ -55,7 +68,7 @@ def _split(self, workdir):
'--description={0}'.format(self._map_description),
'--geonames-file={0}'.format(_path_to_geonames_zip),
'--polygon-file={}'.format(self._polyfile_path),
- CONVERSION_SETTINGS.get('PBF_PLANET_FILE_PATH'),
+ _pbf_file_path,
])
config_file_path = os.path.join(workdir, 'template.args')
return config_file_path
@@ -79,7 +92,7 @@ def _produce_garmin(self, config_file_path, out_dir):
'--route',
]
- subprocess.check_call(
+ logged_check_call(
mkg_map_command +
output_dir +
config
diff --git a/osmaxx/conversion/converters/converter_gis/__init__.py b/osmaxx/conversion/converters/converter_gis/__init__.py
index e69de29bb..b2b7a6664 100644
--- a/osmaxx/conversion/converters/converter_gis/__init__.py
+++ b/osmaxx/conversion/converters/converter_gis/__init__.py
@@ -0,0 +1,3 @@
+from .gis import perform_export
+
+__all__ = ['perform_export']
diff --git a/osmaxx/conversion/converters/converter_gis/bootstrap/bootstrap.py b/osmaxx/conversion/converters/converter_gis/bootstrap/bootstrap.py
index 9ab03810d..951d11de4 100644
--- a/osmaxx/conversion/converters/converter_gis/bootstrap/bootstrap.py
+++ b/osmaxx/conversion/converters/converter_gis/bootstrap/bootstrap.py
@@ -1,17 +1,18 @@
import glob
import os
-import subprocess
+from memoize import mproperty
+
+from osmaxx.conversion.converters.converter_gis.detail_levels import DETAIL_LEVEL_ALL, DETAIL_LEVEL_TABLES
from osmaxx.conversion.converters.converter_gis.helper.default_postgres import get_default_postgres_wrapper
from osmaxx.conversion.converters.converter_gis.helper.osm_boundaries_importer import OSMBoundariesImporter
-from osmaxx.conversion.converters import detail_levels
-from osmaxx.conversion.converters.converter_pbf.to_pbf import polyfile_string_to_pbf
-from osmaxx.conversion.converters.detail_levels import DETAIL_LEVEL_TABLES
+from osmaxx.conversion.converters.converter_pbf.to_pbf import cut_pbf_along_polyfile
+from osmaxx.conversion.converters.utils import logged_check_call
from osmaxx.utils import polyfile_helpers
class BootStrapper:
- def __init__(self, area_polyfile_string, *, detail_level=detail_levels.DETAIL_LEVEL_ALL):
+ def __init__(self, area_polyfile_string, *, detail_level=DETAIL_LEVEL_ALL):
self.area_polyfile_string = area_polyfile_string
self._postgres = get_default_postgres_wrapper()
self._script_base_dir = os.path.abspath(os.path.dirname(__file__))
@@ -22,7 +23,7 @@ def __init__(self, area_polyfile_string, *, detail_level=detail_levels.DETAIL_LE
def bootstrap(self):
self._reset_database()
- polyfile_string_to_pbf(self.area_polyfile_string, self._pbf_file_path)
+ cut_pbf_along_polyfile(self.area_polyfile_string, self._pbf_file_path)
self._import_boundaries()
self._import_pbf()
self._setup_db_functions()
@@ -30,7 +31,7 @@ def bootstrap(self):
self._filter_data()
self._create_views()
- @property
+ @mproperty
def geom(self):
return polyfile_helpers.parse_poly_string(self.area_polyfile_string)
@@ -129,4 +130,4 @@ def _import_pbf(self):
'--input-reader', 'pbf',
self._pbf_file_path,
]
- subprocess.check_call(osm_2_pgsql_command)
+ logged_check_call(osm_2_pgsql_command)
diff --git a/osmaxx/conversion/converters/detail_levels.py b/osmaxx/conversion/converters/converter_gis/detail_levels.py
similarity index 100%
rename from osmaxx/conversion/converters/detail_levels.py
rename to osmaxx/conversion/converters/converter_gis/detail_levels.py
diff --git a/osmaxx/conversion/converters/converter_gis/extract/db_to_format/extract.py b/osmaxx/conversion/converters/converter_gis/extract/db_to_format/extract.py
index 66643571e..065691bcc 100644
--- a/osmaxx/conversion/converters/converter_gis/extract/db_to_format/extract.py
+++ b/osmaxx/conversion/converters/converter_gis/extract/db_to_format/extract.py
@@ -2,25 +2,25 @@
import subprocess
from osmaxx.conversion._settings import CONVERSION_SETTINGS
-from osmaxx.conversion_api.formats import FGDB, SHAPEFILE, GPKG, SPATIALITE
+from osmaxx.conversion import output_format
FORMATS = {
- FGDB: {
+ output_format.FGDB: {
'ogr_name': 'FileGDB',
'extension': '.gdb',
'extraction_options': [],
},
- GPKG: {
+ output_format.GPKG: {
'ogr_name': 'GPKG',
'extension': '.gpkg',
'extraction_options': [],
},
- SHAPEFILE: {
+ output_format.SHAPEFILE: {
'ogr_name': 'Esri Shapefile',
'extension': '.shp',
'extraction_options': ['-lco', 'ENCODING=UTF-8'],
},
- SPATIALITE: {
+ output_format.SPATIALITE: {
'ogr_name': 'SQLite',
'extension': '.sqlite',
'extraction_options': ['-dsco', 'SPATIALITE=YES', '-nlt', 'GEOMETRY'] # FIXME: Remove or change -nlt because of geometry reading problems
diff --git a/osmaxx/conversion/converters/converter_gis/gis.py b/osmaxx/conversion/converters/converter_gis/gis.py
index c29d0ec29..628112648 100644
--- a/osmaxx/conversion/converters/converter_gis/gis.py
+++ b/osmaxx/conversion/converters/converter_gis/gis.py
@@ -11,11 +11,25 @@
from jinja2 import Environment, PackageLoader
from rq import get_current_job
+from osmaxx.conversion import output_format
from osmaxx.conversion._settings import odb_license
from osmaxx.conversion.converters.converter_gis.bootstrap import BootStrapper
from osmaxx.conversion.converters.converter_gis.extract.db_to_format.extract import extract_to
from osmaxx.conversion.converters.utils import zip_folders_relative, recursive_getsize
-from osmaxx.conversion_api.formats import FORMAT_DEFINITIONS
+
+
+def perform_export(
+ *, conversion_format, output_zip_file_path, filename_prefix, out_srs, osmosis_polygon_file_string, detail_level,
+ **__):
+ gis = GISConverter(
+ conversion_format=conversion_format,
+ output_zip_file_path=output_zip_file_path,
+ base_file_name=filename_prefix,
+ out_srs=out_srs,
+ polyfile_string=osmosis_polygon_file_string,
+ detail_level=detail_level
+ )
+ gis.create_gis_export()
QGIS_DISPLAY_SRID = 3857 # Web Mercator
@@ -28,12 +42,13 @@ class ScaleLevel(Enum):
class GISConverter:
- def __init__(self, *, conversion_format, out_zip_file_path, base_file_name, out_srs, polyfile_string, detail_level):
+ def __init__(
+ self, *, conversion_format, output_zip_file_path, base_file_name, out_srs, polyfile_string, detail_level):
"""
Converts a specified pbf into the specified format.
Args:
- out_zip_file_path: path to where the zipped result should be stored, directory must already exist
+ output_zip_file_path: path to where the zipped result should be stored, directory must already exist
conversion_format: One of 'fgdb', 'shapefile', 'gpkg', 'spatialite'
base_file_name: base for created files inside the zip file
@@ -41,7 +56,7 @@ def __init__(self, *, conversion_format, out_zip_file_path, base_file_name, out_
the path to the resulting zip file
"""
self._base_file_name = base_file_name
- self._out_zip_file_path = out_zip_file_path
+ self._out_zip_file_path = output_zip_file_path
self._polyfile_string = polyfile_string
self._conversion_format = conversion_format
self._out_srs = out_srs
@@ -98,7 +113,7 @@ def _dump_qgis_symbology(self, data_location, geom_in_qgis_display_srs, target_d
shutil.copy(qgis_symbology_readme, qgis_symbology_dir)
for scale_level in ScaleLevel:
template = self._env.get_template('OSMaxx_{}.qgs.jinja2'.format(scale_level.name.upper()))
- format_definition = FORMAT_DEFINITIONS[self._conversion_format]
+ format_definition = output_format.DEFINITIONS[self._conversion_format]
template.stream(
data_location=os.path.basename(data_location),
separator=format_definition.qgis_datasource_separator,
diff --git a/osmaxx/conversion/converters/converter_pbf/__init__.py b/osmaxx/conversion/converters/converter_pbf/__init__.py
index e69de29bb..4818980c4 100644
--- a/osmaxx/conversion/converters/converter_pbf/__init__.py
+++ b/osmaxx/conversion/converters/converter_pbf/__init__.py
@@ -0,0 +1,3 @@
+from .to_pbf import produce_pbf as perform_export
+
+__all__ = ['perform_export']
diff --git a/osmaxx/conversion/converters/converter_pbf/to_pbf.py b/osmaxx/conversion/converters/converter_pbf/to_pbf.py
index 563bc149c..dea0bd45b 100644
--- a/osmaxx/conversion/converters/converter_pbf/to_pbf.py
+++ b/osmaxx/conversion/converters/converter_pbf/to_pbf.py
@@ -1,14 +1,13 @@
import os
import shutil
-import subprocess
import tempfile
from django.utils import timezone
from rq import get_current_job
-from osmaxx.conversion._settings import CONVERSION_SETTINGS, odb_license, copying_notice, creative_commons_license
-from osmaxx.conversion.converters.utils import zip_folders_relative, recursive_getsize
+from osmaxx.conversion._settings import CONVERSION_SETTINGS, odb_license
+from osmaxx.conversion.converters.utils import zip_folders_relative, recursive_getsize, logged_check_call
def cut_area_from_pbf(pbf_result_file_path, extent_polyfile_path):
@@ -21,33 +20,32 @@ def cut_area_from_pbf(pbf_result_file_path, extent_polyfile_path):
"-B={}".format(extent_polyfile_path),
"{}".format(CONVERSION_SETTINGS["PBF_PLANET_FILE_PATH"]),
]
- subprocess.check_call(command)
+ logged_check_call(command)
-def polyfile_string_to_pbf(polyfile_string, pbf_out_path):
- polyfile_path = os.path.join('/tmp', 'polyfile_extent.poly')
- with open(polyfile_path, 'w') as f:
- f.write(polyfile_string)
- cut_area_from_pbf(pbf_out_path, polyfile_path)
+def cut_pbf_along_polyfile(polyfile_string, pbf_out_path):
+ with tempfile.NamedTemporaryFile('w') as polyfile:
+ polyfile.write(polyfile_string)
+ polyfile.flush()
+ os.fsync(polyfile)
+ cut_area_from_pbf(pbf_out_path, polyfile.name)
-def produce_pbf(*, out_zip_file_path, area_name, polyfile_string):
+def produce_pbf(*, output_zip_file_path, filename_prefix, osmosis_polygon_file_string, **__):
_start_time = timezone.now()
with tempfile.TemporaryDirectory() as tmp_dir:
out_dir = os.path.join(tmp_dir, 'pbf')
os.makedirs(out_dir, exist_ok=True)
- pbf_out_path = os.path.join(out_dir, area_name + '.pbf')
+ pbf_out_path = os.path.join(out_dir, filename_prefix + '.pbf')
- shutil.copy(copying_notice, out_dir)
shutil.copy(odb_license, out_dir)
- shutil.copy(creative_commons_license, out_dir)
- polyfile_string_to_pbf(polyfile_string, pbf_out_path)
+ cut_pbf_along_polyfile(osmosis_polygon_file_string, pbf_out_path)
unzipped_result_size = recursive_getsize(out_dir)
- zip_folders_relative([tmp_dir], out_zip_file_path)
+ zip_folders_relative([tmp_dir], output_zip_file_path)
job = get_current_job()
if job:
diff --git a/osmaxx/conversion/converters/utils.py b/osmaxx/conversion/converters/utils.py
index ec79c7ea4..64e1d24dc 100644
--- a/osmaxx/conversion/converters/utils.py
+++ b/osmaxx/conversion/converters/utils.py
@@ -1,8 +1,9 @@
+import logging
+import os
+import subprocess
import uuid
import zipfile
-import os
-
# Use the built-in version of scandir if possible, otherwise
# use the scandir module version
try:
@@ -10,6 +11,8 @@
except ImportError:
from scandir import scandir
+logger = logging.getLogger(__name__)
+
def zip_folders_relative(folder_list, zip_out_file_path=None):
"""
@@ -42,3 +45,11 @@ def recursive_getsize(path):
elif entry.is_dir(follow_symlinks=False):
size += recursive_getsize(os.path.join(path, entry.path))
return size
+
+
+def logged_check_call(*args, **kwargs):
+ try:
+ subprocess.check_call(*args, **kwargs)
+ except subprocess.CalledProcessError as e:
+ logger.error('Command `{}` exited with return value {}\nOutput:\n{}'.format(e.cmd, e.returncode, e.output))
+ raise
diff --git a/osmaxx/conversion/management/commands/result_harvester.py b/osmaxx/conversion/management/commands/result_harvester.py
index a40470f0a..59997ab06 100644
--- a/osmaxx/conversion/management/commands/result_harvester.py
+++ b/osmaxx/conversion/management/commands/result_harvester.py
@@ -12,7 +12,7 @@
from osmaxx.conversion import models as conversion_models
from osmaxx.conversion._settings import CONVERSION_SETTINGS
-from osmaxx.conversion_api.statuses import FINAL_STATUSES, FINISHED, FAILED
+from osmaxx.conversion.constants.statuses import FINAL_STATUSES, FINISHED, FAILED
logging.basicConfig()
logger = logging.getLogger(__name__)
diff --git a/osmaxx/conversion/models.py b/osmaxx/conversion/models.py
index 6421ad503..3901ae5fa 100644
--- a/osmaxx/conversion/models.py
+++ b/osmaxx/conversion/models.py
@@ -7,12 +7,12 @@
from django.utils.translation import gettext_lazy as _
from rest_framework.reverse import reverse
+from osmaxx.conversion import output_format
from osmaxx.clipping_area.models import ClippingArea
from osmaxx.conversion.converters.converter import convert
-from osmaxx.conversion.converters.detail_levels import DETAIL_LEVEL_CHOICES, DETAIL_LEVEL_ALL
-from osmaxx.conversion_api.coordinate_reference_systems import CRS_CHOICES
-from osmaxx.conversion_api.formats import FORMAT_CHOICES
-from osmaxx.conversion_api.statuses import STATUS_CHOICES, RECEIVED
+from osmaxx.conversion.converters.converter_gis.detail_levels import DETAIL_LEVEL_CHOICES, DETAIL_LEVEL_ALL
+from osmaxx.conversion.constants.coordinate_reference_systems import CRS_CHOICES
+from osmaxx.conversion.constants.statuses import STATUS_CHOICES, RECEIVED
def job_directory_path(instance, filename):
@@ -20,7 +20,7 @@ def job_directory_path(instance, filename):
class Parametrization(models.Model):
- out_format = models.CharField(verbose_name=_("out format"), choices=FORMAT_CHOICES, max_length=100)
+ out_format = models.CharField(verbose_name=_("out format"), choices=output_format.CHOICES, max_length=100)
out_srs = models.IntegerField(
verbose_name=_("output SRS"), help_text=_("EPSG code of the output spatial reference system"),
null=True, blank=True, default=4326, choices=CRS_CHOICES
diff --git a/osmaxx/conversion/serializers.py b/osmaxx/conversion/serializers.py
index 4bfef9511..1d308d41a 100644
--- a/osmaxx/conversion/serializers.py
+++ b/osmaxx/conversion/serializers.py
@@ -1,8 +1,8 @@
from rest_framework import serializers
-from osmaxx.conversion.converters import detail_levels
+from osmaxx.conversion import output_format
+from osmaxx.conversion.converters.converter_gis import detail_levels
from osmaxx.conversion.size_estimator import size_estimation_for_format
-from osmaxx.conversion_api import formats
from .models import Job, Parametrization
@@ -41,7 +41,7 @@ def validate(self, data):
data.update(
{
output_format: size_estimation_for_format(output_format, detail_level, estimated_pbf)
- for output_format in formats.FORMAT_DEFINITIONS
+ for output_format in output_format.DEFINITIONS
}
)
return data
diff --git a/osmaxx/conversion/size_estimator.py b/osmaxx/conversion/size_estimator.py
index 57c9cbeff..69d5aa7a3 100644
--- a/osmaxx/conversion/size_estimator.py
+++ b/osmaxx/conversion/size_estimator.py
@@ -1,37 +1,36 @@
import math
+from osmaxx.conversion import output_format
+from osmaxx.conversion.converters.converter_gis import detail_levels
from osmaxx.conversion.models import Job
-from osmaxx.conversion_api import formats
-from osmaxx.conversion.converters import detail_levels
-
PRE_DATA = {
- formats.GARMIN: {
+ output_format.GARMIN: {
'pbf_predicted': [25000, 44000, 96000, 390000],
detail_levels.DETAIL_LEVEL_ALL: [11000, 18000, 42000, 95000],
detail_levels.DETAIL_LEVEL_REDUCED: [11000, 18000, 42000, 95000],
},
- formats.PBF: {
+ output_format.PBF: {
'pbf_predicted': [25000, 44000, 96000, 390000],
detail_levels.DETAIL_LEVEL_ALL: [25000, 44000, 96000, 390000],
detail_levels.DETAIL_LEVEL_REDUCED: [25000, 44000, 96000, 390000],
},
- formats.FGDB: {
+ output_format.FGDB: {
'pbf_predicted': [25000, 44000, 96000, 390000],
detail_levels.DETAIL_LEVEL_ALL: [46000, 101000, 309000, 676000],
detail_levels.DETAIL_LEVEL_REDUCED: [21000, 27000, 107000, 250000],
},
- formats.GPKG: {
+ output_format.GPKG: {
'pbf_predicted': [25000, 44000, 96000, 390000],
detail_levels.DETAIL_LEVEL_ALL: [109000, 210000, 690000, 1500000],
detail_levels.DETAIL_LEVEL_REDUCED: [49000, 58000, 252000, 599000],
},
- formats.SHAPEFILE: {
+ output_format.SHAPEFILE: {
'pbf_predicted': [25000, 44000, 96000, 390000],
detail_levels.DETAIL_LEVEL_ALL: [255000, 638000, 2000000, 4400000],
detail_levels.DETAIL_LEVEL_REDUCED: [100000, 138000, 652000, 1600000],
},
- formats.SPATIALITE: {
+ output_format.SPATIALITE: {
'pbf_predicted': [25000, 44000, 96000, 390000],
detail_levels.DETAIL_LEVEL_ALL: [115000, 216000, 719000, 1600000],
detail_levels.DETAIL_LEVEL_REDUCED: [55000, 66000, 269000, 635000],
@@ -50,7 +49,7 @@ def size_estimation_for_format(format_type, detail_level, predicted_pbf_size):
def get_data(format_type, detail_level):
- assert format_type in formats.FORMAT_DEFINITIONS
+ assert format_type in output_format.DEFINITIONS
assert detail_level in [level[0] for level in detail_levels.DETAIL_LEVEL_CHOICES]
base_query_set = Job.objects.filter(
parametrization__out_format=format_type,
diff --git a/osmaxx/conversion_api/__init__.py b/osmaxx/conversion_api/__init__.py
deleted file mode 100644
index aeff70cec..000000000
--- a/osmaxx/conversion_api/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-"""
-Interface between OSMaxx frontend (Django-based web client) and the OSMaxx conversion service (mediator and worker).
-
-This Django app holds shared code. All OSMaxx components (frontend & conversion service) may depend on it.
-No code in this app may depend on other OSMaxx Django apps, especially not the component-specific ones.
-
-The OSMaxx conversion service implementation (provided by the mediator) is located in Django app `conversion`,
-not here in app `conversion_api`.
-"""
diff --git a/tests/utilities/__init__.py b/osmaxx/core/__init__.py
similarity index 100%
rename from tests/utilities/__init__.py
rename to osmaxx/core/__init__.py
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil_wgs-84_2016-11-17_gpkg_full-detail.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_fgdb_full-detail.zip
similarity index 71%
rename from osmaxx/core/static/osmaxx/example_data/rapperswil_wgs-84_2016-11-17_gpkg_full-detail.zip
rename to osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_fgdb_full-detail.zip
index 894df7c7d..d5dcfebe4 100644
Binary files a/osmaxx/core/static/osmaxx/example_data/rapperswil_wgs-84_2016-11-17_gpkg_full-detail.zip and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_fgdb_full-detail.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_fgdb_simplified.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_fgdb_simplified.zip
new file mode 100644
index 000000000..76056bd99
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_fgdb_simplified.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_garmin_full-detail.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_garmin_full-detail.zip
new file mode 100644
index 000000000..1e208b182
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_garmin_full-detail.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_gpkg_full-detail.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_gpkg_full-detail.zip
new file mode 100644
index 000000000..61b2a4dc8
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_gpkg_full-detail.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_gpkg_simplified.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_gpkg_simplified.zip
new file mode 100644
index 000000000..6bee9cd50
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_gpkg_simplified.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_pbf_full-detail.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_pbf_full-detail.zip
new file mode 100644
index 000000000..c2caf700d
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_pbf_full-detail.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_shapefile_full-detail.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_shapefile_full-detail.zip
new file mode 100644
index 000000000..8947060c2
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_shapefile_full-detail.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_shapefile_simplified.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_shapefile_simplified.zip
new file mode 100644
index 000000000..b787250f5
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_shapefile_simplified.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_spatialite_full-detail.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_spatialite_full-detail.zip
new file mode 100644
index 000000000..87b6221ad
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_spatialite_full-detail.zip differ
diff --git a/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_spatialite_simplified.zip b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_spatialite_simplified.zip
new file mode 100644
index 000000000..a176a1581
Binary files /dev/null and b/osmaxx/core/static/osmaxx/example_data/rapperswil-jona_wgs-84_2017-03-20_spatialite_simplified.zip differ
diff --git a/osmaxx/core/static/osmaxx/images/homepage_screenshot.png b/osmaxx/core/static/osmaxx/images/homepage_screenshot.png
new file mode 100644
index 000000000..27b4cbf2b
Binary files /dev/null and b/osmaxx/core/static/osmaxx/images/homepage_screenshot.png differ
diff --git a/osmaxx/core/static/osmaxx/stylesheets/main.css b/osmaxx/core/static/osmaxx/stylesheets/main.css
index 37728f0b2..06cff7c95 100644
--- a/osmaxx/core/static/osmaxx/stylesheets/main.css
+++ b/osmaxx/core/static/osmaxx/stylesheets/main.css
@@ -282,4 +282,4 @@ footer a:link,
footer a:visited,
footer a:hover,
footer a:focus,
-footer a:active { color: white; background-color: rgb(50, 110, 160); padding: 4px 4px; }
+footer a:active { color: white; }
diff --git a/osmaxx/core/templates/base.html b/osmaxx/core/templates/base.html
index db8b88860..4f6d19df0 100644
--- a/osmaxx/core/templates/base.html
+++ b/osmaxx/core/templates/base.html
@@ -1,7 +1,7 @@
{% load staticfiles i18n %}
-
+{# needed for Open Graph metatags in osmaxx/core/templates/osmaxx/base.html #}
diff --git a/osmaxx/core/templates/osmaxx/base.html b/osmaxx/core/templates/osmaxx/base.html
index 84fff4374..a0251ade7 100644
--- a/osmaxx/core/templates/osmaxx/base.html
+++ b/osmaxx/core/templates/osmaxx/base.html
@@ -1,9 +1,20 @@
{% extends 'base.html' %}
-{% load staticfiles %}
+{% load staticfiles navigation %}
{% block extra_head %}
OSMaxx
+
+
+
+
+
+
+
+
+
+
+
diff --git a/osmaxx/core/templates/osmaxx/login.html b/osmaxx/core/templates/osmaxx/login.html
index 85aebde14..083e19d91 100644
--- a/osmaxx/core/templates/osmaxx/login.html
+++ b/osmaxx/core/templates/osmaxx/login.html
@@ -22,6 +22,6 @@
{% trans 'Login' %}
{% endblocktrans %}
- Log in using OpenStreetMap
+ Log in using OpenStreetMap
{% endblock %}
diff --git a/osmaxx/core/templates/pages/downloads.html b/osmaxx/core/templates/pages/downloads.html
index 8a33879b9..0882afbc3 100644
--- a/osmaxx/core/templates/pages/downloads.html
+++ b/osmaxx/core/templates/pages/downloads.html
@@ -10,12 +10,60 @@
Downloads
Here you can find additional downloads and some useful links to similar projects.
-
Styles
-
Sample Export
+
Sample Exports
- As an export example, we provide an example export featuring "Rapperswil"
- rapperswil_wgs-84_2016-11-17_gpkg_full-detail.zip.
+ The following sample exports feature excerpt "Rapperswil-Jona".
+
{% trans 'Please Contact Your Administrator or Request Access' %}
-
- {% blocktrans %}You do not appear to have the proper access rights. Please contact your
- supervisor/administrator and ask for the needed access rights.{% endblocktrans %}
-
-
-
New account
-
- {% blocktrans %}If you logged in by a new OpenStreetMap-account, please request its activation: {% endblocktrans %}
-