Porównaj commity

...

16 Commity

Autor SHA1 Wiadomość Data
Hartmut Holzgraefe ee5ad39915 fully fix issue #24 allowing for bounding box / city merge 2023-10-31 00:13:13 +00:00
Hartmut Holzgraefe 6b3309f593 add some comments 2023-10-30 22:13:58 +00:00
Hartmut Holzgraefe cc4feb7885 OCitysMap base installation path no longer hardcoded 2023-10-30 22:10:36 +00:00
Hartmut Holzgraefe 60cf27ad0e typo fix 2023-10-30 22:02:43 +00:00
Hartmut Holzgraefe 0563245851 remove unneeded extra context_processor 2023-10-30 22:01:22 +00:00
Hartmut Holzgraefe 38e6ca7d9e split up feeds.py - finished 2023-10-29 11:05:07 +00:00
Hartmut Holzgraefe bee31b3fbf split feeds.py - WiP 2023-10-29 10:28:40 +00:00
Hartmut Holzgraefe 2e88738617 split up feeds.py - WiP 2023-10-29 10:19:37 +00:00
Hartmut Holzgraefe e73905c62e reorder settings context entries 2023-10-29 06:43:41 +00:00
Hartmut Holzgraefe 9a37d9dcc2 whitespace/formatting only 2023-10-29 01:21:49 +00:00
Hartmut Holzgraefe fb0b362220 restore wrongly removed method, remove correct one 2023-10-28 16:55:05 +00:00
Hartmut Holzgraefe a46d555a07 finish split of views.py and apis.py 2023-10-25 19:17:27 +00:00
Hartmut Holzgraefe 53cbb56d26 more views and apis file splitting (WiP) 2023-10-24 17:11:25 +00:00
Hartmut Holzgraefe 9a9e240748 preparing to split up APIs file 2023-10-24 12:26:51 +00:00
Hartmut Holzgraefe f992156c70 splitting up the large views file into smaller units (WiP) 2023-10-24 05:05:55 +00:00
Hartmut Holzgraefe 1b9d930b50 remove some unused functions 2023-10-23 21:14:15 +00:00
42 zmienionych plików z 1954 dodań i 1164 usunięć

Wyświetl plik

@ -452,7 +452,7 @@ class JobRenderer(threading.Thread):
config.title = self.job.maptitle
config.osmid = self.job.administrative_osmid
if config.osmid:
if config.osmid and not self.job.lat_upper_left:
bbox_wkt, area_wkt \
= renderer.get_geographic_info(config.osmid)
config.bounding_box = ocitysmap.coords.BoundingBox.parse_wkt(

Wyświetl plik

@ -0,0 +1,20 @@
# public API calls
from .styles import styles
from .overlays import overlays
from .paper_formats import paper_formats
from .layouts import layouts
from .jobs import jobs
from .job_stati import job_stati
from .cancel_job import cancel_job
# private API calls
from .papersize import api_papersize
from .bbox import api_bbox
from .polygon import api_polygon
from .rendering_status import api_rendering_status
from .heatmap import heatdata
from .reverse_country_lookup import api_postgis_reverse
from .places_db_search import api_geosearch
from .nominatim_search import api_nominatim

Wyświetl plik

@ -0,0 +1,48 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse, HttpResponseBadRequest
import ocitysmap
import www.settings
from www.maposmatic import helpers, forms, nominatim, models
def api_bbox(request, osm_id):
"""API handler that returns the bounding box from an OSM ID polygon."""
try:
osm_id = int(osm_id)
except ValueError:
return HttpResponseBadRequest("ERROR: Invalid arguments")
renderer = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
try:
bbox_wkt, area_wkt = renderer.get_geographic_info(osm_id)
bbox = ocitysmap.coords.BoundingBox.parse_wkt(bbox_wkt)
return HttpResponse(content=json.dumps(bbox.as_json_bounds()),
content_type='text/json')
except:
LOG.exception("Error calculating bounding box for OSM ID %d!" % osm_id)
return HttpResponseBadRequest("ERROR: OSM ID %d not found!" % osm_id)

Wyświetl plik

@ -0,0 +1,59 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse, HttpResponseNotAllowed, HttpResponseBadRequest, HttpResponseForbidden
from django.shortcuts import get_object_or_404
from django.forms.models import model_to_dict
import ocitysmap
import www.settings
from www.maposmatic import helpers, forms, models
def cancel_job(request):
"""API handler for canceling rendering requests"""
if request.method != 'POST':
return HttpResponseNotAllowed(['POST'])
if request.content_type == 'application/json':
input = json.loads(request.body.decode('utf-8-sig'))
else:
input = json.loads(request.POST['job'])
if not "id" in input or not "nonce" in input:
return HttpResponseBadRequest()
job = get_object_or_404(models.MapRenderingJob, id = input['id'])
reply = model_to_dict(job)
if input['nonce'] != reply['nonce']:
return HttpResponseForbidden()
if job.is_waiting():
job.cancel()
return HttpResponse(status=204)

Wyświetl plik

@ -0,0 +1,82 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse
from django.db import connections
import ocitysmap
import www.settings
from www.maposmatic import helpers, forms, models
def heatdata(request, days=1):
query = """
select round(lat::numeric, 4)::float as lat
, round(lng::numeric, 4)::float as lng
, count(*) as count
from (
select (lat_upper_left + lat_bottom_right)/2 as lat
, (lon_upper_left + lon_bottom_right)/2 as lng
from maposmatic_maprenderingjob
where lat_upper_left is not null
and submission_time BETWEEN LOCALTIMESTAMP - INTERVAL '%s days' AND LOCALTIMESTAMP
union
select (north + south)/2 as lat
, (west + east)/2 as lng
from maposmatic_maprenderingjob m
left outer join dblink('dbname=gis', 'SELECT osm_id, west, east, north, south FROM place') AS p(osm_id bigint, west float, east float, north float, south float)
on -m.administrative_osmid = p.osm_id
where m.administrative_osmid is not null
and submission_time BETWEEN LOCALTIMESTAMP - INTERVAL '%s days' AND LOCALTIMESTAMP
) x group by lat, lng;
;
""" % (days, days)
data = { "max": 8, "data": [] }
try:
cursor = connections['default'].cursor()
if cursor is None:
raise Http404("postgis: no cursor")
cursor.execute(query)
columns = [col[0] for col in cursor.description]
for row in cursor.fetchall():
data["data"].append(dict(zip(columns, row)))
cursor.close()
return HttpResponse(content="var data = " + json.dumps(data, indent=2),
content_type='application/javascript')
except Exception as e:
raise RuntimeError(e)

Wyświetl plik

@ -0,0 +1,52 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse
import ocitysmap
import www.settings
def _job_stati_dict(id = None):
# TODO do not hard-code these, get them from OCitysMap cleanly
result = {
"0": "Submitted",
"1": "In progress",
"2": "Done",
"3": "Done w/o files",
"4": "Cancelled"
}
if id is not None:
return result[str(id)]
return result
def job_stati(request):
return HttpResponse( content=json.dumps(_job_stati_dict(),
indent = 4,
sort_keys = True,
default = str),
content_type='text/json')

Wyświetl plik

@ -1,7 +1,7 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2018 Hartmut Holzgraefe
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -16,157 +16,31 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# API calls for MapOSMatic
from os import path
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.core.exceptions import ValidationError
from django.core.files import File
from django.core.files.base import ContentFile
from django.http import HttpResponseRedirect, HttpResponseBadRequest, HttpResponseNotFound, HttpResponse, HttpResponseNotAllowed, HttpResponseForbidden, Http404
from django.forms.models import model_to_dict
from django.shortcuts import get_object_or_404
from django.db import connections
import ocitysmap
from www.maposmatic import helpers, forms, nominatim, models
import www.settings
import urllib.parse
import gpxpy
import gpxpy.gpx
import requests
from tempfile import NamedTemporaryFile
import urllib.parse
import logging
LOG = logging.getLogger('maposmatic')
def styles(request):
result = {}
for style in ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH).get_all_style_configurations():
result[style.name] = { "description": style.description,
"annotation": style.annotation,
"preview_url": request.build_absolute_uri('/media/img/style/'+style.name+'.png')
}
from django.http import HttpResponse, HttpResponseNotFound, HttpResponseNotAllowed
from django.shortcuts import get_object_or_404
from django.forms.models import model_to_dict
from django.core.exceptions import ValidationError
from django.core.files import File
from django.core.files.base import ContentFile
return HttpResponse( content=json.dumps(result, indent=4, sort_keys=True, default=str), content_type='text/json')
import ocitysmap
def overlays(request):
result = {}
for overlay in ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH).get_all_overlay_configurations():
result[overlay.name] = { "description": overlay.description,
"annotation": overlay.annotation,
"preview_url": request.build_absolute_uri('/media/img/overlay/'+overlay.name+'.png')
}
return HttpResponse( content=json.dumps(result, indent=4, sort_keys=True, default=str), content_type='text/json')
def paper_formats(request):
_ocitysmap = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
result = {}
for p in _ocitysmap.get_all_paper_sizes():
if p[1] and p[2]:
result[p[0]] = {'width': p[1], 'height': p[2]}
return HttpResponse( content=json.dumps(result, indent=4, sort_keys=True, default=str), content_type='text/json')
def layouts(request):
result = {}
for renderer in ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH).get_all_renderers():
result[renderer.name] = { "description": renderer.description,
"preview_url": request.build_absolute_uri('/media/img/layout/'+renderer.name+'.png')
}
return HttpResponse( content=json.dumps(result, indent=4, sort_keys=True, default=str), content_type='text/json')
def job_stati_dict(id = None):
# TODO do not hard-code these, get them from OCitysMap cleanly
result = {
"0": "Submitted",
"1": "In progress",
"2": "Done",
"3": "Done w/o files",
"4": "Cancelled"
}
if id is not None:
return result[str(id)]
return result
def job_stati(request):
return HttpResponse( content=json.dumps(job_stati_dict(), indent=4, sort_keys=True, default=str), content_type='text/json')
def heatdata(request, days=1):
query = """
select round(lat::numeric, 4)::float as lat
, round(lng::numeric, 4)::float as lng
, count(*) as count
from (
select (lat_upper_left + lat_bottom_right)/2 as lat
, (lon_upper_left + lon_bottom_right)/2 as lng
from maposmatic_maprenderingjob
where lat_upper_left is not null
and submission_time BETWEEN LOCALTIMESTAMP - INTERVAL '%s days' AND LOCALTIMESTAMP
union
select (north + south)/2 as lat
, (west + east)/2 as lng
from maposmatic_maprenderingjob m
left outer join dblink('dbname=gis', 'SELECT osm_id, west, east, north, south FROM place') AS p(osm_id bigint, west float, east float, north float, south float)
on -m.administrative_osmid = p.osm_id
where m.administrative_osmid is not null
and submission_time BETWEEN LOCALTIMESTAMP - INTERVAL '%s days' AND LOCALTIMESTAMP
) x group by lat, lng;
;
""" % (days, days)
data = { "max": 8, "data": [] }
try:
cursor = connections['default'].cursor()
if cursor is None:
raise Http404("postgis: no cursor")
cursor.execute(query)
columns = [col[0] for col in cursor.description]
for row in cursor.fetchall():
data["data"].append(dict(zip(columns, row)))
cursor.close()
return HttpResponse(content="var data = " + json.dumps(data, indent=2),
content_type='application/javascript')
except Exception as e:
raise RuntimeError(e)
def jobs(request, job_id=False):
"""API handler for external rendering requests"""
if request.method == 'GET':
return _jobs_get(request, job_id)
elif request.method == 'POST':
return _jobs_post(request)
else:
return HttpResponseNotAllowed(['GET','POST'])
import www.settings
from www.maposmatic import helpers, forms, nominatim, models
from .job_stati import _job_stati_dict
def _jobs_get(request, job_id):
if not job_id:
@ -179,7 +53,7 @@ def _jobs_get(request, job_id):
result = {}
result['id'] = int(job_id)
result['status'] = reply['status']
result['status_msg'] = job_stati_dict(reply['status'])
result['status_msg'] = _job_stati_dict(reply['status'])
if reply['administrative_osmid']:
result['osm_id'] = reply['administrative_osmid']
@ -489,8 +363,6 @@ def _jobs_post(request):
return HttpResponse( content=json.dumps(result, indent=4, sort_keys=True, default=str)
, content_type='text/json', status=status)
def _no_geometry(job):
return not job.administrative_osmid and not job.lat_upper_left
@ -651,58 +523,15 @@ def _process_poi_file(file):
return result
def cancel_job(request):
"""API handler for canceling rendering requests"""
if request.method != 'POST':
return HttpResponseNotAllowed(['POST'])
def jobs(request, job_id=False):
"""API handler for external rendering requests"""
if request.content_type == 'application/json':
input = json.loads(request.body.decode('utf-8-sig'))
if request.method == 'GET':
return _jobs_get(request, job_id)
elif request.method == 'POST':
return _jobs_post(request)
else:
input = json.loads(request.POST['job'])
return HttpResponseNotAllowed(['GET','POST'])
if not "id" in input or not "nonce" in input:
return HttpResponseBadRequest()
job = get_object_or_404(models.MapRenderingJob, id = input['id'])
reply = model_to_dict(job)
if input['nonce'] != reply['nonce']:
return HttpResponseForbidden()
if job.is_waiting():
job.cancel()
return HttpResponse(status=204)
def get_paper_from_size(w, h):
oc = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
paper_size = None
paper_orientation = "landscape" if (w > h) else "portrait"
for paper in oc.get_all_paper_sizes():
if int(paper[1]) == w and int(paper[2]) == h:
paper_size = paper[0]
break
if int(paper[1]) == h and int(paper[2]) == w:
paper_size = paper[0]
break
return paper_size, paper_orientation
def api_reverse_papersize(request, w, h):
"""API to do a reverse papersize name lookup by width and height"""
w = int(w)
h = int(h)
paper_size, paper_orientation = get_paper_from_size(w, h)
if paper_size:
return HttpResponse(content=json.dumps((paper_size, paper_orientation)),
content_type='text/json')
else:
return HttpResponseBadRequest("ERROR: Paper size not found")

