Merge branch 'site-osm-baustelle' of https://github.com/hholzgra/maposmatic into site-osm-baustelle
|
@ -33,7 +33,7 @@ pdf: api-docs.pdf user-guide.pdf README.pdf INSTALL.pdf
|
|||
clean:
|
||||
rm -f *.html *.pdf *~
|
||||
|
||||
install: all
|
||||
install: html
|
||||
cp *.html ../www/maposmatic/templates/generated
|
||||
|
||||
.PHONY = html clean all install
|
||||
|
|
|
@ -199,7 +199,7 @@ Expects render job named parameters as a JSON collection.
|
|||
|
||||
Possible parameters:
|
||||
|
||||
osmid:: ID of an object in the osm2pgsql
|
||||
osmid:: ID of an object in the osm2pgsql polygon table
|
||||
bbox_top::
|
||||
bbox_bottom::
|
||||
bbox_left::
|
||||
|
@ -317,7 +317,7 @@ Example results
|
|||
----
|
||||
HTTP/1.1 202 Accepted
|
||||
[...]
|
||||
Location: /api/jobs/36
|
||||
Location: /api/jobs/214
|
||||
Content-Type: text/json
|
||||
|
||||
{
|
||||
|
@ -325,15 +325,16 @@ Content-Type: text/json
|
|||
"bbox_left": 8.52,
|
||||
"bbox_right": 8.50,
|
||||
"bbox_top": 52.02,
|
||||
"id": 36,
|
||||
"id": 214,
|
||||
"interactive": "https://api.get-map.org/maps/214"
|
||||
"language": "en_US.UTF-8",
|
||||
"layout": "plain",
|
||||
"nonce": "ESubNGmuwYGxPEGM",
|
||||
"paper_height_mm": 297,
|
||||
"paper_width_mm": 210,
|
||||
"status": 0,
|
||||
"styles": "CartoOSM"
|
||||
"title": "API Test",
|
||||
"styles": "CartoOSM",
|
||||
"title": "API Test"
|
||||
}
|
||||
----
|
||||
|
||||
|
@ -404,6 +405,35 @@ Content-type: application/json
|
|||
----
|
||||
|
||||
|
||||
Cancel a submitted job
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Request URL
|
||||
^^^^^^^^^^^
|
||||
|
||||
----
|
||||
POST https://api.get-map.org/apis/cancel_job
|
||||
----
|
||||
|
||||
Expects id and nonce of job to cancel as a JSON collection.
|
||||
|
||||
Nonce is only returned when creating a job, so only the creator
|
||||
should be able to cancel a job but nobody else.
|
||||
|
||||
Required parameters:
|
||||
|
||||
id:: ID of job to cancel
|
||||
nonce:: nonce string as returned on job creation call
|
||||
|
||||
Return codes
|
||||
^^^^^^^^^^^^
|
||||
|
||||
204:: 'No content' when job was cancelled successfully, or already no longer in a wait queue
|
||||
400:: 'Bad request' when either id or nonce parameter are missing
|
||||
403:: 'Forbidden' when the given nonce does not match the jobs actual nonce
|
||||
404:: 'Not found' when no job with the given id exists
|
||||
|
||||
|
||||
|
||||
Example code
|
||||
------------
|
||||
|
|
|
@ -63,8 +63,9 @@ class MapOSMaticDaemon:
|
|||
stalls the queue.
|
||||
"""
|
||||
|
||||
def __init__(self, frequency=_DEFAULT_POLL_FREQUENCY):
|
||||
def __init__(self, frequency=_DEFAULT_POLL_FREQUENCY, queue_name="default"):
|
||||
self.frequency = frequency
|
||||
self.queue_name = queue_name
|
||||
LOG.info("MapOSMatic rendering daemon started.")
|
||||
self.rollback_orphaned_jobs()
|
||||
|
||||
|
@ -89,7 +90,7 @@ class MapOSMaticDaemon:
|
|||
|
||||
while True:
|
||||
try:
|
||||
job = MapRenderingJob.objects.to_render()[0]
|
||||
job = MapRenderingJob.objects.to_render(self.queue_name)[0]
|
||||
self.dispatch(job)
|
||||
|
||||
# check disk space after rendering
|
||||
|
@ -144,8 +145,8 @@ class MapOSMaticDaemon:
|
|||
|
||||
class ForkingMapOSMaticDaemon(MapOSMaticDaemon):
|
||||
|
||||
def __init__(self, frequency=_DEFAULT_POLL_FREQUENCY):
|
||||
MapOSMaticDaemon.__init__(self, frequency)
|
||||
def __init__(self, frequency=_DEFAULT_POLL_FREQUENCY, queue_name="default"):
|
||||
MapOSMaticDaemon.__init__(self, frequency, queue_name)
|
||||
LOG.info('This is the forking daemon. Will fork to process each job.')
|
||||
|
||||
def get_renderer(self, job, prefix):
|
||||
|
@ -273,7 +274,10 @@ if __name__ == '__main__':
|
|||
sys.exit(1)
|
||||
|
||||
try:
|
||||
daemon = ForkingMapOSMaticDaemon()
|
||||
if len(sys.argv) == 2:
|
||||
daemon = ForkingMapOSMaticDaemon(queue_name=sys.argv[1])
|
||||
else:
|
||||
daemon = ForkingMapOSMaticDaemon()
|
||||
daemon.serve()
|
||||
except Exception as e:
|
||||
LOG.exception('Fatal error during daemon execution!')
|
||||
|
|
|
@ -114,7 +114,7 @@ class ThreadingJobRenderer:
|
|||
'timeout': self.__timeout / 60
|
||||
}
|
||||
msg = template.render(context)
|
||||
|
||||
|
||||
mailer.sendmail(DAEMON_ERRORS_EMAIL_FROM,
|
||||
[admin[1] for admin in ADMINS], msg)
|
||||
LOG.info("Email notification sent.")
|
||||
|
@ -196,8 +196,8 @@ class ForkingJobRenderer:
|
|||
'title': self.__job.maptitle,
|
||||
'timeout': self.__timeout / 60
|
||||
}
|
||||
msg = template.render(context)
|
||||
|
||||
msg = template.render(context)
|
||||
|
||||
mailer.sendmail(DAEMON_ERRORS_EMAIL_FROM,
|
||||
[admin[1] for admin in ADMINS], msg)
|
||||
LOG.info("Email notification sent.")
|
||||
|
@ -309,7 +309,7 @@ class JobRenderer(threading.Thread):
|
|||
'title': self.job.maptitle
|
||||
}
|
||||
msg = template.render(context)
|
||||
|
||||
|
||||
mailer.sendmail(DAEMON_ERRORS_EMAIL_FROM, self.job.submittermail, msg.encode("utf8"))
|
||||
LOG.info("Email notification sent.")
|
||||
except Exception as e:
|
||||
|
@ -359,7 +359,7 @@ class JobRenderer(threading.Thread):
|
|||
'tb': ''.join(traceback.format_exception(*exc_info))
|
||||
}
|
||||
msg = template.render(context)
|
||||
|
||||
|
||||
mailer.sendmail(DAEMON_ERRORS_EMAIL_FROM,
|
||||
[admin[1] for admin in ADMINS], msg)
|
||||
LOG.info("Error report sent.")
|
||||
|
@ -440,6 +440,7 @@ class JobRenderer(threading.Thread):
|
|||
|
||||
# TODO have the create form provide this
|
||||
config.origin_url = 'https://print.get-map.org' + self.job.get_absolute_url()
|
||||
|
||||
config.title = self.job.maptitle
|
||||
config.osmid = self.job.administrative_osmid
|
||||
|
||||
|
@ -456,6 +457,9 @@ class JobRenderer(threading.Thread):
|
|||
self.job.lon_bottom_right)
|
||||
|
||||
config.language = self.job.map_language
|
||||
|
||||
config.indexer = self.job.indexer
|
||||
|
||||
config.stylesheet = renderer.get_stylesheet_by_name(
|
||||
self.job.stylesheet)
|
||||
config.overlays = []
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
Copy both .service files to /etc/systemd/system and edit them to change the
|
||||
path to the wrapper.py script to the actual script location on your system.
|
||||
|
||||
The maposmatic-render.service takes render requests from the "default" queue.
|
||||
|
||||
You can start this service by simply invoking
|
||||
|
||||
systemctl start maposmatic-render
|
||||
|
||||
and enable it permanently using
|
||||
|
||||
systemctl enable maposmatic-render
|
||||
|
||||
Jobs from additional queues, like e.g. "api", can be rendered using the
|
||||
maposmatic-render@.service template. To start a service for a specific
|
||||
queue add the queue name after the @ sign, e.g.:
|
||||
|
||||
systemctl start maposmatic-render@api
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=Maposmatic render daemon processing queue: %I
|
||||
After=multi-user.target
|
||||
Wants=postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=idle
|
||||
User=maposmatic
|
||||
ExecStart=/usr/bin/python /path/to/maposmatic/scripts/wrapper.py scripts/daemon.py %i
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ 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, Http404
|
||||
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
|
||||
|
@ -90,9 +90,7 @@ def layouts(request):
|
|||
|
||||
return HttpResponse( content=json.dumps(result, indent=4, sort_keys=True, default=str), content_type='text/json')
|
||||
|
||||
|
||||
|
||||
def job_stati(request):
|
||||
def job_stati_dict(id = None):
|
||||
# TODO do not hard-code these, get them from OCitysMap cleanly
|
||||
result = {
|
||||
"0": "Submitted",
|
||||
|
@ -102,16 +100,40 @@ def job_stati(request):
|
|||
"4": "Cancelled"
|
||||
}
|
||||
|
||||
return HttpResponse( content=json.dumps(result, indent=4, sort_keys=True, default=str), content_type='text/json')
|
||||
if id is not None:
|
||||
return result[str(id)]
|
||||
|
||||
def heatdata(request):
|
||||
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
|
||||
, 1 as count
|
||||
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": [] }
|
||||
|
||||
|
@ -129,7 +151,7 @@ select (lat_upper_left + lat_bottom_right)/2 as lat
|
|||
|
||||
cursor.close()
|
||||
|
||||
return HttpResponse(content="var data = " + json.dumps(data),
|
||||
return HttpResponse(content="var data = " + json.dumps(data, indent=2),
|
||||
content_type='application/javascript')
|
||||
|
||||
except Exception as e:
|
||||
|
@ -155,8 +177,9 @@ def _jobs_get(request, job_id):
|
|||
reply = model_to_dict(job)
|
||||
|
||||
result = {}
|
||||
result['id'] = job_id
|
||||
result['id'] = int(job_id)
|
||||
result['status'] = reply['status']
|
||||
result['status_msg'] = job_stati_dict(reply['status'])
|
||||
|
||||
if reply['administrative_osmid']:
|
||||
result['osm_id'] = reply['administrative_osmid']
|
||||
|
@ -188,6 +211,8 @@ def _jobs_get(request, job_id):
|
|||
for key, val in files['maps'].items():
|
||||
result['files'][key] = request.build_absolute_uri(val[0])
|
||||
|
||||
result['interactive'] = request.build_absolute_uri('../../../maps/%d' % reply['id'])
|
||||
|
||||
if job.status <= 1:
|
||||
status = 202
|
||||
else:
|
||||
|
@ -209,10 +234,15 @@ def _jobs_post(request):
|
|||
input = json.loads(request.POST['job'])
|
||||
|
||||
valid_keys = ['osmid',
|
||||
'bbox',
|
||||
'bbox_bottom',
|
||||
'bbox_left',
|
||||
'bbox_right',
|
||||
'bbox_top',
|
||||
'min_lat',
|
||||
'max_lat',
|
||||
'min_lon',
|
||||
'max_lon',
|
||||
'import_urls',
|
||||
'language',
|
||||
'layout',
|
||||
|
@ -233,6 +263,16 @@ def _jobs_post(request):
|
|||
|
||||
if 'osmid' in input:
|
||||
job.administrative_osmid= input['osmid']
|
||||
elif 'bbox' in input:
|
||||
job.lat_upper_left = input['bbox'][0]
|
||||
job.lon_upper_left = input['bbox'][3]
|
||||
job.lat_bottom_right = input['bbox'][2]
|
||||
job.lon_bottom_right = input['bbox'][1]
|
||||
elif 'lat_min' in input and 'lat_max' in input and 'lon_min' in input and 'lon_max' in input:
|
||||
job.lat_upper_left = input['max_lat']
|
||||
job.lon_upper_left = input['min_lon']
|
||||
job.lat_bottom_right = input['min_lat']
|
||||
job.lon_bottom_right = input['max_lon']
|
||||
elif 'bbox_top' in input and 'bbox_bottom' in input and 'bbox_left' in input and 'bbox_right' in input:
|
||||
job.lat_upper_left = input['bbox_top']
|
||||
job.lon_upper_left = input['bbox_left']
|
||||
|
@ -370,6 +410,8 @@ def _jobs_post(request):
|
|||
if not job.layout:
|
||||
job.layout = 'plain'
|
||||
|
||||
job.queue = 'api'
|
||||
|
||||
if not result['error']:
|
||||
job.status = 0
|
||||
if www.settings.SUBMITTER_IP_LIFETIME != 0:
|
||||
|
@ -377,7 +419,7 @@ def _jobs_post(request):
|
|||
else:
|
||||
job.submitterip = None
|
||||
|
||||
job.index_queue_at_submission = (models.MapRenderingJob.objects.queue_size())
|
||||
job.index_queue_at_submission = (models.MapRenderingJob.objects.queue_size(job.queue))
|
||||
job.nonce = helpers.generate_nonce(models.MapRenderingJob.NONCE_SIZE)
|
||||
try:
|
||||
job.full_clean()
|
||||
|
@ -393,7 +435,15 @@ def _jobs_post(request):
|
|||
reply = model_to_dict(job)
|
||||
|
||||
result['id'] = reply['id']
|
||||
result['nonce'] = reply['nonce']
|
||||
result['status'] = reply['status']
|
||||
result['status_msg'] = job_stati_dict(reply['status'])
|
||||
if reply['status'] == 0:
|
||||
result['queue_size'] = models.MapRenderingJob.objects.queue_size()
|
||||
else:
|
||||
result['queue_size'] = 0
|
||||
|
||||
result['files'] = {}
|
||||
|
||||
result['interactive'] = request.build_absolute_uri('../../maps/%d' % reply['id'])
|
||||
|
||||
|
@ -588,3 +638,29 @@ def _process_poi_file(file):
|
|||
raise RuntimeError('Cannot parse POI file: %s' % e)
|
||||
|
||||
return result
|
||||
|
||||
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)
|
||||
|
|
|
@ -32,7 +32,7 @@ import datetime
|
|||
from .models import MapRenderingJob
|
||||
import www.settings
|
||||
|
||||
from www.maposmatic import forms
|
||||
from www.maposmatic import forms, models
|
||||
|
||||
import logging
|
||||
|
||||
|
@ -98,6 +98,51 @@ def get_waymarked_database_last_update():
|
|||
|
||||
return None
|
||||
|
||||
def queue_states():
|
||||
queues = {}
|
||||
|
||||
for queue_name in www.settings.QUEUE_NAMES:
|
||||
status = {}
|
||||
status['running'] = www.settings.is_daemon_running(queue_name)
|
||||
status['size'] = models.MapRenderingJob.objects.queue_size(queue_name)
|
||||
queues[queue_name] = status
|
||||
|
||||
return queues
|
||||
|
||||
def all_queues_running():
|
||||
for queue_name in www.settings.QUEUE_NAMES:
|
||||
if not www.settings.is_daemon_running(queue_name):
|
||||
return False
|
||||
return True
|
||||
|
||||
def queues_overall_state():
|
||||
queues_total = 0
|
||||
queues_running = 0
|
||||
for queue_name in www.settings.QUEUE_NAMES:
|
||||
queues_total = queues_total + 1
|
||||
if www.settings.is_daemon_running(queue_name):
|
||||
queues_running = queues_running + 1
|
||||
|
||||
if queues_running == 0:
|
||||
return "danger"
|
||||
if queues_running < queues_total:
|
||||
return "warning"
|
||||
return "success"
|
||||
|
||||
def queues_overall_symbol():
|
||||
queues_total = 0
|
||||
queues_running = 0
|
||||
for queue_name in www.settings.QUEUE_NAMES:
|
||||
queues_total = queues_total + 1
|
||||
if www.settings.is_daemon_running(queue_name):
|
||||
queues_running = queues_running + 1
|
||||
|
||||
if queues_running == 0:
|
||||
return "times"
|
||||
if queues_running < queues_total:
|
||||
return "exclamation"
|
||||
return "check"
|
||||
|
||||
def all(request):
|
||||
# Do not add the useless overhead of parsing blog entries when generating
|
||||
# the rss feed
|
||||
|
@ -112,7 +157,7 @@ def all(request):
|
|||
paypal_lang_code = "en_US"
|
||||
paypal_country_code = "US"
|
||||
|
||||
daemon_running = www.settings.is_daemon_running()
|
||||
daemon_running = all_queues_running()
|
||||
|
||||
gis_lastupdate = get_osm_database_last_update()
|
||||
gis_lag_ok = (gis_lastupdate
|
||||
|
@ -168,4 +213,8 @@ def all(request):
|
|||
|
||||
'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(),
|
||||
}
|
||||
|
|
|
@ -55,14 +55,15 @@ class MapRenderingJobForm(forms.ModelForm):
|
|||
"""
|
||||
class Meta:
|
||||
model = models.MapRenderingJob
|
||||
fields = ('layout', 'stylesheet', 'overlay',
|
||||
fields = ('layout', 'indexer', 'stylesheet', 'overlay',
|
||||
'maptitle', 'administrative_city',
|
||||
'lat_upper_left', 'lon_upper_left',
|
||||
'lat_bottom_right', 'lon_bottom_right',
|
||||
'submittermail')
|
||||
|
||||
mode = forms.CharField(initial='bbox', widget=forms.HiddenInput)
|
||||
layout = forms.ChoiceField(choices=(), widget=forms.RadioSelect(attrs= { 'onchange' : 'clearPaperSize(this.value); $("#layout-preview").attr("src","/media/img/layout/"+this.value+".png");'}))
|
||||
layout = forms.ChoiceField(choices=(), widget=forms.Select(attrs= { 'onchange' : 'clearPaperSize(this.value); load_preview("#layout-preview", this.value);'}))
|
||||
indexer = forms.ChoiceField(choices=(), widget=forms.Select())
|
||||
stylesheet = forms.ChoiceField(choices=(), widget=forms.Select(attrs= { 'onchange' : '$("#style-preview").attr("src","/media/img/style/"+this.value+".jpg");'}))
|
||||
overlay = forms.MultipleChoiceField(choices=(), widget=forms.SelectMultiple(attrs= { 'class': 'multipleSelect' }), required=False)
|
||||
paper_width_mm = forms.IntegerField(widget=forms.NumberInput(attrs= {'onchange' : 'change_papersize();', 'style': 'width: 5em;'}), min_value=100, max_value=2000)
|
||||
|
@ -96,32 +97,24 @@ class MapRenderingJobForm(forms.ModelForm):
|
|||
self._ocitysmap = ocitysmap.OCitySMap(www.settings.OCITYSMAP_CFG_PATH)
|
||||
|
||||
layout_renderers = self._ocitysmap.get_all_renderers()
|
||||
indexers = self._ocitysmap.get_all_indexers()
|
||||
stylesheets = self._ocitysmap.get_all_style_configurations()
|
||||
overlays = self._ocitysmap.get_all_overlay_configurations()
|
||||
|
||||
self.fields['layout'].choices = []
|
||||
# TODO move descriptions to ocitysmap side
|
||||
for r in layout_renderers:
|
||||
if r.name == 'plain':
|
||||
description = _(u"Full-page layout without street index")
|
||||
elif r.name == 'single_page_index_side':
|
||||
description = _(u"Full-page layout with the street index on the side")
|
||||
elif r.name == 'single_page_index_bottom':
|
||||
description = _(u"Full-page layout with the street index at the bottom")
|
||||
elif r.name == 'single_page_index_extra_page':
|
||||
description = _(u"Full-page layout with the street index on extra page (PDF only)")
|
||||
elif r.name == 'tk25':
|
||||
description = _(u"TK25 full page layout")
|
||||
elif r.name == 'multi_page':
|
||||
description = _(u"Multi-page layout")
|
||||
else:
|
||||
continue
|
||||
# description = mark_safe(_(u"The %(layout_name)s layout") % {'layout_name':r.name})
|
||||
self.fields['layout'].choices.append((r.name, description))
|
||||
self.fields['layout'].choices.append((r.name, r.description))
|
||||
|
||||
if not self.fields['layout'].initial:
|
||||
self.fields['layout'].initial = layout_renderers[0].name
|
||||
|
||||
# TODO get these from ocitysmap instead of hardcoding here
|
||||
self.fields['indexer'].choices = self._ocitysmap.get_all_indexers_name_desc()
|
||||
|
||||
if not self.fields['indexer'].initial:
|
||||
self.fields['indexer'].initial = 'Street' # TODO: make configurable
|
||||
|
||||
style_choices = {"": []}
|
||||
for s in stylesheets:
|
||||
if s.description is not None:
|
||||
|
@ -136,7 +129,7 @@ class MapRenderingJobForm(forms.ModelForm):
|
|||
group = s.group
|
||||
else:
|
||||
group = ""
|
||||
|
||||
|
||||
if group not in style_choices:
|
||||
style_choices[group] = []
|
||||
style_choices[s.group].append((s.name, description))
|
||||
|
@ -185,6 +178,7 @@ class MapRenderingJobForm(forms.ModelForm):
|
|||
city = cleaned_data.get("administrative_city")
|
||||
title = cleaned_data.get("maptitle")
|
||||
layout = cleaned_data.get("layout")
|
||||
indexer = cleaned_data.get("indexer")
|
||||
stylesheet = cleaned_data.get("stylesheet")
|
||||
overlay_array = []
|
||||
try:
|
||||
|
@ -199,6 +193,11 @@ class MapRenderingJobForm(forms.ModelForm):
|
|||
self._errors["layout"] = ErrorList([msg])
|
||||
del cleaned_data["layout"]
|
||||
|
||||
if indexer == '':
|
||||
msg = _(u"Indexer required")
|
||||
self._errors["indexer"] = ErrorList([msg])
|
||||
del cleaned_data["indexer"]
|
||||
|
||||
if stylesheet == '':
|
||||
msg = _(u"Stylesheet required")
|
||||
self._errors["stylesheet"] = ErrorList([msg])
|
||||
|
@ -293,6 +292,7 @@ class MapPaperSizeForm(forms.Form):
|
|||
"""
|
||||
osmid = forms.IntegerField(required=False)
|
||||
layout = forms.CharField(max_length=256)
|
||||
indexer = forms.CharField(max_length=256)
|
||||
stylesheet = forms.CharField(max_length=256)
|
||||
lat_upper_left = forms.FloatField(required=False, min_value=-90.0, max_value=90.0)
|
||||
lon_upper_left = forms.FloatField(required=False, min_value=-180.0, max_value=180.0)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.12 on 2022-08-16 12:40
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('maposmatic', '0023_no_NULL_maptitles'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='maprenderingjob',
|
||||
name='queue',
|
||||
field=models.CharField(default='default', max_length=40),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.12 on 2022-08-21 15:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('maposmatic', '0024_maprenderingjob_queue'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='maprenderingjob',
|
||||
name='indexer',
|
||||
field=models.CharField(max_length=256, null=True),
|
||||
),
|
||||
migrations.RunSQL("UPDATE maposmatic_maprenderingjob SET indexer = 'Street' WHERE layout LIKE '%index%'"),
|
||||
]
|
|
@ -0,0 +1,11 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('maposmatic', '0025_maprenderingjob_indexer'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunSQL("UPDATE maposmatic_maprenderingjob j SET indexer = 'poi' FROM maposmatic_uploadfile_job uj, maposmatic_uploadfile u WHERE j.id = uj.maprenderingjob_id AND uj.uploadfile_id = u.id AND u.file_type = 'poi'"),
|
||||
]
|
|
@ -0,0 +1,12 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('maposmatic', '0026_maprenderingjob_indexer'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunSQL("UPDATE maposmatic_maprenderingjob SET indexer = 'StreetIndex' WHERE indexer = 'Street'"),
|
||||
migrations.RunSQL("UPDATE maposmatic_maprenderingjob SET indexer = 'PoiIndex' WHERE indexer = 'Poi'"),
|
||||
]
|
|
@ -45,24 +45,11 @@ def get_poi_file_path(instance, filename):
|
|||
return ""
|
||||
|
||||
class MapRenderingJobManager(models.Manager):
|
||||
def to_render(self):
|
||||
return MapRenderingJob.objects.filter(status=0).order_by('submission_time')
|
||||
def to_render(self, queue_name = 'default'):
|
||||
return MapRenderingJob.objects.filter(status=0).filter(queue=queue_name).order_by('submission_time')
|
||||
|
||||
def queue_size(self):
|
||||
return MapRenderingJob.objects.filter(status=0).count()
|
||||
|
||||
# We try to find a rendered map from the last 15 days, which still
|
||||
# has its thumbnail present.
|
||||
def get_random_with_thumbnail(self):
|
||||
fifteen_days_before = datetime.now() - timedelta(15)
|
||||
maps = (MapRenderingJob.objects.filter(status=2)
|
||||
.filter(submission_time__gte=fifteen_days_before)
|
||||
.filter(resultmsg='ok')
|
||||
.order_by('?')[0:10])
|
||||
for m in maps:
|
||||
if m.get_thumbnail():
|
||||
return m
|
||||
return None
|
||||
def queue_size(self, queue_name = 'default'):
|
||||
return MapRenderingJob.objects.filter(status=0).filter(queue=queue_name).count()
|
||||
|
||||
def get_by_filename(self, name):
|
||||
"""Tries to find the parent MapRenderingJob of a given file from its
|
||||
|
@ -98,6 +85,7 @@ class MapRenderingJob(models.Model):
|
|||
stylesheet = models.CharField(max_length=256)
|
||||
overlay = models.CharField(max_length=256, null=True, blank=True)
|
||||
layout = models.CharField(max_length=256)
|
||||
indexer = models.CharField(max_length=256, null=True)
|
||||
paper_width_mm = models.IntegerField()
|
||||
paper_height_mm = models.IntegerField()
|
||||
bitmap_dpi = models.IntegerField(default=72)
|
||||
|
@ -126,6 +114,8 @@ class MapRenderingJob(models.Model):
|
|||
|
||||
renderstep = models.CharField(max_length=80,null=True,blank=True)
|
||||
|
||||
queue = models.CharField(max_length=40,null=False,blank=False, default='default')
|
||||
|
||||
nonce = models.CharField(max_length=NONCE_SIZE, blank=True)
|
||||
|
||||
class Meta:
|
||||
|
@ -325,17 +315,7 @@ class MapRenderingJob(models.Model):
|
|||
return None
|
||||
|
||||
def current_position_in_queue(self):
|
||||
return MapRenderingJob.objects.filter(status=0).filter(id__lte=self.id).count()
|
||||
|
||||
# Estimate the date at which the rendering will be started
|
||||
def rendering_estimated_start_time(self):
|
||||
waiting_time = datetime.now() - self.submission_time
|
||||
progression = self.index_queue_at_submission - self.current_position_in_queue()
|
||||
if progression == 0:
|
||||
return datetime.now()
|
||||
mean_job_rendering_time = waiting_time // progression
|
||||
estimated_time_left = mean_job_rendering_time * self.current_position_in_queue()
|
||||
return datetime.now() + estimated_time_left
|
||||
return MapRenderingJob.objects.filter(status=0).filter(queue=self.queue).filter(id__lte=self.id).count()
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('map-by-id', args=[self.id])
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
data-html="true"
|
||||
data-original-title="{% trans "Platform status" %}"
|
||||
data-placement="bottom"
|
||||
data-content='<p>{% trans "Rendering daemon: " %}<i class="pull-right fas fa-{% if daemon_running %}check{% else %}times{% endif %}"></i></p>
|
||||
<p>{% trans "GIS database: " %}<i class="pull-right fas fa-{% if gis_lag_ok %}check{% else %}{% if gis_lastupdate %}warning{% else %}times{% endif %}{% endif %}"></i></p>
|
||||
<p>{% trans "WayMarked database: " %}<i class="pull-right fas fa-{% if waymarked_lag_ok %}check{% else %}{% if waymarked_lastupdate %}warning{% else %}times{% endif %}{% endif %}"></i></p>'
|
||||
data-content='<p class="text-{{queues_overall_state}}">{% trans "Rendering queue(s): " %}<i class="pull-right fas fa-{{queues_overall_symbol}}"></i></p>
|
||||
<p class="text-{% if gis_lag_ok %}success{% else %}{% if gis_lastupdate %}warning{% else %}danger{% endif %}{% endif %}">{% trans "GIS database: " %}<i class="pull-right fas fa-{% if gis_lag_ok %}check{% else %}{% if gis_lastupdate %}hourglass-half{% else %}times{% endif %}{% endif %}"></i></p>
|
||||
<p class="text-{% if waymarked_lag_ok %}success{% else %}{% if waymarked_lastupdate %}warning{% else %}danger{% endif %}{% endif %}">{% trans "WayMarked database: " %}<i class="pull-right fas fa-{% if waymarked_lag_ok %}check{% else %}{% if waymarked_lastupdate %}hourglass-half{% else %}times{% endif %}{% endif %}"></i></p>'
|
||||
class="navbar-brand popovered" href="#"><i class="fas fa-{{ platform_status }}"></i> {{BRAND_NAME}}</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar-collapse" aria-expanded="false" aria-label="{% trans "Toggle navigation" %}">
|
||||
|
@ -22,63 +22,63 @@
|
|||
|
||||
<div id="navbar" class="navbar-collapse collapse justify-content-end">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item {% block menu-home %}{% endblock %}"><a class="nav-link" href="{% url "main" %}"><i class="fas fa-home"></i> {% trans "Home" %}</a></li>
|
||||
<li class="nav-item {% block menu-new %}{% endblock %}"><a class="nav-link" href="{% url "new" %}"><i class="fas fa-edit"></i> {% trans "Create map" %}</a></li>
|
||||
<li class="nav-item {% block menu-maps %}{% endblock %}"><a class="nav-link" href="{% url "maps" %}"><i class="fas fa-list"></i> {% trans "Maps" %}</a></li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button"><i class="fas fa-comment"></i> {% trans "About" %} <b class="caret"></b></a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="{% url "about" %}"><i class="fas fa-comment"></i> {% trans "About Maposmatic" %}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url "documentation_user_guide" %}"><i class="fas fa-book"></i> {% trans "User Guide" %}</a>
|
||||
<a class="dropdown-item" href="{% url "documentation_api" %}"><i class="fas fa-book"></i> {% trans "API Docs" %}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="https://github.com/hholzgra/maposmatic/" target="_blank"><i class="fab fa-lg fa-git-square"></i> MapOSMatic project</a>
|
||||
<a class="dropdown-item" href="https://github.com/hholzgra/ocitysmap/" target="_blank"><i class="fab fa-lg fa-git-square"></i> OCitysMap project</a>
|
||||
<a class="dropdown-item" href="https://github.com/hholzgra/maposmatic-vagrant/" target="_blank"><i class="fab fa-lg fa-git-square"></i> MapOSMatic Vagrant Box</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url "rss-feed" %}"><i class="fas fa-rss-square"></i> {% trans "Maps feed" %}</a>
|
||||
<a class="dropdown-item" href="{% url "error-feed" %}"><i class="fas fa-rss-square"></i> {% trans "Errors feed" %}</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item {% block menu-home %}{% endblock %}"><a class="nav-link" href="{% url "main" %}"><i class="fas fa-home"></i> {% trans "Home" %}</a></li>
|
||||
<li class="nav-item {% block menu-new %}{% endblock %}"><a class="nav-link" href="{% url "new" %}"><i class="fas fa-edit"></i> {% trans "Create map" %}</a></li>
|
||||
<li class="nav-item {% block menu-maps %}{% endblock %}"><a class="nav-link" href="{% url "maps" %}"><i class="fas fa-list"></i> {% trans "Maps" %}</a></li>
|
||||
|
||||
{% if PAYPAL_ID %}
|
||||
<li class="nav-item {% block menu-donate %}{% endblock %}"><a class="nav-item" href="{% url "donate" %}"><i class="fas fa-gift"></i> {% trans "Donate" %}</a></li>
|
||||
{% endif %}
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<li class="nav-item dropdown">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button"><i class="fas fa-comment"></i> {% trans "About" %} <b class="caret"></b></a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="{% url "about" %}"><i class="fas fa-comment"></i> {% trans "About Maposmatic" %}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url "documentation_user_guide" %}"><i class="fas fa-book"></i> {% trans "User Guide" %}</a>
|
||||
<a class="dropdown-item" href="{% url "documentation_api" %}"><i class="fas fa-book"></i> {% trans "API Docs" %}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="https://github.com/hholzgra/maposmatic/" target="_blank"><i class="fab fa-lg fa-git-square"></i> MapOSMatic project</a>
|
||||
<a class="dropdown-item" href="https://github.com/hholzgra/ocitysmap/" target="_blank"><i class="fab fa-lg fa-git-square"></i> OCitysMap project</a>
|
||||
<a class="dropdown-item" href="https://github.com/hholzgra/maposmatic-vagrant/" target="_blank"><i class="fab fa-lg fa-git-square"></i> MapOSMatic Vagrant Box</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url "rss-feed" %}"><i class="fas fa-rss-square"></i> {% trans "Maps feed" %}</a>
|
||||
<a class="dropdown-item" href="{% url "error-feed" %}"><i class="fas fa-rss-square"></i> {% trans "Errors feed" %}</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
{% if PAYPAL_ID %}
|
||||
<li class="nav-item {% block menu-donate %}{% endblock %}"><a class="nav-item" href="{% url "donate" %}"><i class="fas fa-gift"></i> {% trans "Donate" %}</a></li>
|
||||
{% endif %}
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="{{LANGUAGE_CODE|language_flag}}"> </span> {{ LANGUAGES|getitem:LANGUAGE_CODE }} <b class="caret"></b>
|
||||
</a>
|
||||
<div class="dropdown-menu bg-light">
|
||||
<form action="/i18n/setlang/" method="post" name="langsel" class="form-inline form-horizontal">
|
||||
<input name="next" type="hidden" value="{{ request.path }}" />
|
||||
<input name="next" type="hidden" value="{{ request.path }}" />
|
||||
<input name="language" type="hidden" value="{{ LANGUAGE_CODE }}" />
|
||||
{% for language in LANGUAGES_LIST %}
|
||||
<a class="dropdown-item" href="javascript:(function() { document.langsel.language.value = '{{ language.0 }}'; document.langsel.submit(); })();"><span class="{{language.0|language_flag}}"> </span> {{ language.1 }}</a>
|
||||
{% endfor %}
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
</li>
|
||||
|
||||
{% if WEBLATE_BASE_URL %}
|
||||
{% if LANGUAGE_CODE != "en" %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" target=_blank" href="{{ WEBLATE_BASE_URL }}engage/maposmatic/?utm_source=widget">
|
||||
<img src="{{ WEBLATE_BASE_URL }}widgets/maposmatic/{{ LANGUAGE_CODE }}/svg-badge.svg" alt="Translation status" />
|
||||
</a>
|
||||
</li>
|
||||
{% if WEBLATE_BASE_URL %}
|
||||
{% if LANGUAGE_CODE != "en" %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" target=_blank" href="{{ WEBLATE_BASE_URL }}engage/maposmatic/?utm_source=widget">
|
||||
<img src="{{ WEBLATE_BASE_URL }}widgets/maposmatic/{{ LANGUAGE_CODE }}/svg-badge.svg" alt="Translation status" />
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
|
||||
<form action="{% url "maps" %}" method="get" class="form-inline">
|
||||
<div class="md-form">
|
||||
<i class="fas fa-search"></i>
|
||||
{{ searchform.query }}
|
||||
</div>
|
||||
<div class="md-form">
|
||||
<i class="fas fa-search"></i>
|
||||
{{ searchform.query }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -49,6 +49,17 @@
|
|||
<script src="/media/node_modules/bootstrap/dist/js/bootstrap.js"></script>
|
||||
<link rel="stylesheet" href="/media/node_modules/bootstrap/dist/css/bootstrap.css" />
|
||||
|
||||
<!--
|
||||
<link rel="stylesheet" href="/media/node_modules/mdbootstrap/css/bootstrap.css">
|
||||
<link rel="stylesheet" href="/media/node_modules/mdbootstrap/css/mdb.min.css">
|
||||
<link rel="stylesheet" href="/media/node_modules/mdbootstrap/css/style.css">
|
||||
|
||||
<script type="text/javascript" src="/media/node_modules/mdbootstrap/js/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/media/node_modules/mdbootstrap/js/popper.min.js"></script>
|
||||
<script type="text/javascript" src="/media/node_modules/mdbootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="/media/node_modules/mdbootstrap/js/mdb.min.js"></script>
|
||||
-->
|
||||
|
||||
<script src="/media/node_modules/leaflet/dist/leaflet.js"></script>
|
||||
<link rel="stylesheet" href="/media/node_modules/leaflet/dist/leaflet.css" />
|
||||
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
{% extends "maposmatic/base.html" %}
|
||||
|
||||
{% comment %}
|
||||
coding: utf-8
|
||||
|
||||
maposmatic, the web front-end of the MapOSMatic city map generation system
|
||||
Copyright (C) 2022 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/>.
|
||||
{% endcomment %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load extratags %}
|
||||
|
||||
{% block title %}{% trans "Congo Health Map" %}{% endblock %}
|
||||
|
||||
{% block page %}
|
||||
|
||||
<div class="treeview w-20 border">
|
||||
<h6 class="pt-3 pl-3">Folders</h6>
|
||||
<hr>
|
||||
<ul class="mb-1 pl-3 pb-2">
|
||||
<li><i class="fas fa-angle-right rotate"></i>
|
||||
<span><i class="far fa-envelope-open ic-w mx-1"></i>Mail</span>
|
||||
<ul class="nested">
|
||||
<li><i class="far fa-bell ic-w mr-1"></i>Offers</li>
|
||||
<li><i class="far fa-address-book ic-w mr-1"></i>Contacts</li>
|
||||
<li><i class="fas fa-angle-right rotate"></i>
|
||||
<span><i class="far fa-calendar-alt ic-w mx-1"></i>Calendar</span>
|
||||
<ul class="nested">
|
||||
<li><i class="far fa-clock ic-w mr-1"></i>Deadlines</li>
|
||||
<li><i class="fas fa-users ic-w mr-1"></i>Meetings</li>
|
||||
<li><i class="fas fa-basketball-ball ic-w mr-1"></i>Workouts</li>
|
||||
<li><i class="fas fa-mug-hot ic-w mr-1"></i>Events</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="fas fa-angle-right rotate"></i>
|
||||
<span><i class="far fa-folder-open ic-w mx-1"></i>Inbox</span>
|
||||
<ul class="nested">
|
||||
<li><i class="far fa-folder-open ic-w mr-1"></i>Admin</li>
|
||||
<li><i class="far fa-folder-open ic-w mr-1"></i>Corporate</li>
|
||||
<li><i class="far fa-folder-open ic-w mr-1"></i>Finance</li>
|
||||
<li><i class="far fa-folder-open ic-w mr-1"></i>Other</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="fas fa-angle-right rotate"></i>
|
||||
<span><i class="far fa-gem ic-w mx-1"></i>Favourites</span>
|
||||
<ul class="nested">
|
||||
<li><i class="fas fa-pepper-hot ic-w mr-1"></i>Restaurants</li>
|
||||
<li><i class="far fa-eye ic-w mr-1"></i>Places</li>
|
||||
<li><i class="fas fa-gamepad ic-w mr-1"></i>Games</li>
|
||||
<li><i class="fas fa-cocktail ic-w mr-1"></i>Coctails</li>
|
||||
<li><i class="fas fa-pizza-slice ic-w mr-1"></i>Food</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="far fa-comment ic-w mr-1"></i>Notes</li>
|
||||
<li><i class="fas fa-cogs ic-w mr-1"></i>Settings</li>
|
||||
<li><i class="fas fa-desktop ic-w mr-1"></i>Devices</li>
|
||||
<li><i class="fas fa-trash-alt ic-w mr-1"></i>Deleted Items</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div class="treeview w-20 border">
|
||||
<h6 class="pt-3 pl-3">foobar</h6><hr/>
|
||||
<ul class="mb-1 pl-3 pb-2">
|
||||
<li>foo
|
||||
<ul class="nested">
|
||||
<li>foo1</li>
|
||||
<li>foo2</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>bar
|
||||
<ul class="nested">
|
||||
<li>bar1</li>
|
||||
<li>bar2</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
-->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajs %}
|
||||
$(document).ready(function() {
|
||||
$('.treeview').mdbTreeview();
|
||||
});
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Heatmap</title>
|
||||
<script src="/media/node_modules/leaflet/dist/leaflet.js"></script>
|
||||
<link rel="stylesheet" href="/media/node_modules/leaflet/dist/leaflet.css" />
|
||||
|
||||
<script src="/media/node_modules/heatmap.js/build/heatmap.min.js"></script>
|
||||
<script src="/media/node_modules/leaflet-heatmap/leaflet-heatmap.js"></script>
|
||||
|
||||
<script src="/apis/heatdata/{{ days }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Heatmap test 2x</h1>
|
||||
<div class="demo-wrapper">
|
||||
<div class="heatmap" id="map-canvas" style="height: 500px;">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
var baseLayer = L.tileLayer(
|
||||
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://cloudmade.com">CloudMade</a>',
|
||||
maxZoom: 18
|
||||
}
|
||||
);
|
||||
|
||||
var cfg = {
|
||||
// radius should be small ONLY if scaleRadius is true (or small radius is intended)
|
||||
"radius": 10,
|
||||
"maxOpacity": .8,
|
||||
// scales the radius based on map zoom
|
||||
"scaleRadius": false,
|
||||
// if set to false the heatmap uses the global maximum for colorization
|
||||
// if activated: uses the data maximum within the current map boundaries
|
||||
// (there will always be a red spot with useLocalExtremas true)
|
||||
"useLocalExtrema": true,
|
||||
// which field name in your data represents the latitude - default "lat"
|
||||
latField: 'lat',
|
||||
// which field name in your data represents the longitude - default "lng"
|
||||
lngField: 'lng',
|
||||
// which field name in your data represents the data value - default "value"
|
||||
valueField: 'count'
|
||||
};
|
||||
|
||||
|
||||
var heatmapLayer = new HeatmapOverlay(cfg);
|
||||
|
||||
var map = new L.Map('map-canvas', {
|
||||
center: new L.LatLng(20,0),
|
||||
zoom: 2,
|
||||
layers: [baseLayer, heatmapLayer]
|
||||
});
|
||||
|
||||
heatmapLayer.setData(data);
|
||||
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,3 +1,7 @@
|
|||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load extratags %}
|
||||
|
||||
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
|
||||
<!-- Indicators -->
|
||||
<ol class="carousel-indicators">
|
||||
|
@ -9,21 +13,30 @@
|
|||
<!-- Wrapper for slides -->
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<img src="/media/img/preview-1.png" width="100%" alt="plain layout">
|
||||
<img
|
||||
src="/media/img/layout/plain.png"
|
||||
srcset="/media/img/layout/plain.png, /media/img/layout/plain-1.5x.png 1.5x, /media/img/layout/plain-2x.png 2x"
|
||||
width="100%" alt="{% trans "Plain Layout" %}">
|
||||
<div class="carousel-caption">
|
||||
<h3>Plain Layout</h3>
|
||||
<h3>{% trans "Plain Layout" %}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/media/img/preview-2.png" width="100%" alt="side index layout">
|
||||
<img
|
||||
src="/media/img/layout/single_page_index_side.png"
|
||||
srcset="/media/img/layout/single_page_index_side.png, /media/img/layout/single_page_index_side-1.5x.png 1.5x, /media/img/layout/single_page_index_side-2x.png 2x"
|
||||
width="100%" alt="{% trans "Index Layout" %}">
|
||||
<div class="carousel-caption">
|
||||
<h3>Side Index Layout</h3>
|
||||
<h3>{% trans "Index Layout" %}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img src="/media/img/preview-3.png" width="100%" alt="multi page layout">
|
||||
<img
|
||||
src="/media/img/layout/multi_page.png"
|
||||
srcset="/media/img/layout/multi_page.png, /media/img/layout/multi_page-1.5x.png 1.5x, /media/img/layout/multi_page-2x.png 2x"
|
||||
width="100%" alt="{% trans "Multi Page Layout" %}">
|
||||
<div class="carousel-caption">
|
||||
<h3>Multi Page Layout</h3>
|
||||
<h3>{% trans "Multi Page Layout" %}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,11 +44,11 @@
|
|||
<!-- Controls -->
|
||||
<a class="carousel-control-prev" href="#carousel-example-generic" role="button" data-slide="prev">
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||
<span class="sr-only">Previous</span>
|
||||
<span class="sr-only">{% trans "Previous" %}</span>
|
||||
</a>
|
||||
<a class="carousel-control-next" href="#carousel-example-generic" role="button" data-slide="next">
|
||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||
<span class="sr-only">Next</span>
|
||||
<span class="sr-only">{% trans "Next" %}</span>
|
||||
</a>
|
||||
|
||||
</div> <!-- Carousel -->
|
||||
|
|
|
@ -5,44 +5,43 @@
|
|||
<div class="alert alert-info">
|
||||
<h2>{% trans "Platform status" %}</h2>
|
||||
|
||||
{% if queued %}
|
||||
<p class="queue">
|
||||
{% blocktrans with queued|pluralize as qp %}{{ queued }} job{{ qp }} in the rendering queue.{% endblocktrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
{% if daemon_running and gis_lag_ok and waymarked_lag_ok%}
|
||||
{% blocktrans with gis_lastupdate|timesince:utc_now as date %}All systems are operational.{% endblocktrans %}
|
||||
{% else %}
|
||||
{% if daemon_running and gis_lastupdate %}
|
||||
{% blocktrans %}Systems are operational but renderings may not reflect the latest available OpenStreetMap data.{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if daemon_running %}
|
||||
<div class="alert alert-success">
|
||||
<i class="fas fa-check"></i> {% blocktrans %}The rendering daemon is running.{% endblocktrans %}
|
||||
<div class="alert alert-{{queues_overall_state}}">
|
||||
<h5>Render queue states:</h5>
|
||||
<ul class="list-group">
|
||||
{% for key, value in queue_states.items %}
|
||||
<li class="list-group-item
|
||||
list-group-item-{{value.running|yesno:"success,danger,warning"}}
|
||||
d-flex justify-content-between align-items-center"
|
||||
>{{key}}
|
||||
<span
|
||||
class="badge badge-pill
|
||||
badge-{{value.running|yesno:"success,danger,warning"}}"
|
||||
title="{% blocktrans with size=value.size qp=value.size|pluralize %} {{size}} job{{ qp }} in the rendering queue.{% endblocktrans %}">
|
||||
{% if value.size > 0 %}
|
||||
{{value.size}}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-danger">
|
||||
<i class="fas fa-times"></i> {% blocktrans %}The rendering daemon is not running: jobs will be queued until the rendering daemon is back up.{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if gis_lag_ok %}
|
||||
<div class="alert alert-success">
|
||||
<i class="fas fa-check"></i> {% blocktrans with gis_lastupdate|timesince:utc_now as date %}The GIS database is online and up to date, <span class="tooltipped" data-original-title="{{ gis_lastupdate }}">updated {{ date }} ago</span>.{% endblocktrans %}
|
||||
<i class="fas fa-check"></i> {% blocktrans with gis_lastupdate|timesince:utc_now as date %}The GIS database is online and up to date, <span class="tooltipped" data-original-title="{{ gis_lastupdate }}">updated {{ date }} ago</span>.{% endblocktrans %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% if gis_lastupdate %}
|
||||
<div class="alert alert-warning">
|
||||
<i class="fas fa-warning"></i>
|
||||
{% blocktrans with gis_lastupdate|timesince:utc_now as date %}The GIS database is not up to date and was only <span class="tooltipped" data-original-title="{{ gis_lastupdate }}">updated {{ date }} ago</span>.{% endblocktrans %}
|
||||
<i class="fas fa-warning"></i>
|
||||
{% blocktrans with gis_lastupdate|timesince:utc_now as date %}The GIS database is not up to date and was only <span class="tooltipped" data-original-title="{{ gis_lastupdate }}">updated {{ date }} ago</span>.{% endblocktrans %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-danger">
|
||||
<i class="fas fa-times"></i> {% blocktrans %}The GIS database is not available. Renderings cannot be processed at this time.{% endblocktrans %}
|
||||
<i class="fas fa-times"></i> {% blocktrans %}The GIS database is not available. Renderings cannot be processed at this time.{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
<tr><td><strong>{% trans "Overlays" %}</strong></td>
|
||||
<td>{{ obj.overlay|add_blank_after_comma }}</td></tr>
|
||||
{% endif %}
|
||||
{% if obj.indexer %}
|
||||
<tr><td><strong>{% trans "Indexer" %}</strong></td>
|
||||
<td>{{ obj.indexer }}</td></tr>
|
||||
{% endif %}
|
||||
{% if obj.track %}
|
||||
<tr><td><strong>{% trans "GPX Track" %}</strong></td>
|
||||
<td>{{ obj.track|file_basename }}</td></tr>
|
||||
|
|
|
@ -40,10 +40,11 @@
|
|||
<div style="height: 2em"></div>
|
||||
|
||||
{% if map.needs_waiting %}
|
||||
<div id="queue-progress" class="progress progress-striped active">
|
||||
<div class="bar" style="width: {{ progress }}%; text-align: right; padding-right: 10px;">
|
||||
{{ map.current_position_in_queue }} / {{ queue_size }}
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="queue-progress" class="progress-bar progress-bar-striped progress-bar-animated"" role="progressbar"
|
||||
style="width: {{ progress }}%" aria-valuenow="{{ progress }}" aria-valuemin="0" aria-valuemax="100">
|
||||
<span class="text-dark font-weight-bold">{{ map.current_position_in_queue }} {% trans "jobs ahead of us" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -85,6 +85,10 @@
|
|||
<tr><td><strong>{% trans "Overlays" %}</strong></td>
|
||||
<td>{{ map.overlay|add_blank_after_comma }}</td></tr>
|
||||
{% endif %}
|
||||
{% if map.indexer %}
|
||||
<tr><td><strong>{% trans "Indexer" %}</strong></td>
|
||||
<td>{{ map.indexer }}</td></tr>
|
||||
{% endif %}
|
||||
{% if map.track %}
|
||||
<tr><td><strong>{% trans "GPX Track" %}</strong></td>
|
||||
<td>{{ map.track|file_basename }}</td></tr>
|
||||
|
|
|
@ -76,6 +76,9 @@
|
|||
{% if map.overlay %}
|
||||
<tr><td><strong>{% trans "Overlay(s)" %}</strong></td><td>{{ map.overlay|add_blank_after_comma }}</td></tr>
|
||||
{% endif %}
|
||||
{% if map.indexer %}
|
||||
<tr><td><strong>{% trans "Indexer" %}</strong></td><td>{{ map.indexer }}</td></tr>
|
||||
{% endif %}
|
||||
{% if map.track %}
|
||||
<tr><td><strong>{% trans "GPX track" %}</strong></td><td>{{ map.track|file_basename }}</td></tr>
|
||||
{% endif %}
|
||||
|
@ -125,6 +128,7 @@
|
|||
{% endif %}
|
||||
{% if map.needs_waiting and map.current_position_in_queue %}
|
||||
<p class="queue-position">#{{ map.current_position_in_queue }}</p>
|
||||
<p class="queue-name">{% trans "in queue:" %} {{ map.queue }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -247,9 +247,16 @@ $('#error-modal').modal('show')
|
|||
<legend>{% trans "Layout" %}</legend>
|
||||
{{ form.layout }}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Indexer" %}</legend>
|
||||
{{ form.indexer }}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<img id="layout-preview" align="right" src="/media/img/layout/{{request.session.new_layout}}.png"/>
|
||||
<img id="layout-preview" align="right"
|
||||
src="/media/img/layout/{{request.session.new_layout}}.png"
|
||||
srcset="/media/img/layout/{{request.session.new_layout}}.png, /media/img/layout/{{request.session.new_layout}}-1.5x.png 1.5x, /media/img/layout/{{request.session.new_layout}}-2x.png 2x"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -30,3 +30,9 @@ function metric_dist(lat1, lon1, lat2, lon2)
|
|||
return Math.acos(dist) * 10000 / 90;
|
||||
}
|
||||
|
||||
function load_preview(id, base)
|
||||
{
|
||||
var base2 = "/media/img/layout/" + base;
|
||||
$(id).attr("src", base2 + ".png");
|
||||
$(id).attr("srcset", base2 + ".png, " + base2 + "-1.5x.png 1.5x, " + base2 + "-2x.png 2x");
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ function choose_paper_buttons(layout)
|
|||
$('#multi_page_sizes').hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var best_fit_width = 0;
|
||||
|
@ -34,7 +34,7 @@ function preparePaperSize() {
|
|||
$('#nextlink').show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$('#paper-wait').show();
|
||||
$('#paper-size').hide();
|
||||
$('#paper-size-loading-error').hide();
|
||||
|
@ -56,6 +56,15 @@ function preparePaperSize() {
|
|||
}
|
||||
|
||||
args['layout'] = $('input[name=layout]:checked').val();
|
||||
if (!args['layout']) {
|
||||
args['layout'] = $('#id_layout :selected').val();
|
||||
}
|
||||
|
||||
args['indexer'] = $('input[name=indexer]:checked').val();
|
||||
if (!args['indexer']) {
|
||||
args['indexer'] = $('#id_indexer :selected').val();
|
||||
}
|
||||
|
||||
args['stylesheet'] = $('input[name=stylesheet]:checked').val();
|
||||
if (!args['stylesheet']) {
|
||||
args['stylesheet'] = $('#id_stylesheet :selected').val();
|
||||
|
@ -77,7 +86,7 @@ function preparePaperSize() {
|
|||
|
||||
disable_all_papersizes();
|
||||
choose_paper_buttons(args['layout']);
|
||||
|
||||
|
||||
for (i in data) {
|
||||
var w = data[i]['width'];
|
||||
var h = data[i]['height'];
|
||||
|
@ -89,8 +98,8 @@ function preparePaperSize() {
|
|||
|
||||
best_fit_width = parseInt(w);
|
||||
best_fit_height = parseInt(h);
|
||||
best_fit_scale = parseInt( data[i][(data[i]['portrait_ok']) ? 'portrait_scale' : 'landscape_scale']);
|
||||
|
||||
best_fit_scale = parseInt( data[i][(data[i]['portrait_ok']) ? 'portrait_scale' : 'landscape_scale']);
|
||||
|
||||
$("#best_width").text(w);
|
||||
$("#best_height").text(h);
|
||||
|
||||
|
@ -323,15 +332,15 @@ function show_paper_preview(canvas_name, w, h, scale)
|
|||
|
||||
// show actual selected area
|
||||
ctx.fillStyle = "#DEDEFF";
|
||||
if (scale) { // only set on single page formats
|
||||
if (scale) { // only set on single page formats
|
||||
var canvas_aspect = tw / th;
|
||||
var selection_aspect = best_fit_width / best_fit_height;
|
||||
|
||||
|
||||
var aw = tw;
|
||||
var ah = th;
|
||||
var oh = 0;
|
||||
var ow = 0;
|
||||
|
||||
|
||||
if (selection_aspect > canvas_aspect) {
|
||||
ah = ah * canvas_aspect / selection_aspect;
|
||||
oh = (th - ah) / 2;
|
||||
|
@ -339,12 +348,12 @@ function show_paper_preview(canvas_name, w, h, scale)
|
|||
aw = aw * selection_aspect / canvas_aspect;
|
||||
ow = (tw - aw) / 2;
|
||||
}
|
||||
|
||||
|
||||
ctx.fillRect(dw + ow, dh + oh, aw, ah);
|
||||
} else {
|
||||
ctx.fillRect(dw, dh, tw, th);
|
||||
}
|
||||
|
||||
|
||||
// dashed paper diagonals
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = "#000000";
|
||||
|
@ -364,7 +373,7 @@ function show_paper_preview(canvas_name, w, h, scale)
|
|||
ctx.fillText('ca. 1:' + scale, dw+tw/2, dh+th/4);
|
||||
ctx.fillText('zoom '+ scaleDenominator2zoom(scale), dw+tw/2, dh+3*th/4);
|
||||
}
|
||||
|
||||
|
||||
// the actual paper size rectangle frame
|
||||
ctx.strokeStyle = "#000000";
|
||||
ctx.setLineDash([]);
|
||||
|
@ -376,13 +385,13 @@ function show_paper_preview(canvas_name, w, h, scale)
|
|||
function enable_button(buttons, txt)
|
||||
{
|
||||
for (button of buttons)
|
||||
{
|
||||
{
|
||||
button.classList.remove("btn-success");
|
||||
button.classList.remove("btn-outline-secondary");
|
||||
button.classList.add("btn-primary");
|
||||
|
||||
|
||||
button.removeAttribute("disabled");
|
||||
|
||||
|
||||
button.setAttribute("title", txt);
|
||||
}
|
||||
}
|
||||
|
@ -390,11 +399,11 @@ function enable_button(buttons, txt)
|
|||
function disable_button(buttons)
|
||||
{
|
||||
for (button of buttons)
|
||||
{
|
||||
{
|
||||
button.classList.remove("btn-primary");
|
||||
button.classList.remove("btn-success");
|
||||
button.classList.add("btn-outline-secondary");
|
||||
|
||||
|
||||
button.setAttribute("disabled", "");
|
||||
|
||||
button.setAttribute("title", "");
|
||||
|
@ -404,7 +413,7 @@ function disable_button(buttons)
|
|||
function mark_button(buttons)
|
||||
{
|
||||
for (button of buttons)
|
||||
{
|
||||
{
|
||||
button.classList.remove("btn-primary");
|
||||
button.classList.add("btn-success");
|
||||
}
|
||||
|
@ -413,7 +422,7 @@ function mark_button(buttons)
|
|||
function unmark_button(buttons)
|
||||
{
|
||||
for (button of buttons)
|
||||
{
|
||||
{
|
||||
button.classList.remove("btn-success");
|
||||
button.classList.add("btn-primary");
|
||||
}
|
||||
|
|
|
@ -79,9 +79,7 @@ def about(request):
|
|||
|
||||
return render(request,
|
||||
'maposmatic/about.html',
|
||||
{ 'form': form,
|
||||
'queued': job_list.count()
|
||||
}
|
||||
{ }
|
||||
)
|
||||
|
||||
def privacy(request):
|
||||
|
@ -91,6 +89,13 @@ def privacy(request):
|
|||
{ }
|
||||
)
|
||||
|
||||
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,
|
||||
|
@ -117,9 +122,7 @@ def donate(request):
|
|||
|
||||
return render(request,
|
||||
'maposmatic/donate.html',
|
||||
{ 'form': form,
|
||||
'queued': job_list.count()
|
||||
}
|
||||
{ }
|
||||
)
|
||||
|
||||
def donate_thanks(request):
|
||||
|
@ -146,6 +149,7 @@ def new(request):
|
|||
form = forms.MapRenderingJobForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
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')
|
||||
|
@ -156,6 +160,9 @@ def new(request):
|
|||
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
|
||||
|
@ -167,7 +174,7 @@ def new(request):
|
|||
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())
|
||||
.queue_size(job.queue) + 1)
|
||||
job.nonce = helpers.generate_nonce(models.MapRenderingJob.NONCE_SIZE)
|
||||
|
||||
job.save()
|
||||
|
@ -193,6 +200,11 @@ def new(request):
|
|||
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:
|
||||
|
@ -252,11 +264,11 @@ def map_full(request, id, nonce=None):
|
|||
isredirected = request.session.get('redirected', False)
|
||||
request.session.pop('redirected', None)
|
||||
|
||||
queue_size = models.MapRenderingJob.objects.queue_size()
|
||||
queue_size = job.index_queue_at_submission
|
||||
progress = 100
|
||||
if queue_size:
|
||||
progress = 20 + int(80 * (queue_size -
|
||||
job.current_position_in_queue()) / float(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 \
|
||||
|
@ -326,9 +338,15 @@ def recreate(request):
|
|||
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.layout = job.layout
|
||||
|
||||
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
|
||||
|
||||
|
@ -340,7 +358,7 @@ def recreate(request):
|
|||
newjob.submittermail = None # TODO
|
||||
newjob.map_language = job.map_language
|
||||
newjob.index_queue_at_submission = (models.MapRenderingJob.objects
|
||||
.queue_size())
|
||||
.queue_size() + 1)
|
||||
newjob.nonce = helpers.generate_nonce(models.MapRenderingJob.NONCE_SIZE)
|
||||
|
||||
newjob.save()
|
||||
|
@ -392,6 +410,12 @@ def api_nominatim(request):
|
|||
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)
|
||||
|
@ -635,11 +659,11 @@ def api_rendering_status(request, id, nonce=None):
|
|||
isredirected = request.session.get('redirected', False)
|
||||
request.session.pop('redirected', None)
|
||||
|
||||
queue_size = models.MapRenderingJob.objects.queue_size()
|
||||
queue_size = job.index_queue_at_submission
|
||||
progress = 100
|
||||
if queue_size:
|
||||
progress = 20 + int(80 * (queue_size -
|
||||
job.current_position_in_queue()) / float(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 \
|
||||
|
|
|
@ -319,8 +319,17 @@ MAP_LANGUAGES_LIST.append(("C", _(u"No localization")))
|
|||
REFRESH_JOB_WAITING = 15
|
||||
REFRESH_JOB_RENDERING = 10
|
||||
|
||||
def is_daemon_running():
|
||||
return 0 == os.system('systemctl is-active maposmatic-render.service')
|
||||
QUEUE_NAMES = ['default', 'api', 'multipage']
|
||||
|
||||
# We are having this check in the settings file as it is somewhat
|
||||
# platform specific. The below implementation assumes that the
|
||||
# renderer process(es) are running as systemD services which
|
||||
# should be a sensible default these days.
|
||||
def is_daemon_running(queue_name=None):
|
||||
name = ''
|
||||
if queue_name is not None:
|
||||
name = "@" + queue_name
|
||||
return 0 == os.system('systemctl is-active maposmatic-render%s.service' % name)
|
||||
|
||||
# Logging
|
||||
logconfig.setup_maposmatic_logging(
|
||||
|
|
|
@ -319,9 +319,20 @@ a.carousel-control { display: none; }
|
|||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.queue-position { position: absolute;
|
||||
top: -15px; right: 0; color: #eee; text-align: right;
|
||||
font-weight: bold; line-height: 100pt; font-size: 100pt;
|
||||
letter-spacing: -2px; vertical-align: top; z-index: 999;
|
||||
.queue-position {
|
||||
color: #eee;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 60pt;
|
||||
letter-spacing: -2px;
|
||||
align: center;
|
||||
}
|
||||
|
||||
.queue-name {
|
||||
color: #7f7f7f;
|
||||
text-align: center;
|
||||
font-size: 16pt;
|
||||
letter-spacing: -2px;
|
||||
align: center;
|
||||
}
|
||||
|
||||
|
|
Po Szerokość: | Wysokość: | Rozmiar: 406 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 698 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 91 KiB Po Szerokość: | Wysokość: | Rozmiar: 188 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 724 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 1.2 MiB |
Przed Szerokość: | Wysokość: | Rozmiar: 47 KiB Po Szerokość: | Wysokość: | Rozmiar: 341 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 724 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 1.2 MiB |
Przed Szerokość: | Wysokość: | Rozmiar: 44 KiB Po Szerokość: | Wysokość: | Rozmiar: 341 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 639 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 1.0 MiB |
Przed Szerokość: | Wysokość: | Rozmiar: 43 KiB Po Szerokość: | Wysokość: | Rozmiar: 299 KiB |
|
@ -0,0 +1,2 @@
|
|||
*.jpg
|
||||
*.png
|
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 53 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 59 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 16 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 57 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 72 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 51 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 30 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 51 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 94 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 78 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 140 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 60 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 54 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 35 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 75 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 54 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 66 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 63 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 66 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 58 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 53 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 67 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 65 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 52 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 49 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 48 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 51 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 49 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 36 KiB |
|
@ -0,0 +1,2 @@
|
|||
*.jpg
|
||||
*.png
|
Przed Szerokość: | Wysokość: | Rozmiar: 75 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 156 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 47 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 49 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 106 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 71 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 157 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 158 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 51 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 82 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 20 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 77 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 77 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 79 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 72 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 78 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 77 KiB |