kopia lustrzana https://github.com/hholzgra/maposmatic/
Porównaj commity
16 Commity
c032057703
...
ee5ad39915
Autor | SHA1 | Data |
---|---|---|
Hartmut Holzgraefe | ee5ad39915 | |
Hartmut Holzgraefe | 6b3309f593 | |
Hartmut Holzgraefe | cc4feb7885 | |
Hartmut Holzgraefe | 60cf27ad0e | |
Hartmut Holzgraefe | 0563245851 | |
Hartmut Holzgraefe | 38e6ca7d9e | |
Hartmut Holzgraefe | bee31b3fbf | |
Hartmut Holzgraefe | 2e88738617 | |
Hartmut Holzgraefe | e73905c62e | |
Hartmut Holzgraefe | 9a37d9dcc2 | |
Hartmut Holzgraefe | fb0b362220 | |
Hartmut Holzgraefe | a46d555a07 | |
Hartmut Holzgraefe | 53cbb56d26 | |
Hartmut Holzgraefe | 9a9e240748 | |
Hartmut Holzgraefe | f992156c70 | |
Hartmut Holzgraefe | 1b9d930b50 |
|
@ -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(
|
||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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')
|
|
@ -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")
|
||||
|
|
@ -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')
|
||||
|
|
@ -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')
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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')
|
|
@ -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')
|
|
@ -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')
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
|
@ -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",
|
||||
})
|
|
@ -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")
|
|
@ -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')
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -0,0 +1,2 @@
|
|||
from .MapsFeed import MapsFeed
|
||||
from .ErrorFeed import ErrorFeed
|
|
@ -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 %}
|
||||
|
|
|
@ -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>×<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×%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×%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",
|
||||
})
|
|
@ -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
|
|
@ -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',
|
||||
{ }
|
||||
)
|
|
@ -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")
|
|
@ -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',
|
||||
{ }
|
||||
)
|
|
@ -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',
|
||||
{ }
|
||||
)
|
|
@ -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')
|
|
@ -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 ,
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -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()
|
||||
}
|
||||
)
|
|
@ -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,
|
||||
})
|
||||
|
|
@ -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),
|
||||
})
|
||||
|
|
@ -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>×<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×%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×%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),
|
||||
})
|
|
@ -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',
|
||||
{ }
|
||||
)
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
149
www/urls.py
149
www/urls.py
|
@ -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}))
|
||||
|
|
Ładowanie…
Reference in New Issue