Wyświetl plik

@ -0,0 +1,43 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse
import ocitysmap
import www.settings
def layouts(request):
result = {}
for renderer in ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH).get_all_renderers():
result[renderer.name] = { "description": renderer.description,
"preview_url": request.build_absolute_uri('/media/img/layout/'+renderer.name+'.png')
}
return HttpResponse( content=json.dumps(result,
indent = 4,
sort_keys = True,
default = str),
content_type='text/json')

Wyświetl plik

@ -0,0 +1,64 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse
import www.settings
from www.maposmatic import nominatim
def api_nominatim(request):
"""Nominatim query gateway."""
exclude = request.GET.get('exclude', '')
squery = request.GET.get('q', '')
lang = None
if 'HTTP_ACCEPT_LANGUAGE' in request.META:
# Accept-Language headers typically look like
# fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3. Unfortunately,
# Nominatim behaves improperly with such a string: it gives
# the region name in French, but the country name in
# English. We split at the first comma to only keep the
# preferred language, which makes Nominatim work properly.
lang = request.META['HTTP_ACCEPT_LANGUAGE'].split(',')[0]
try:
contents = nominatim.query(squery, exclude, with_polygons=False,
accept_language=lang)
except Exception as e:
LOG.exception("Error querying Nominatim")
contents = []
return HttpResponse(content=json.dumps(contents),
content_type='text/json')

Wyświetl plik

@ -0,0 +1,42 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse
import ocitysmap
import www.settings
def overlays(request):
result = {}
for overlay in ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH).get_all_overlay_configurations():
result[overlay.name] = { "description": overlay.description,
"annotation": overlay.annotation,
"preview_url": request.build_absolute_uri('/media/img/overlay/'+overlay.name+'.png')
}
return HttpResponse( content=json.dumps(result,
indent = 4,
sort_keys = True,
default = str),
content_type='text/json')

Wyświetl plik

@ -0,0 +1,42 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse
import ocitysmap
import www.settings
def paper_formats(request):
_ocitysmap = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
result = {}
for p in _ocitysmap.get_all_paper_sizes():
if p[1] and p[2]:
result[p[0]] = {'width': p[1], 'height': p[2]}
return HttpResponse( content=json.dumps(result,
indent = 4,
sort_keys = True,
default = str),
content_type='text/json')

Wyświetl plik

@ -0,0 +1,78 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse, HttpResponseBadRequest
import ocitysmap
import www.settings
from www.maposmatic import helpers, forms, nominatim, models
def api_papersize(request):
"""API handler to get the compatible paper sizes for the provided layout
and bounding box."""
if request.method != 'POST':
return HttpResponseBadRequest("ERROR: Bad request")
f = forms.MapPaperSizeForm(request.POST)
if not f.is_valid():
return HttpResponseBadRequest("ERROR: Invalid arguments")
renderer = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
osmid = f.cleaned_data.get('osmid')
layout = f.cleaned_data.get('layout')
stylesheet = renderer.get_stylesheet_by_name(
f.cleaned_data.get('stylesheet'))
# Determine geographic area
if osmid is not None:
try:
bbox_wkt, area_wkt = renderer.get_geographic_info(osmid)
except ValueError:
LOG.exception("Error determining compatible paper sizes")
raise
bbox = ocitysmap.coords.BoundingBox.parse_wkt(bbox_wkt)
else:
lat_upper_left = f.cleaned_data.get("lat_upper_left")
lon_upper_left = f.cleaned_data.get("lon_upper_left")
lat_bottom_right = f.cleaned_data.get("lat_bottom_right")
lon_bottom_right = f.cleaned_data.get("lon_bottom_right")
# Check we have correct floats
if (lat_upper_left == None or lon_upper_left == None
or lat_bottom_right == None or lon_bottom_right == None):
return HttpResponseBadRequest("ERROR: Invalid arguments")
bbox = ocitysmap.coords.BoundingBox(
lat_upper_left, lon_upper_left,
lat_bottom_right, lon_bottom_right)
renderer_cls = ocitysmap.renderers.get_renderer_class_by_name(layout)
paper_sizes = sorted(renderer_cls.get_compatible_paper_sizes(bbox, renderer),
key = lambda p: p['width'])
return HttpResponse(content=json.dumps(paper_sizes),
content_type='text/json')

Wyświetl plik

@ -0,0 +1,142 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse, Http404
from django.db import connections
from django.db.transaction import TransactionManagementError
import ocitysmap
import www.settings
def api_geosearch(request):
"""Simple place name search."""
exclude = request.GET.get('exclude', '')
squery = request.GET.get('q', '')
squery = squery.lower()
contents = { "entries": [] }
cursor = None
if www.settings.MAX_BOUNDING_BOX:
m = www.settings.MAX_BOUNDING_BOX
max_bbox = "ST_GeomFromText('POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))', 4326)" % (m[1], m[0], m[1], m[2], m[3], m[2], m[3], m[0], m[1], m[0])
pt_bbox = 'AND ST_Contains(ST_Transform(%s, 3857), pt.way)' % max_bbox
poly_bbox = 'AND ST_Contains(ST_Transform(%s, 3857), poly.way)' % max_bbox
else:
pt_bbox = ''
poly_bbox = ''
query = """SELECT p.name
, p.display_name
, p.class
, p.type
, p.osm_type
, p.osm_id
, p.lat
, p.lon
, p.west
, p.east
, p.north
, p.south
, p.place_rank
, p.importance
, p.country_code
FROM place p
LEFT JOIN planet_osm_hstore_point pt
ON p.osm_id = pt.osm_id
%s -- optionally filter by max bbox
LEFT JOIN planet_osm_hstore_polygon poly
ON - p.osm_id = poly.osm_id
%s -- optionally filter by max bbox
WHERE LOWER(p.name) = %%s
AND ( pt.osm_id IS NOT NULL
OR poly.osm_id IS NOT NULL
)
ORDER BY p.place_rank
, p.importance DESC
""" % (pt_bbox, poly_bbox)
try:
cursor = connections['osm'].cursor()
if cursor is None:
raise Http404("postgis: no cursor")
cursor.execute(query, [ squery ])
columns = [col[0] for col in cursor.description]
for row in cursor.fetchall():
values = dict(zip(columns, row))
values["boundingbox"] = "%f,%f,%f,%f" % (values["south"], values["north"], values["west"], values["east"])
bbox = ocitysmap.coords.BoundingBox(values["south"], values["west"], values["north"], values["east"])
(metric_size_lat, metric_size_lon) = bbox.spheric_sizes()
LOG.warning("metric lat/lon %f : %f - %f" % (metric_size_lat, metric_size_lon, www.settings.BBOX_MAXIMUM_LENGTH_IN_METERS))
if values["osm_type"] == "node":
values["icon"] = "../media/img/place-node.png"
values["ocitysmap_params"] = {
"valid": False,
"reason": "no-admin",
"reason_text": "No administrative boundary"
}
else:
values["icon"] = "../media/img/place-polygon.png"
if (metric_size_lat > www.settings.BBOX_MAXIMUM_LENGTH_IN_METERS
or metric_size_lon > www.settings.BBOX_MAXIMUM_LENGTH_IN_METERS):
valid = False
reason = "area-too-big"
reason_text = gettext("Administrative area too big for rendering")
else:
valid = True
reason = ""
reason_text = ""
values["ocitysmap_params"] = {
"valid": valid,
"table": "polygon",
"id": -values["osm_id"],
"reason": reason,
"reason_text": reason_text
}
contents["entries"].append(values)
cursor.close()
return HttpResponse(content=json.dumps(contents),
content_type='text/json')
except Exception as e:
raise TransactionManagementError(e)

Wyświetl plik

@ -0,0 +1,49 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse, HttpResponseBadRequest
import ocitysmap
import www.settings
from www.maposmatic import helpers, forms, nominatim, models
def api_polygon(request, osm_id):
"""API handler that returns the polygon outline from an OSM ID polygon."""
try:
osm_id = int(osm_id)
except ValueError:
return HttpResponseBadRequest("ERROR: Invalid arguments")
renderer = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
try:
bbox_wkt, area_wkt = renderer.get_geographic_info(osm_id)
bbox = ocitysmap.coords.BoundingBox.parse_wkt(bbox_wkt).as_json_bounds()
return HttpResponse(content=json.dumps({'bbox': bbox, 'wkt': area_wkt}),
content_type='text/json')
except:
LOG.exception("Error retrieving polygon outline for OSM ID %d!" % osm_id)
return HttpResponseBadRequest("ERROR: OSM ID %d not found!" % osm_id)

Wyświetl plik

@ -0,0 +1,63 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404, render
import ocitysmap
import www.settings
from www.maposmatic import helpers, forms, nominatim, models
def api_rendering_status(request, id, nonce=None):
"""API handler for updating map request rendering status"""
try:
id = int(id)
except ValueError:
return HttpResponseBadRequest("ERROR: Invalid arguments")
job = get_object_or_404(models.MapRenderingJob, id=id)
isredirected = request.session.get('redirected', False)
request.session.pop('redirected', None)
queue_size = job.index_queue_at_submission
progress = 100
if queue_size:
progress = int(100 * (queue_size -
job.current_position_in_queue()) / float(queue_size))
refresh = job.is_rendering() and \
www.settings.REFRESH_JOB_RENDERING or \
www.settings.REFRESH_JOB_WAITING
return render(request, 'maposmatic/map-full-parts/rendering-status.html',
{ 'map': job,
'redirected': isredirected,
'nonce': nonce,
'refresh': refresh,
'progress': progress,
'queue_size': queue_size,
'status': job.renderstep or "working",
})

Wyświetl plik

@ -0,0 +1,63 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.http import HttpResponse, Http404
from django.db import connections
def api_postgis_reverse(request, lat, lon):
lat = float(lat)
lon = float(lon)
cursor = None
query = """select country_code
from country_osm_grid
where st_contains(geometry,
st_geomfromtext('POINT(%f %f)', 4326))
""" % (lon, lat)
LOG.debug("Reverse Lookup Query %s" % query)
try:
connections['osm'].rollback() # make sure there's no pending transaction
cursor = connections['osm'].cursor()
cursor.execute(query)
country_code = cursor.fetchone()
cursor.close()
if country_code is None or len(country_code) < 1:
raise Http404("postgis: country not found")
return HttpResponse('{"address": {"country_code": "%s"}}' % country_code[0], content_type='text/json')
except Exception as e:
LOG.warning("reverse geo lookup failed: %s" % e)
pass
finally:
# Close the DB cursor if necessary
if cursor is not None and not cursor.closed:
cursor.close()
raise Http404("postgis: something went wrong")

Wyświetl plik

@ -0,0 +1,44 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import json
from django.http import HttpResponse
import ocitysmap
import www.settings
def styles(request):
result = {}
for style in ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH).get_all_style_configurations():
result[style.name] = { "description": style.description,
"annotation": style.annotation,
"preview_url": request.build_absolute_uri('/media/img/style/'+style.name+'.png')
}
return HttpResponse( content = json.dumps(result,
indent = 4,
sort_keys = True,
default = str),
content_type = 'text/json')

Wyświetl plik

@ -202,45 +202,41 @@ def all(request):
platform_status = 'hourglas-clock'
return {
'DEBUG': www.settings.DEBUG,
'LANGUAGES': www.settings.LANGUAGES,
'LANGUAGES_LIST': www.settings.LANGUAGES_LIST,
'LANGUAGE_FLAGS': www.settings.LANGUAGE_FLAGS,
'MAP_LANGUAGES': www.settings.MAP_LANGUAGES,
'BBOX_MAXIMUM_LENGTH_IN_METERS': www.settings.BBOX_MAXIMUM_LENGTH_IN_METERS,
'BRAND_NAME': www.settings.BRAND_NAME,
'MAX_BOUNDING_BOX': www.settings.MAX_BOUNDING_BOX,
'BRAND_NAME': www.settings.BRAND_NAME,
'CONTACT_CHAT': www.settings.CONTACT_CHAT,
'CONTACT_EMAIL': www.settings.CONTACT_EMAIL,
'DEBUG': www.settings.DEBUG,
'EXTRA_FOOTER': www.settings.EXTRA_FOOTER,
'LANGUAGES': www.settings.LANGUAGES,
'LANGUAGES_LIST': www.settings.LANGUAGES_LIST,
'LANGUAGE_FLAGS': www.settings.LANGUAGE_FLAGS,
'MAINTENANCE_NOTICE': www.settings.MAINTENANCE_NOTICE,
'MAP_LANGUAGES': www.settings.MAP_LANGUAGES,
'MAX_BOUNDING_BOX': www.settings.MAX_BOUNDING_BOX,
'OUTER_BOUNDS_JSON': www.settings.MAX_BOUNDING_OUTER,
'PAYPAL_ID': www.settings.PAYPAL_ID,
'PIWIK_BASE_URL': www.settings.PIWIK_BASE_URL,
'SUBMITTER_IP_LIFETIME': www.settings.SUBMITTER_IP_LIFETIME,
'SUBMITTER_MAIL_LIFETIME': www.settings.SUBMITTER_MAIL_LIFETIME,
'WEBLATE_BASE_URL': www.settings.WEBLATE_BASE_URL,
'PAYPAL_ID': www.settings.PAYPAL_ID,
'CONTACT_EMAIL': www.settings.CONTACT_EMAIL,
'CONTACT_CHAT': www.settings.CONTACT_CHAT,
'EXTRA_FOOTER': www.settings.EXTRA_FOOTER,
'MAINTENANCE_NOTICE': www.settings.MAINTENANCE_NOTICE,
'searchform': forms.MapSearchForm(request.GET),
'blogposts': get_latest_blog_posts(),
'PIWIK_BASE_URL': www.settings.PIWIK_BASE_URL,
'WEBLATE_BASE_URL': www.settings.WEBLATE_BASE_URL,
'daemon_running': daemon_running,
'gis_lastupdate': gis_lastupdate,
'gis_lag_ok': gis_lag_ok,
'waymarked_lastupdate': waymarked_lastupdate,
'waymarked_lag_ok': waymarked_lag_ok,
'osmnames_ok': osmnames_ok,
'utc_now': datetime.datetime.utcnow(),
'platform_status': platform_status,
'searchform': forms.MapSearchForm(request.GET),
'blogposts': get_latest_blog_posts(),
'paypal_lang_code': paypal_lang_code,
'paypal_country_code': paypal_country_code,
'daemon_running': daemon_running,
'gis_lastupdate': gis_lastupdate,
'gis_lag_ok': gis_lag_ok,
'waymarked_lastupdate': waymarked_lastupdate,
'waymarked_lag_ok': waymarked_lag_ok,
'osmnames_ok': osmnames_ok,
'utc_now': datetime.datetime.utcnow(),
'platform_status': platform_status,
'paypal_lang_code': paypal_lang_code,
'paypal_country_code': paypal_country_code,
'OUTER_BOUNDS_JSON': www.settings.MAX_BOUNDING_OUTER,
'SUBMITTER_MAIL_LIFETIME': www.settings.SUBMITTER_MAIL_LIFETIME,
'SUBMITTER_IP_LIFETIME': www.settings.SUBMITTER_IP_LIFETIME,
'queue_states': queue_states(),
'queues_overall_state': queues_overall_state(),
'queues_overall_symbol': queues_overall_symbol(),
'queue_states': queue_states(),
'queues_overall_state': queues_overall_state(),
'queues_overall_symbol': queues_overall_symbol(),
}

Wyświetl plik

@ -206,18 +206,14 @@ class MapRenderingJobForm(forms.ModelForm):
del cleaned_data["stylesheet"]
if mode == 'admin':
# TODO as bounding box override now exists (Issue #24)
# we need to do the same bbox checks here as in
# the mode=bbox section below?
if city == "":
msg = _(u"Administrative city required")
self._errors["administrative_city"] = ErrorList([msg])
del cleaned_data["administrative_city"]
# Make sure that bbox and admin modes are exclusive
# TODO: we should maybe merge these two instead? (See also OcitysMap Github Issue #24)
cleaned_data["lat_upper_left"] = None
cleaned_data["lon_upper_left"] = None
cleaned_data["lat_bottom_right"] = None
cleaned_data["lon_bottom_right"] = None
try:
self._check_osm_id(cleaned_data.get("administrative_osmid"))
except Exception as ex:

Wyświetl plik

@ -35,15 +35,11 @@ from slugify import slugify
import logging
LOG = logging.getLogger('maposmatic')
# TODO: legacy function that was once used in old migration
# 0005_auto_20170521_0103, keep or remove?
def get_track_path(instance, filename):
return ""
def get_umap_path(instance, filename):
return ""
def get_poi_file_path(instance, filename):
return ""
class MapRenderingJobManager(models.Manager):
def to_render(self, queue_name = 'default'):
return MapRenderingJob.objects.filter(status=0).filter(queue=queue_name).order_by('submission_time')
@ -164,13 +160,6 @@ class MapRenderingJob(models.Model):
self.resultmsg = resultmsg
self.save()
def rendering_time_gt_1min(self):
if self.needs_waiting():
return False
delta = self.endofrendering_time - self.startofrendering_time
return delta.seconds > 60
def __is_ok(self): return self.resultmsg == 'ok'
def is_waiting(self): return self.status == 0
@ -179,11 +168,8 @@ class MapRenderingJob(models.Model):
def is_done(self): return self.status == 2
def is_done_ok(self): return self.is_done() and self.__is_ok()
def is_done_failed(self): return self.is_done() and not self.__is_ok()
def is_obsolete(self): return self.status == 3
def is_obsolete_ok(self): return self.is_obsolete() and self.__is_ok()
def is_obsolete_failed(self): return self.is_obsolete() and not self.__is_ok()
def is_cancelled(self): return self.status == 4

Wyświetl plik

@ -0,0 +1,86 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Feeds for MapOSMatic
import datetime
import logging
LOG = logging.getLogger('maposmatic')
from django.contrib.gis.feeds import Feed
from django.utils.translation import gettext_lazy as _
from django.template.loader import render_to_string, get_template
from www.maposmatic import models
import www.settings
class ErrorFeed(Feed):
"""
This feeds syndicates the latest failed render request in MapOSMatic
"""
title = "%s %s %s" % (www.settings.BRAND_NAME, _("errors"),
www.settings.DEBUG and '' or _('[DEV]'))
link = '/maps/' # We can't use reverse here as the urlpatterns aren't
# defined yet at this point.
description = _('The latest render failures on MapOSMatic.')
# description_template = "maposmatic/map-feed.html"
def items(self):
"""Returns the rendering failures from the last week, or
the last 10 failures if nothing happened recently."""
one_day_before = datetime.datetime.now() - datetime.timedelta(7)
items = (models.MapRenderingJob.objects
.filter(status=2)
.exclude(resultmsg='ok')
.filter(endofrendering_time__gte=one_day_before)
.order_by('-endofrendering_time'))
if items.count():
return items
# Fall back to the last 10 entries, regardless of time
return (models.MapRenderingJob.objects
.filter(status=2)
.exclude(resultmsg='ok')
.order_by('-endofrendering_time')[:10])
# Not sure what to do if we still don't have any items at this point.
def item_title(self, item):
return item.maptitle
def item_description(self, item):
try:
errortext = open(item.get_errorlog_file(), 'r').read()
except:
errortext = 'no error file found'
return "<strong>%s</strong><hr/><pre>%s</pre>" % (item.resultmsg, errortext)
def item_geometry(self, item):
if item.administrative_city:
return None
else:
return (item.lon_upper_left, item.lat_upper_left,
item.lon_bottom_right, item.lat_bottom_right)
def item_pubdate(self, item):
return item.startofrendering_time;

Wyświetl plik

@ -93,58 +93,3 @@ class MapsFeed(Feed):
context['MAP_LANGUAGES'] = www.settings.MAP_LANGUAGES
return context
class ErrorFeed(Feed):
"""
This feeds syndicates the latest failed render request in MapOSMatic
"""
title = "%s %s %s" % (www.settings.BRAND_NAME, _("errors"),
www.settings.DEBUG and '' or _('[DEV]'))
link = '/maps/' # We can't use reverse here as the urlpatterns aren't
# defined yet at this point.
description = _('The latest render failures on MapOSMatic.')
# description_template = "maposmatic/map-feed.html"
def items(self):
"""Returns the rendering failures from the last week, or
the last 10 failures if nothing happened recently."""
one_day_before = datetime.datetime.now() - datetime.timedelta(7)
items = (models.MapRenderingJob.objects
.filter(status=2)
.exclude(resultmsg='ok')
.filter(endofrendering_time__gte=one_day_before)
.order_by('-endofrendering_time'))
if items.count():
return items
# Fall back to the last 10 entries, regardless of time
return (models.MapRenderingJob.objects
.filter(status=2)
.exclude(resultmsg='ok')
.order_by('-endofrendering_time')[:10])
# Not sure what to do if we still don't have any items at this point.
def item_title(self, item):
return item.maptitle
def item_description(self, item):
try:
errortext = open(item.get_errorlog_file(), 'r').read()
except:
errortext = 'no error file found'
return "<strong>%s</strong><hr/><pre>%s</pre>" % (item.resultmsg, errortext)
def item_geometry(self, item):
if item.administrative_city:
return None
else:
return (item.lon_upper_left, item.lat_upper_left,
item.lon_bottom_right, item.lat_bottom_right)
def item_pubdate(self, item):
return item.startofrendering_time;

Wyświetl plik

@ -0,0 +1,2 @@
from .MapsFeed import MapsFeed
from .ErrorFeed import ErrorFeed

Wyświetl plik

@ -60,7 +60,7 @@
{% blocktrans with url=map.get_errorlog %}
Check the <a target='_blank' href='{{ url }}'><i class='fas fa-file-lines'></i> error log</a> for more details<br>
{% endblocktrans %}
{% if settings.CONTACT_EMAIL %}
{% if CONTACT_EMAIL %}
{% blocktrans with email=map|email_url %}
or contact {{ email }} for more information.
{% endblocktrans %}

Wyświetl plik

@ -1,750 +0,0 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2019 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Views for MapOSMatic
import datetime
import logging
import json
import os
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.urls import reverse
from django.http import HttpResponseRedirect, HttpResponseBadRequest, HttpResponseNotFound, HttpResponse, Http404
from django.db.transaction import TransactionManagementError
from django.shortcuts import get_object_or_404, render
from django.template import RequestContext
from django.utils.translation import gettext, gettext_lazy as _
from django.core import serializers
from django.forms.models import model_to_dict
from django.core.exceptions import ValidationError
from django.urls import get_script_prefix
from django.db import connections
from django.utils.safestring import mark_safe
import ocitysmap
from www.maposmatic import helpers, forms, nominatim, models
import www.settings
from www.maposmatic.apis import get_paper_from_size
import psycopg2
from ipware import get_client_ip
LOG = logging.getLogger('maposmatic')
def index(request):
"""The main page."""
form = forms.MapSearchForm(request.GET)
job_list = (models.MapRenderingJob.objects.all()
.order_by('-submission_time'))
job_list = (job_list.filter(status=0) |
job_list.filter(status=1))
return render(request,
'maposmatic/index.html',
{ 'form': form,
'queued': job_list.count()
}
)
def about(request):
"""The about page."""
form = forms.MapSearchForm(request.GET)
job_list = (models.MapRenderingJob.objects.all()
.order_by('-submission_time'))
job_list = (job_list.filter(status=0) |
job_list.filter(status=1))
return render(request,
'maposmatic/about.html',
{ }
)
def privacy(request):
"""The privacy statement page."""
return render(request,
'maposmatic/privacy.html',
{ }
)
def congo(request):
"""The congo health map page."""
return render(request,
'maposmatic/congo.html',
{ }
)
def documentation_user_guide(request):
"""The user guide page."""
return render(request,
'maposmatic/documentation-user-guide.html',
{ }
)
def documentation_api(request):
"""The api documentation."""
return render(request,
'maposmatic/documentation-api.html',
{ }
)
def donate(request):
"""The donate page."""
form = forms.MapSearchForm(request.GET)
job_list = (models.MapRenderingJob.objects.all()
.order_by('-submission_time'))
job_list = (job_list.filter(status=0) |
job_list.filter(status=1))
return render(request,
'maposmatic/donate.html',
{ }
)
def donate_thanks(request):
"""The thanks for donation page."""
return render(request, 'maposmatic/donate-thanks.html')
def create_upload_file(job, file, keep_until = None):
first_line = file.readline().decode("utf-8-sig")
LOG.info("firstline type %s" % type(first_line))
if first_line.startswith(u'<?xml'):
file_type = 'gpx'
else:
file_type = 'umap'
file_instance = models.UploadFile(uploaded_file = file,
file_type = file_type,
keep_until = keep_until)
file_instance.save()
file_instance.job.add(job)
def _papersize_buttons(basename, width=None, height=None):
format = "<button id='{0}_{1}_{2}' type='button' class='btn btn-primary papersize papersize_{1}_{2}' onclick='set_papersize({1}, {2});'><i class='fas fa-{3} fa-2x'></i></button> "
if width is None or height is None: # no values -> "best fit"
return format.format(basename, "best", "fit", 'square')
if width == height: # square format, just one button
return format.format(basename, width, height, 'square')
# individual buttons for landscape and portrait
return format.format(basename, height, width, 'image') + format.format(basename, width, height, 'portrait')
def new(request):
"""The map creation page and form."""
if request.method == 'POST':
form = forms.MapRenderingJobForm(request.POST, request.FILES)
if form.is_valid():
# remember some settings as future defaults
request.session['new_layout'] = form.cleaned_data.get('layout')
request.session['new_indexer'] = form.cleaned_data.get('indexer')
request.session['new_stylesheet'] = form.cleaned_data.get('stylesheet')
request.session['new_overlay'] = form.cleaned_data.get('overlay')
request.session['new_paper_width_mm'] = form.cleaned_data.get('paper_width_mm')
request.session['new_paper_height_mm'] = form.cleaned_data.get('paper_height_mm')
job = form.save(commit=False)
job.administrative_osmid = form.cleaned_data.get('administrative_osmid')
job.stylesheet = form.cleaned_data.get('stylesheet')
job.overlay = ",".join(form.cleaned_data.get('overlay'))
job.layout = form.cleaned_data.get('layout')
if job.layout.startswith('multi'):
job.queue = 'multipage'
job.indexer = form.cleaned_data.get('indexer')
job.paper_width_mm = form.cleaned_data.get('paper_width_mm')
job.paper_height_mm = form.cleaned_data.get('paper_height_mm')
job.status = 0 # Submitted
if www.settings.SUBMITTER_IP_LIFETIME != 0:
job.submitterip = request.META['REMOTE_ADDR']
else:
job.submitterip = None
job.submitteremail = form.cleaned_data.get('submitteremail')
job.map_language = form.cleaned_data.get('map_language')
job.index_queue_at_submission = (models.MapRenderingJob.objects
.queue_size(job.queue) + 1)
job.nonce = helpers.generate_nonce(models.MapRenderingJob.NONCE_SIZE)
client_ip, is_routable = get_client_ip(request)
if www.settings.EXTRA_IP is None or ( client_ip is not None and client_ip == www.settings.EXTRA_IP ):
job.extra_text = www.settings.EXTRA_FOOTER
job.logo = "bundled:osm-logo.svg"
job.extra_logo = www.settings.EXTRA_LOGO
job.save()
files = request.FILES.getlist('uploadfile')
if form.cleaned_data.get('delete_files_after_rendering'):
keep_until = None
else:
if www.settings.UPLOAD_FILE_LIFETIME > 0:
keep_until = datetime.datetime.now() + datetime.timedelta(days=www.settings.UPLOAD_FILE_LIFETIME)
else:
keep_until = '2999-12-30' # arbitrary 'max' value
for file in files:
create_upload_file(job, file, keep_until)
return HttpResponseRedirect(reverse('map-by-id-and-nonce',
args=[job.id, job.nonce]))
else:
data = {'form': form }
return render(request, 'generic_error.html', data)
LOG.warning("FORM NOT VALID")
else:
init_vals = request.GET.dict()
oc = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
if not 'layout' in init_vals and 'new_layout' in request.session :
init_vals['layout'] = request.session['new_layout']
else:
request.session['new_layout'] = oc.get_all_renderer_names()[0]
if not 'indexer' in init_vals and 'new_indexer' in request.session :
init_vals['indexer'] = request.session['new_indexer']
else:
request.session['new_indexer'] = 'Street' # TODO make configurable
if not 'stylesheet' in init_vals and 'new_stylesheet' in request.session:
init_vals['stylesheet'] = request.session['new_stylesheet']
else:
request.session['new_stylesheet'] = oc.get_all_style_names()[0]
if not 'overlay' in init_vals and 'new_overlay' in request.session:
init_vals['overlay'] = request.session['new_overlay']
if not 'paper_width_mm' in init_vals and 'new_paper_width_mm' in request.session:
init_vals['paper_width_mm'] = request.session['new_paper_width_mm']
if not 'paper_height_mm' in init_vals and 'new_paper_width_mm' in request.session:
init_vals['paper_height_mm'] = request.session['new_paper_height_mm']
form = forms.MapRenderingJobForm(initial=init_vals)
_ocitysmap = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
papersize_buttons = '<p>'
papersize_buttons += _papersize_buttons('paper')
papersize_buttons += "<b>%s</b> (<span id='best_width'>?</span>&times;<span id='best_height'>?</span>mm²)</p>" % _("Best fit")
for p in _ocitysmap.get_all_paper_sizes():
if p[1] is not None:
papersize_buttons += "<p>"
papersize_buttons += _papersize_buttons('paper', p[1], p[2])
papersize_buttons += "<b>%s</b> (%s&times;%smm²)</p>" % (p[0], repr(p[1]), repr(p[2]))
multisize_buttons = ''
for p in _ocitysmap.get_all_paper_sizes('multipage'):
if p[1] is not None:
multisize_buttons += "<p>"
multisize_buttons += _papersize_buttons('multipaper', p[1], p[2])
multisize_buttons += "<b>%s</b> (%s&times;%smm²)</p>" % (p[0], repr(p[1]), repr(p[2]))
return render(request, 'maposmatic/new.html',
{ 'form' : form ,
'papersize_suggestions': mark_safe(papersize_buttons),
'multipage_papersize_suggestions': mark_safe(multisize_buttons),
})
def map_full(request, id, nonce=None):
"""The full-page map details page.
Args:
id (int): the job ID in the database.
"""
job = get_object_or_404(models.MapRenderingJob, id=id)
isredirected = request.session.get('redirected', False)
request.session.pop('redirected', None)
queue_size = job.index_queue_at_submission
progress = 100
if queue_size:
progress = int(100 * (queue_size -
job.current_position_in_queue()) / float(queue_size))
refresh = job.is_rendering() and \
www.settings.REFRESH_JOB_RENDERING or \
www.settings.REFRESH_JOB_WAITING
return render(request, 'maposmatic/map-full.html',
{ 'map': job, 'redirected': isredirected,
'nonce': nonce, 'refresh': refresh,
'progress': progress, 'queue_size': queue_size })
def maps(request, category=None, extra=None):
"""Displays all maps and jobs, sorted by submission time, or maps matching
the search terms when provided."""
map_list = None
form = forms.MapSearchForm(request.GET)
if form.is_valid():
map_list = (models.MapRenderingJob.objects
.order_by('-submission_time')
.filter(maptitle__icontains=form.cleaned_data['query']))
if len(map_list) == 1:
return HttpResponseRedirect(reverse('map-by-id',
args=[map_list[0].id]))
else:
form = forms.MapSearchForm()
if map_list is None:
map_list = (models.MapRenderingJob.objects
.order_by('-submission_time'))
if category == 'errors':
map_list = map_list.filter(status=2).exclude(resultmsg='ok')
elif category == 'queue' and extra is not None:
map_list = map_list.filter(queue=extra)
paginator = Paginator(map_list, www.settings.ITEMS_PER_PAGE)
try:
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
maps = paginator.page(page)
except (EmptyPage, InvalidPage):
maps = paginator.page(paginator.num_pages)
return render(request, 'maposmatic/maps.html',
{ 'maps': maps,
'form': form,
'category': category,
'extra': extra,
'is_search': form.is_valid(),
'pages': helpers.get_pages_list(maps, paginator) })
def recreate(request):
if request.method == 'POST':
form = forms.MapRecreateForm(request.POST)
if form.is_valid():
job = get_object_or_404(models.MapRenderingJob,
id=form.cleaned_data['id'])
newjob = models.MapRenderingJob()
newjob.maptitle = job.maptitle
newjob.administrative_city = job.administrative_city
newjob.administrative_osmid = job.administrative_osmid
newjob.lat_upper_left = job.lat_upper_left
newjob.lon_upper_left = job.lon_upper_left
newjob.lat_bottom_right = job.lat_bottom_right
newjob.lon_bottom_right = job.lon_bottom_right
newjob.layout = job.layout
newjob.indexer = job.indexer
newjob.stylesheet = job.stylesheet
newjob.overlay = job.overlay
newjob.logo = job.logo
newjob.extra_logo = job.extra_logo
newjob.extra_text = job.extra_text
newjob.queue = "default"
if job.layout.startswith('multi'):
newjob.queue = 'multipage'
newjob.paper_width_mm = job.paper_width_mm
newjob.paper_height_mm = job.paper_height_mm
newjob.status = 0 # Submitted
if www.settings.SUBMITTER_IP_LIFETIME != 0:
newjob.submitterip = request.META['REMOTE_ADDR']
else:
newjob.submitterip = None
newjob.submittermail = None # TODO
newjob.map_language = job.map_language
newjob.index_queue_at_submission = (models.MapRenderingJob.objects
.queue_size() + 1)
newjob.nonce = helpers.generate_nonce(models.MapRenderingJob.NONCE_SIZE)
newjob.save()
for each in job.uploads.all():
each.job.add(newjob)
return HttpResponseRedirect(reverse('map-by-id-and-nonce',
args=[newjob.id, newjob.nonce]))
return HttpResponseBadRequest("ERROR: Invalid request")
def reedit(request):
if request.method == 'POST':
form = forms.MapRecreateForm(request.POST)
if form.is_valid():
job = get_object_or_404(models.MapRenderingJob,
id=form.cleaned_data['id'])
paper_size, paper_orientation = get_paper_from_size(job.paper_width_mm, job.paper_height_mm)
init_vals = {
'layout': job.layout,
'indexer': job.indexer,
'stylesheet': job.stylesheet,
'overlay': job.overlay.split(","),
'maptitle': job.maptitle,
'submittermail': job.submittermail,
'default_papersize': paper_size,
'default_paperorientation': paper_orientation,
}
request.session['new_layout'] = job.layout
request.session['new_indexer'] = job.indexer
request.session['new_stylesheet'] = job.stylesheet
request.session['new_overlay'] = job.overlay.split(",")
form = forms.MapRenderingJobForm(initial=init_vals)
bounds = "L.latLngBounds(L.latLng(%f,%f),L.latLng(%f,%f))" % (job.lat_upper_left,
job.lon_upper_left,
job.lat_bottom_right,
job.lon_bottom_right)
return render(request,
'maposmatic/new.html',
{
'form' : form,
'SELECTION_BOUNDS': bounds,
})
return HttpResponseBadRequest("ERROR: Invalid request")
def cancel(request):
if request.method == 'POST':
form = forms.MapCancelForm(request.POST)
if form.is_valid():
job = get_object_or_404(models.MapRenderingJob,
id=form.cleaned_data['id'],
nonce=form.cleaned_data['nonce'])
job.cancel()
return HttpResponseRedirect(reverse('map-by-id-and-nonce',
args=[job.id, job.nonce]))
return HttpResponseBadRequest("ERROR: Invalid request")
def api_nominatim(request):
"""Nominatim query gateway."""
exclude = request.GET.get('exclude', '')
squery = request.GET.get('q', '')
lang = None
if 'HTTP_ACCEPT_LANGUAGE' in request.META:
# Accept-Language headers typically look like
# fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3. Unfortunately,
# Nominatim behaves improperly with such a string: it gives
# the region name in French, but the country name in
# English. We split at the first comma to only keep the
# preferred language, which makes Nominatim work properly.
lang = request.META['HTTP_ACCEPT_LANGUAGE'].split(',')[0]
try:
contents = nominatim.query(squery, exclude, with_polygons=False,
accept_language=lang)
except Exception as e:
LOG.exception("Error querying Nominatim")
contents = []
return HttpResponse(content=json.dumps(contents),
content_type='text/json')
def heatmap(request, days=7):
return render(request, 'maposmatic/heatmap.html',
{ 'days' : days ,
})
def api_nominatim_reverse(request, lat, lon):
"""Nominatim reverse geocoding query gateway."""
lat = float(lat)
lon = float(lon)
return HttpResponse(json.dumps(nominatim.reverse_geo(lat, lon)),
content_type='text/json')
def api_postgis_reverse(request, lat, lon):
lat = float(lat)
lon = float(lon)
cursor = None
query = """select country_code
from country_osm_grid
where st_contains(geometry,
st_geomfromtext('POINT(%f %f)', 4326))
""" % (lon, lat)
LOG.debug("Reverse Lookup Query %s" % query)
try:
connections['osm'].rollback() # make sure there's no pending transaction
cursor = connections['osm'].cursor()
cursor.execute(query)
country_code = cursor.fetchone()
cursor.close()
if country_code is None or len(country_code) < 1:
raise Http404("postgis: country not found")
return HttpResponse('{"address": {"country_code": "%s"}}' % country_code[0], content_type='text/json')
except Exception as e:
LOG.warning("reverse geo lookup failed: %s" % e)
pass
finally:
# Close the DB cursor if necessary
if cursor is not None and not cursor.closed:
cursor.close()
raise Http404("postgis: something went wrong")
def api_geosearch(request):
"""Simple place name search."""
exclude = request.GET.get('exclude', '')
squery = request.GET.get('q', '')
squery = squery.lower()
contents = { "entries": [] }
cursor = None
if www.settings.MAX_BOUNDING_BOX:
m = www.settings.MAX_BOUNDING_BOX
max_bbox = "ST_GeomFromText('POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))', 4326)" % (m[1], m[0], m[1], m[2], m[3], m[2], m[3], m[0], m[1], m[0])
pt_bbox = 'AND ST_Contains(ST_Transform(%s, 3857), pt.way)' % max_bbox
poly_bbox = 'AND ST_Contains(ST_Transform(%s, 3857), poly.way)' % max_bbox
else:
pt_bbox = ''
poly_bbox = ''
query = """SELECT p.name
, p.display_name
, p.class
, p.type
, p.osm_type
, p.osm_id
, p.lat
, p.lon
, p.west
, p.east
, p.north
, p.south
, p.place_rank
, p.importance
, p.country_code
FROM place p
LEFT JOIN planet_osm_hstore_point pt
ON p.osm_id = pt.osm_id
%s -- optionally filter by max bbox
LEFT JOIN planet_osm_hstore_polygon poly
ON - p.osm_id = poly.osm_id
%s -- optionally filter by max bbox
WHERE LOWER(p.name) = %%s
AND ( pt.osm_id IS NOT NULL
OR poly.osm_id IS NOT NULL
)
ORDER BY p.place_rank
, p.importance DESC
""" % (pt_bbox, poly_bbox)
try:
cursor = connections['osm'].cursor()
if cursor is None:
raise Http404("postgis: no cursor")
cursor.execute(query, [ squery ])
columns = [col[0] for col in cursor.description]
for row in cursor.fetchall():
values = dict(zip(columns, row))
values["boundingbox"] = "%f,%f,%f,%f" % (values["south"], values["north"], values["west"], values["east"])
bbox = ocitysmap.coords.BoundingBox(values["south"], values["west"], values["north"], values["east"])
(metric_size_lat, metric_size_lon) = bbox.spheric_sizes()
LOG.warning("metric lat/lon %f : %f - %f" % (metric_size_lat, metric_size_lon, www.settings.BBOX_MAXIMUM_LENGTH_IN_METERS))
if values["osm_type"] == "node":
values["icon"] = "../media/img/place-node.png"
values["ocitysmap_params"] = {
"valid": False,
"reason": "no-admin",
"reason_text": "No administrative boundary"
}
else:
values["icon"] = "../media/img/place-polygon.png"
if (metric_size_lat > www.settings.BBOX_MAXIMUM_LENGTH_IN_METERS
or metric_size_lon > www.settings.BBOX_MAXIMUM_LENGTH_IN_METERS):
valid = False
reason = "area-too-big"
reason_text = gettext("Administrative area too big for rendering")
else:
valid = True
reason = ""
reason_text = ""
values["ocitysmap_params"] = {
"valid": valid,
"table": "polygon",
"id": -values["osm_id"],
"reason": reason,
"reason_text": reason_text
}
contents["entries"].append(values)
cursor.close()
return HttpResponse(content=json.dumps(contents),
content_type='text/json')
except Exception as e:
raise TransactionManagementError(e)
def api_papersize(request):
"""API handler to get the compatible paper sizes for the provided layout
and bounding box."""
if request.method != 'POST':
return HttpResponseBadRequest("ERROR: Bad request")
f = forms.MapPaperSizeForm(request.POST)
if not f.is_valid():
return HttpResponseBadRequest("ERROR: Invalid arguments")
renderer = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
osmid = f.cleaned_data.get('osmid')
layout = f.cleaned_data.get('layout')
stylesheet = renderer.get_stylesheet_by_name(
f.cleaned_data.get('stylesheet'))
# Determine geographic area
if osmid is not None:
try:
bbox_wkt, area_wkt = renderer.get_geographic_info(osmid)
except ValueError:
LOG.exception("Error determining compatible paper sizes")
raise
bbox = ocitysmap.coords.BoundingBox.parse_wkt(bbox_wkt)
else:
lat_upper_left = f.cleaned_data.get("lat_upper_left")
lon_upper_left = f.cleaned_data.get("lon_upper_left")
lat_bottom_right = f.cleaned_data.get("lat_bottom_right")
lon_bottom_right = f.cleaned_data.get("lon_bottom_right")
# Check we have correct floats
if (lat_upper_left == None or lon_upper_left == None
or lat_bottom_right == None or lon_bottom_right == None):
return HttpResponseBadRequest("ERROR: Invalid arguments")
bbox = ocitysmap.coords.BoundingBox(
lat_upper_left, lon_upper_left,
lat_bottom_right, lon_bottom_right)
renderer_cls = ocitysmap.renderers.get_renderer_class_by_name(layout)
paper_sizes = sorted(renderer_cls.get_compatible_paper_sizes(bbox, renderer),
key = lambda p: p['width'])
return HttpResponse(content=json.dumps(paper_sizes),
content_type='text/json')
def api_bbox(request, osm_id):
"""API handler that returns the bounding box from an OSM ID polygon."""
try:
osm_id = int(osm_id)
except ValueError:
return HttpResponseBadRequest("ERROR: Invalid arguments")
renderer = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
try:
bbox_wkt, area_wkt = renderer.get_geographic_info(osm_id)
bbox = ocitysmap.coords.BoundingBox.parse_wkt(bbox_wkt)
return HttpResponse(content=json.dumps(bbox.as_json_bounds()),
content_type='text/json')
except:
LOG.exception("Error calculating bounding box for OSM ID %d!" % osm_id)
return HttpResponseBadRequest("ERROR: OSM ID %d not found!" % osm_id)
def api_polygon(request, osm_id):
"""API handler that returns the polygon outline from an OSM ID polygon."""
try:
osm_id = int(osm_id)
except ValueError:
return HttpResponseBadRequest("ERROR: Invalid arguments")
renderer = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
try:
bbox_wkt, area_wkt = renderer.get_geographic_info(osm_id)
bbox = ocitysmap.coords.BoundingBox.parse_wkt(bbox_wkt).as_json_bounds()
return HttpResponse(content=json.dumps({'bbox': bbox, 'wkt': area_wkt}),
content_type='text/json')
except:
LOG.exception("Error retrieving polygon outline for OSM ID %d!" % osm_id)
return HttpResponseBadRequest("ERROR: OSM ID %d not found!" % osm_id)
def api_rendering_status(request, id, nonce=None):
"""API handler for updating map request rendering status"""
try:
id = int(id)
except ValueError:
return HttpResponseBadRequest("ERROR: Invalid arguments")
job = get_object_or_404(models.MapRenderingJob, id=id)
isredirected = request.session.get('redirected', False)
request.session.pop('redirected', None)
queue_size = job.index_queue_at_submission
progress = 100
if queue_size:
progress = int(100 * (queue_size -
job.current_position_in_queue()) / float(queue_size))
refresh = job.is_rendering() and \
www.settings.REFRESH_JOB_RENDERING or \
www.settings.REFRESH_JOB_WAITING
return render(request, 'maposmatic/map-full-parts/rendering-status.html',
{ 'map': job,
'redirected': isredirected,
'nonce': nonce,
'refresh': refresh,
'progress': progress,
'queue_size': queue_size,
'status': job.renderstep or "working",
})

Wyświetl plik

@ -0,0 +1,17 @@
from .index import index
from .about import about
from .privacy import privacy
from .documentation import documentation_user_guide, documentation_api
from .donate import donate, donate_thanks
from .maps import maps
from .map_full import map_full
from .new import new
from .recreate import recreate
from .reedit import reedit
from .cancel import cancel
from .heatmap import heatmap
from .congo import congo

Wyświetl plik

@ -0,0 +1,37 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import render
def about(request):
"""The about page."""
return render(request,
'maposmatic/about.html',
{ }
)

Wyświetl plik

@ -0,0 +1,47 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.http import HttpResponseRedirect, HttpResponseBadRequest
from django.shortcuts import get_object_or_404
import www.settings
from www.maposmatic import helpers, forms, models
def cancel(request):
if request.method == 'POST':
form = forms.MapCancelForm(request.POST)
if form.is_valid():
job = get_object_or_404(models.MapRenderingJob,
id=form.cleaned_data['id'],
nonce=form.cleaned_data['nonce'])
job.cancel()
return HttpResponseRedirect(reverse('map-by-id-and-nonce',
args=[job.id, job.nonce]))
return HttpResponseBadRequest("ERROR: Invalid request")

Wyświetl plik

@ -0,0 +1,36 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import render
def congo(request):
"""The congo health map page."""
return render(request,
'maposmatic/congo.html',
{ }
)

Wyświetl plik

@ -0,0 +1,43 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import render
def documentation_user_guide(request):
"""The user guide page."""
return render(request,
'maposmatic/documentation-user-guide.html',
{ }
)
def documentation_api(request):
"""The api documentation."""
return render(request,
'maposmatic/documentation-api.html',
{ }
)

Wyświetl plik

@ -0,0 +1,40 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import render
def donate(request):
"""The donate page."""
return render(request,
'maposmatic/donate.html',
{ }
)
def donate_thanks(request):
"""The thanks for donation page."""
return render(request, 'maposmatic/donate-thanks.html')

Wyświetl plik

@ -0,0 +1,39 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import render
import www.settings
def heatmap(request, days=7):
return render(request, 'maposmatic/heatmap.html',
{ 'days' : days ,
})

Wyświetl plik

@ -0,0 +1,36 @@
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import render
from www.maposmatic import helpers, forms, models
def index(request):
"""The main page."""
form = forms.MapSearchForm(request.GET)
job_list = (models.MapRenderingJob.objects.all()
.order_by('-submission_time'))
job_list = (job_list.filter(status=0) |
job_list.filter(status=1))
return render(request,
'maposmatic/index.html',
{ 'form': form,
'queued': job_list.count()
}
)

Wyświetl plik

@ -0,0 +1,63 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import get_object_or_404, render
import www.settings
from www.maposmatic import helpers, forms, models
def map_full(request, id, nonce=None):
"""The full-page map details page.
Args:
id (int): the job ID in the database.
"""
job = get_object_or_404(models.MapRenderingJob, id=id)
isredirected = request.session.get('redirected', False)
request.session.pop('redirected', None)
queue_size = job.index_queue_at_submission
progress = 100
if queue_size:
progress = int(100 * (queue_size -
job.current_position_in_queue()) / float(queue_size))
refresh = job.is_rendering() and \
www.settings.REFRESH_JOB_RENDERING or \
www.settings.REFRESH_JOB_WAITING
return render(request, 'maposmatic/map-full.html',
{ 'map': job,
'redirected': isredirected,
'nonce': nonce,
'refresh': refresh,
'progress': progress,
'queue_size': queue_size,
})

Wyświetl plik

@ -0,0 +1,81 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.http import HttpResponseRedirect
from django.shortcuts import render
import www.settings
from www.maposmatic import helpers, forms, models
def maps(request, category=None, extra=None):
"""Displays all maps and jobs, sorted by submission time, or maps matching
the search terms when provided."""
map_list = None
form = forms.MapSearchForm(request.GET)
if form.is_valid():
map_list = (models.MapRenderingJob.objects
.order_by('-submission_time')
.filter(maptitle__icontains=form.cleaned_data['query']))
if len(map_list) == 1:
return HttpResponseRedirect(reverse('map-by-id',
args=[map_list[0].id]))
else:
form = forms.MapSearchForm()
if map_list is None:
map_list = (models.MapRenderingJob.objects
.order_by('-submission_time'))
if category == 'errors':
map_list = map_list.filter(status=2).exclude(resultmsg='ok')
elif category == 'queue' and extra is not None:
map_list = map_list.filter(queue=extra)
paginator = Paginator(map_list, www.settings.ITEMS_PER_PAGE)
try:
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
maps = paginator.page(page)
except (EmptyPage, InvalidPage):
maps = paginator.page(paginator.num_pages)
return render(request, 'maposmatic/maps.html',
{ 'maps': maps,
'form': form,
'category': category,
'extra': extra,
'is_search': form.is_valid(),
'pages': helpers.get_pages_list(maps, paginator),
})

Wyświetl plik

@ -0,0 +1,183 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
import datetime
from ipware import get_client_ip
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils.translation import gettext, gettext_lazy as _
from django.utils.safestring import mark_safe
from django.urls import reverse
import www.settings
from www.maposmatic import helpers, forms, models
import ocitysmap
def _create_upload_file(job, file, keep_until = None):
first_line = file.readline().decode("utf-8-sig")
LOG.info("firstline type %s" % type(first_line))
if first_line.startswith(u'<?xml'):
file_type = 'gpx'
else:
file_type = 'umap'
file_instance = models.UploadFile(uploaded_file = file,
file_type = file_type,
keep_until = keep_until)
file_instance.save()
file_instance.job.add(job)
def _papersize_buttons(basename, width=None, height=None):
format = "<button id='{0}_{1}_{2}' type='button' class='btn btn-primary papersize papersize_{1}_{2}' onclick='set_papersize({1}, {2});'><i class='fas fa-{3} fa-2x'></i></button> "
if width is None or height is None: # no values -> "best fit"
return format.format(basename, "best", "fit", 'square')
if width == height: # square format, just one button
return format.format(basename, width, height, 'square')
# individual buttons for landscape and portrait
return format.format(basename, height, width, 'image') + format.format(basename, width, height, 'portrait')
def new(request):
"""The map creation page and form."""
if request.method == 'POST':
form = forms.MapRenderingJobForm(request.POST, request.FILES)
if form.is_valid():
# remember some settings as future defaults
request.session['new_layout'] = form.cleaned_data.get('layout')
request.session['new_indexer'] = form.cleaned_data.get('indexer')
request.session['new_stylesheet'] = form.cleaned_data.get('stylesheet')
request.session['new_overlay'] = form.cleaned_data.get('overlay')
request.session['new_paper_width_mm'] = form.cleaned_data.get('paper_width_mm')
request.session['new_paper_height_mm'] = form.cleaned_data.get('paper_height_mm')
job = form.save(commit=False)
job.administrative_osmid = form.cleaned_data.get('administrative_osmid')
job.stylesheet = form.cleaned_data.get('stylesheet')
job.overlay = ",".join(form.cleaned_data.get('overlay'))
job.layout = form.cleaned_data.get('layout')
if job.layout.startswith('multi'):
job.queue = 'multipage'
job.indexer = form.cleaned_data.get('indexer')
job.paper_width_mm = form.cleaned_data.get('paper_width_mm')
job.paper_height_mm = form.cleaned_data.get('paper_height_mm')
job.status = 0 # Submitted
if www.settings.SUBMITTER_IP_LIFETIME != 0:
job.submitterip = request.META['REMOTE_ADDR']
else:
job.submitterip = None
job.submitteremail = form.cleaned_data.get('submitteremail')
job.map_language = form.cleaned_data.get('map_language')
job.index_queue_at_submission = (models.MapRenderingJob.objects
.queue_size(job.queue) + 1)
job.nonce = helpers.generate_nonce(models.MapRenderingJob.NONCE_SIZE)
client_ip, is_routable = get_client_ip(request)
if www.settings.EXTRA_IP is None or ( client_ip is not None and client_ip == www.settings.EXTRA_IP ):
job.extra_text = www.settings.EXTRA_FOOTER
job.logo = "bundled:osm-logo.svg"
job.extra_logo = www.settings.EXTRA_LOGO
job.save()
files = request.FILES.getlist('uploadfile')
if form.cleaned_data.get('delete_files_after_rendering'):
keep_until = None
else:
if www.settings.UPLOAD_FILE_LIFETIME > 0:
keep_until = datetime.datetime.now() + datetime.timedelta(days=www.settings.UPLOAD_FILE_LIFETIME)
else:
keep_until = '2999-12-30' # arbitrary 'max' value
for file in files:
_create_upload_file(job, file, keep_until)
return HttpResponseRedirect(reverse('map-by-id-and-nonce',
args=[job.id, job.nonce]))
else:
data = {'form': form }
return render(request, 'generic_error.html', data)
LOG.warning("FORM NOT VALID")
else:
init_vals = request.GET.dict()
oc = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
if not 'layout' in init_vals and 'new_layout' in request.session :
init_vals['layout'] = request.session['new_layout']
else:
request.session['new_layout'] = oc.get_all_renderer_names()[0]
if not 'indexer' in init_vals and 'new_indexer' in request.session :
init_vals['indexer'] = request.session['new_indexer']
else:
request.session['new_indexer'] = 'Street' # TODO make configurable
if not 'stylesheet' in init_vals and 'new_stylesheet' in request.session:
init_vals['stylesheet'] = request.session['new_stylesheet']
else:
request.session['new_stylesheet'] = oc.get_all_style_names()[0]
if not 'overlay' in init_vals and 'new_overlay' in request.session:
init_vals['overlay'] = request.session['new_overlay']
if not 'paper_width_mm' in init_vals and 'new_paper_width_mm' in request.session:
init_vals['paper_width_mm'] = request.session['new_paper_width_mm']
if not 'paper_height_mm' in init_vals and 'new_paper_width_mm' in request.session:
init_vals['paper_height_mm'] = request.session['new_paper_height_mm']
form = forms.MapRenderingJobForm(initial=init_vals)
_ocitysmap = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
papersize_buttons = '<p>'
papersize_buttons += _papersize_buttons('paper')
papersize_buttons += "<b>%s</b> (<span id='best_width'>?</span>&times;<span id='best_height'>?</span>mm²)</p>" % _("Best fit")
for p in _ocitysmap.get_all_paper_sizes():
if p[1] is not None:
papersize_buttons += "<p>"
papersize_buttons += _papersize_buttons('paper', p[1], p[2])
papersize_buttons += "<b>%s</b> (%s&times;%smm²)</p>" % (p[0], repr(p[1]), repr(p[2]))
multisize_buttons = ''
for p in _ocitysmap.get_all_paper_sizes('multipage'):
if p[1] is not None:
multisize_buttons += "<p>"
multisize_buttons += _papersize_buttons('multipaper', p[1], p[2])
multisize_buttons += "<b>%s</b> (%s&times;%smm²)</p>" % (p[0], repr(p[1]), repr(p[2]))
return render(request, 'maposmatic/new.html',
{ 'form' : form ,
'papersize_suggestions': mark_safe(papersize_buttons),
'multipage_papersize_suggestions': mark_safe(multisize_buttons),
})

Wyświetl plik

@ -0,0 +1,37 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import render
def privacy(request):
"""The privacy statement page."""
return render(request,
'maposmatic/privacy.html',
{ }
)

Wyświetl plik

@ -0,0 +1,91 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponseBadRequest
from django.urls import reverse
import www.settings
from www.maposmatic import helpers, forms, models
def recreate(request):
if request.method == 'POST':
form = forms.MapRecreateForm(request.POST)
if form.is_valid():
job = get_object_or_404(models.MapRenderingJob,
id=form.cleaned_data['id'])
newjob = models.MapRenderingJob()
newjob.maptitle = job.maptitle
newjob.administrative_city = job.administrative_city
newjob.administrative_osmid = job.administrative_osmid
newjob.lat_upper_left = job.lat_upper_left
newjob.lon_upper_left = job.lon_upper_left
newjob.lat_bottom_right = job.lat_bottom_right
newjob.lon_bottom_right = job.lon_bottom_right
newjob.layout = job.layout
newjob.indexer = job.indexer
newjob.stylesheet = job.stylesheet
newjob.overlay = job.overlay
newjob.logo = job.logo
newjob.extra_logo = job.extra_logo
newjob.extra_text = job.extra_text
newjob.queue = "default"
if job.layout.startswith('multi'):
newjob.queue = 'multipage'
newjob.paper_width_mm = job.paper_width_mm
newjob.paper_height_mm = job.paper_height_mm
newjob.status = 0 # Submitted
if www.settings.SUBMITTER_IP_LIFETIME != 0:
newjob.submitterip = request.META['REMOTE_ADDR']
else:
newjob.submitterip = None
newjob.submittermail = None # TODO
newjob.map_language = job.map_language
newjob.index_queue_at_submission = (models.MapRenderingJob.objects
.queue_size() + 1)
newjob.nonce = helpers.generate_nonce(models.MapRenderingJob.NONCE_SIZE)
newjob.save()
for each in job.uploads.all():
each.job.add(newjob)
return HttpResponseRedirect(reverse('map-by-id-and-nonce',
args=[newjob.id, newjob.nonce]))
return HttpResponseBadRequest("ERROR: Invalid request")

Wyświetl plik

@ -0,0 +1,95 @@
# coding: utf-8
# maposmatic, the web front-end of the MapOSMatic city map generation system
# Copyright (C) 2009 David Decotigny
# Copyright (C) 2009 Frédéric Lehobey
# Copyright (C) 2009 Pierre Mauduit
# Copyright (C) 2009 David Mentré
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
LOG = logging.getLogger('maposmatic')
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponseBadRequest
from django.urls import reverse
import ocitysmap
import www.settings
from www.maposmatic import helpers, forms, models
def _get_paper_from_size(w, h):
oc = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
paper_size = None
paper_orientation = "landscape" if (w > h) else "portrait"
for paper in oc.get_all_paper_sizes():
if int(paper[1]) == w and int(paper[2]) == h:
paper_size = paper[0]
break
if int(paper[1]) == h and int(paper[2]) == w:
paper_size = paper[0]
break
return paper_size, paper_orientation
def reedit(request):
if request.method == 'POST':
form = forms.MapRecreateForm(request.POST)
if form.is_valid():
job = get_object_or_404(models.MapRenderingJob,
id=form.cleaned_data['id'])
paper_size, paper_orientation = _get_paper_from_size(job.paper_width_mm, job.paper_height_mm)
init_vals = {
'layout': job.layout,
'indexer': job.indexer,
'stylesheet': job.stylesheet,
'overlay': job.overlay.split(","),
'maptitle': job.maptitle,
'submittermail': job.submittermail,
'default_papersize': paper_size,
'default_paperorientation': paper_orientation,
}
request.session['new_layout'] = job.layout
request.session['new_indexer'] = job.indexer
request.session['new_stylesheet'] = job.stylesheet
request.session['new_overlay'] = job.overlay.split(",")
form = forms.MapRenderingJobForm(initial=init_vals)
bounds = "L.latLngBounds(L.latLng(%f,%f),L.latLng(%f,%f))" % (job.lat_upper_left,
job.lon_upper_left,
job.lat_bottom_right,
job.lon_bottom_right)
return render(request,
'maposmatic/new.html',
{
'form' : form,
'SELECTION_BOUNDS': bounds,
})
return HttpResponseBadRequest("ERROR: Invalid request")

Wyświetl plik

@ -83,15 +83,13 @@ TEMPLATES = [
'DIRS': [
os.path.join(PROJECT_PATH, 'templates'),
os.path.join(PROJECT_PATH, 'maposmatic/templates'),
# TODO ocitysmap path should not be hardcoded
os.path.join('/home/maposmatic/ocitysmap/templates'),
OCITYSMAP_PATH,
],
'APP_DIRS': True,
'OPTIONS': {
'debug': True,
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django_settings_export.settings_export',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
@ -105,10 +103,6 @@ TEMPLATES = [
},
]
SETTINGS_EXPORT = [
'CONTACT_EMAIL',
]
MIDDLEWARE = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',

Wyświetl plik

@ -32,12 +32,19 @@ import sys
# sys.path.append('/path/to/ocitysmap')
# sys.path.append('/path/to/lib/python/site-packages')
# path to OCitysMap installation
OCITYSMAP_PATH='/home/maposmatic/ocitysmap'
sys.path.append(OCITYSMAP_PATH)
# Debug mode. Set to False on a production environnement
DEBUG = True
# With DEBUG set to False error will be set to the following emails
ADMINS = (
('MapOSMatic admin', 'your-name@example.org'),
)
# various databases used
DATABASES = {
# default MapOSMatic django database
'default': {
@ -72,12 +79,17 @@ DATABASES = {
# (~/.ocitysmap.conf)
OCITYSMAP_CFG_PATH = None
# Where rendered maps are to be stored
RENDERING_RESULT_PATH = '/path/to/rendering/results/'
RENDERING_RESULT_URL = '/results/' # Either a relative URL or an absolute URL
RENDERING_RESULT_FORMATS = ['pdf', 'svgz', 'png', 'csv']
# When / how fast old maps should get purged
RENDERING_RESULT_MAX_SIZE_GB = 10
RENDERING_RESULT_MAX_PURGE_ITERATIONS = 10
# File formats to render
RENDERING_RESULT_FORMATS = ['pdf', 'svgz', 'png', 'csv']
# Default output log file when the env variable MAPOSMATIC_LOG_FILE is not set
DEFAULT_MAPOSMATIC_LOG_FILE = '/path/to/maposmatic/logs/maposmatic.log'
@ -142,7 +154,6 @@ DAEMON_ERRORS_JOB_URL = 'http://example.org/jobs/%d'
# highest rendering request ID still using the old filename scheme
# before the switch to sluggify
LAST_OLD_ID = 0

Wyświetl plik

@ -8,7 +8,7 @@
# Copyright (C) 2009 Maxime Petazzoni
# Copyright (C) 2009 Thomas Petazzoni
# Copyright (C) 2009 Gaël Utard
# Copyright (C) 2018 Hartmut Holzgraefe
# Copyright (C) 2023 Hartmut Holzgraefe
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -34,129 +34,88 @@ from django.views.generic.base import RedirectView
# from django.contrib import admin
# admin.autodiscover()
from .maposmatic import feeds
from .maposmatic import rss_feeds
from .maposmatic import views
from .maposmatic import apis
from . import settings
urlpatterns = [
re_path(r'^$',
views.index,
name='main'),
re_path(r'^$', views.index, name = 'main'),
re_path(r'^new/$',
views.new,
name='new'),
re_path(r'^recreate/$',
views.recreate,
name='recreate'),
re_path(r'^reedit/$',
views.reedit,
name='reedit'),
re_path(r'^cancel/$',
views.cancel,
name='cancel'),
re_path(r'^new/$', views.new, name = 'new'),
re_path(r'^recreate/$', views.recreate, name = 'recreate'),
re_path(r'^reedit/$', views.reedit, name = 'reedit'),
re_path(r'^cancel/$', views.cancel, name = 'cancel'),
re_path(r'^maps/(?P<id>\d+)/(?P<nonce>[A-Za-z]{16})$',
views.map_full,
name='map-by-id-and-nonce'),
re_path(r'^maps/(?P<id>\d+)[/]?$',
views.map_full,
name='map-by-id'),
re_path(r'^maps/(?P<category>[a-z]+)$',
views.maps,
name='maps-list-cagetory'),
re_path(r'^maps/(?P<category>[a-z]+)/(?P<extra>[a-z-]+)$',
views.maps,
name='maps-list-cagetory-extra'),
re_path(r'^maps/$',
views.maps,
name='maps'),
re_path(r'^maps/(?P<id>\d+)/(?P<nonce>[A-Za-z]{16})$', views.map_full, name = 'map-by-id-and-nonce'),
re_path(r'^maps/(?P<id>\d+)[/]?$', views.map_full, name = 'map-by-id'),
re_path(r'^maps/(?P<category>[a-z]+)$', views.maps, name = 'maps-list-cagetory'),
re_path(r'^maps/(?P<category>[a-z]+)/(?P<extra>[a-z-]+)$', views.maps, name = 'maps-list-cagetory-extra'),
re_path(r'^maps/$', views.maps, name = 'maps'),
re_path(r'^about/api/$',
views.documentation_api,
name='documentation_api'),
re_path(r'^about/user-guide/$',
views.documentation_user_guide,
name='documentation_user_guide'),
re_path(r'^about/$',
views.about,
name='about'),
re_path(r'^about/api/$', views.documentation_api, name = 'documentation_api'),
re_path(r'^about/user-guide/$', views.documentation_user_guide, name = 'documentation_user_guide'),
re_path(r'^about/$', views.about, name = 'about'),
re_path(r'^privacy/$',
views.privacy,
name='privacy'),
re_path(r'^privacy/$', views.privacy, name = 'privacy'),
re_path(r'^donate/$',
views.donate,
name='donate'),
re_path(r'^donate-thanks/$',
views.donate_thanks,
name='donate-thanks'),
re_path(r'^donate/$', views.donate, name = 'donate'),
re_path(r'^donate-thanks/$', views.donate_thanks, name = 'donate-thanks'),
# API calls used by the web frontend
# re_path(r'^apis/nominatim/$', views.api_nominatim),
re_path(r'^apis/nominatim/$', views.api_geosearch),
re_path(r'^apis/reversegeo/([^/]*)/([^/]*)/$', views.api_postgis_reverse),
re_path(r'^apis/papersize', views.api_papersize),
re_path(r'^apis/boundingbox/([^/]*)/$', views.api_bbox),
re_path(r'^apis/polygon/([^/]*)/$', views.api_polygon),
re_path(r'^apis/rendering-status/([^/]*)$', views.api_rendering_status),
# re_path(r'^apis/nominatim/$', api.api_nominatim), # TODO: make configurable
re_path(r'^apis/nominatim/$', apis.api_geosearch),
re_path(r'^apis/reversegeo/([^/]*)/([^/]*)/$', apis.api_postgis_reverse),
re_path(r'^apis/papersize', apis.api_papersize),
re_path(r'^apis/boundingbox/([^/]*)/$', apis.api_bbox),
re_path(r'^apis/polygon/([^/]*)/$', apis.api_polygon),
re_path(r'^apis/rendering-status/([^/]*)$', apis.api_rendering_status),
# API calls for direct clients
# unversioned
re_path(r'^apis/paper_formats', apis.paper_formats),
re_path(r'^apis/layouts', apis.layouts),
re_path(r'^apis/styles', apis.styles),
re_path(r'^apis/overlays', apis.overlays),
re_path(r'^apis/job-stati', apis.job_stati),
re_path(r'^apis/jobs$', apis.jobs),
re_path(r'^apis/jobs/(\d*)$', apis.jobs),
re_path(r'^apis/cancel_job$', apis.cancel_job),
re_path(r'^apis/paper_formats', apis.paper_formats),
re_path(r'^apis/layouts', apis.layouts),
re_path(r'^apis/styles', apis.styles),
re_path(r'^apis/overlays', apis.overlays),
re_path(r'^apis/job-stati', apis.job_stati),
re_path(r'^apis/jobs$', apis.jobs),
re_path(r'^apis/jobs/(\d*)$', apis.jobs),
re_path(r'^apis/cancel_job$', apis.cancel_job),
# versioned
re_path(r'^apis/v1/paper_formats', apis.paper_formats),
re_path(r'^apis/v1/layouts', apis.layouts),
re_path(r'^apis/v1/styles', apis.styles),
re_path(r'^apis/v1/overlays', apis.overlays),
re_path(r'^apis/v1/job-stati', apis.job_stati),
re_path(r'^apis/v1/jobs$', apis.jobs),
re_path(r'^apis/v1/jobs/(\d*)$', apis.jobs),
re_path(r'^apis/v1/cancel_job$', apis.cancel_job),
re_path(r'^apis/v1/paper_formats', apis.paper_formats),
re_path(r'^apis/v1/layouts', apis.layouts),
re_path(r'^apis/v1/styles', apis.styles),
re_path(r'^apis/v1/overlays', apis.overlays),
re_path(r'^apis/v1/job-stati', apis.job_stati),
re_path(r'^apis/v1/jobs$', apis.jobs),
re_path(r'^apis/v1/jobs/(\d*)$', apis.jobs),
re_path(r'^apis/v1/cancel_job$', apis.cancel_job),
# Feeds
re_path(r'feeds/maps/$', feeds.MapsFeed(), name='rss-feed'),
re_path(r'feeds/errors/$', feeds.ErrorFeed(), name='error-feed'),
re_path(r'feeds/maps/$', rss_feeds.MapsFeed(), name='rss-feed'),
re_path(r'feeds/errors/$', rss_feeds.ErrorFeed(), name='error-feed'),
# experimental
re_path(r'heatmap/(\d*)$', views.heatmap, name='heatmap'),
re_path(r'^apis/heatdata/(\d*)$', apis.heatdata),
re_path(r'^congo/$', views.congo, name='congo'),
# Internationalization
re_path(r'^i18n/', include('django.conf.urls.i18n')),
# robots.txt
re_path(r'^robots\.txt$', TemplateView.as_view(template_name="robots.txt", content_type='text/plain')),
re_path(r'^robots\.txt$', TemplateView.as_view(template_name = "robots.txt", content_type = 'text/plain')),
# favicons
re_path(r'^favicon\.png$', RedirectView.as_view(url=staticfiles_storage.url('img/favicon.png'))),
re_path(r'^favicon\.ico$', RedirectView.as_view(url=staticfiles_storage.url('img/favicon.ico'))),
re_path(r'^apple-touch-icon.*\.png$', RedirectView.as_view(url=staticfiles_storage.url('img/apple-touch-icon.png'))),
# test
re_path(r'heatmap/(\d*)$',
views.heatmap,
name='heatmap'),
re_path(r'^apis/heatdata/(\d*)$', apis.heatdata),
re_path(r'^congo/$',
views.congo,
name='congo'),
re_path(r'^favicon\.png$', RedirectView.as_view(url = staticfiles_storage.url('img/favicon.png'))),
re_path(r'^favicon\.ico$', RedirectView.as_view(url = staticfiles_storage.url('img/favicon.ico'))),
re_path(r'^apple-touch-icon.*\.png$', RedirectView.as_view(url = staticfiles_storage.url('img/apple-touch-icon.png'))),
]
if settings.DEBUG:
urlpatterns.append(
re_path(r'^results/(?P<path>.*)$', serve,
{'document_root': settings.RENDERING_RESULT_PATH}))
urlpatterns.append( re_path(r'^results/(?P<path>.*)$', serve, {'document_root': settings.RENDERING_RESULT_PATH}))
urlpatterns.append(
re_path(r'^media/(?P<path>.*)$', serve,
{'document_root': settings.LOCAL_MEDIA_PATH}))
urlpatterns.append( re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.LOCAL_MEDIA_PATH}))