umap/umap/views.py

248 lines
8 KiB
Python
Raw Normal View History

import simplejson
2014-04-19 04:48:54 -05:00
import mimetypes
import urllib2
2014-04-19 10:54:51 -05:00
import socket
from urlparse import urlparse
2012-11-20 03:47:19 -06:00
from django.views.generic import TemplateView
2014-06-19 07:39:45 -05:00
from django.contrib.auth import get_user_model
from django.views.generic import DetailView, View
2012-12-16 08:10:00 -06:00
from django.db.models import Q
from django.contrib.gis.measure import D
from django.conf import settings
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
2014-04-19 05:28:24 -05:00
from django.http import HttpResponse, HttpResponseBadRequest
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from django.db.models.sql.where import ExtraWhere, OR
from pgindex import search as pg_search
2012-11-20 03:47:19 -06:00
from leaflet_storage.models import Map
from leaflet_storage.forms import DEFAULT_CENTER
2012-11-20 03:47:19 -06:00
2014-06-19 07:39:45 -05:00
User = get_user_model()
2012-11-20 03:47:19 -06:00
class PaginatorMixin(object):
per_page = 5
def paginate(self, qs):
paginator = Paginator(qs, self.per_page)
page = self.request.GET.get('p')
try:
qs = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
qs = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
qs = paginator.page(paginator.num_pages)
return qs
class Home(TemplateView, PaginatorMixin):
2013-01-02 08:49:20 -06:00
template_name = "umap/home.html"
list_template_name = "leaflet_storage/map_list.html"
2012-11-20 03:47:19 -06:00
def get_context_data(self, **kwargs):
qs = Map.public
if not 'spatialite' in settings.DATABASES['default']['ENGINE']:
# Unsupported query type for sqlite.
qs = qs.filter(center__distance_gt=(DEFAULT_CENTER, D(km=1)))
demo_map = None
if hasattr(settings, "UMAP_DEMO_PK"):
try:
demo_map = Map.public.get(pk=settings.UMAP_DEMO_PK)
except Map.DoesNotExist:
pass
else:
qs = qs.exclude(id=demo_map.pk)
showcase_map = None
if hasattr(settings, "UMAP_SHOWCASE_PK"):
try:
showcase_map = Map.public.get(pk=settings.UMAP_SHOWCASE_PK)
except Map.DoesNotExist:
pass
else:
qs = qs.exclude(id=showcase_map.pk)
maps = qs.order_by('-modified_at')[:50]
maps = self.paginate(maps)
2012-11-20 03:47:19 -06:00
return {
"maps": maps,
"demo_map": demo_map,
"showcase_map": showcase_map,
"DEMO_SITE": settings.UMAP_DEMO_SITE
2012-11-20 03:47:19 -06:00
}
2012-12-07 06:40:57 -06:00
def get_template_names(self):
"""
Dispatch template according to the kind of request: ajax or normal.
"""
if self.request.is_ajax():
return [self.list_template_name]
else:
return [self.template_name]
2012-11-20 03:47:19 -06:00
home = Home.as_view()
2012-12-11 13:04:03 -06:00
class About(Home):
template_name = "umap/about.html"
about = About.as_view()
class UserMaps(DetailView, PaginatorMixin):
2012-12-11 13:04:03 -06:00
model = User
slug_url_kwarg = 'username'
slug_field = 'username'
list_template_name = "leaflet_storage/map_list.html"
2012-12-11 13:04:03 -06:00
context_object_name = "current_user"
def get_context_data(self, **kwargs):
manager = Map.objects if self.request.user == self.object else Map.public
maps = manager.filter(Q(owner=self.object) | Q(editors=self.object)).distinct().order_by('-modified_at')[:50]
maps = self.paginate(maps)
2012-12-11 13:04:03 -06:00
kwargs.update({
"maps": maps
})
return super(UserMaps, self).get_context_data(**kwargs)
def get_template_names(self):
"""
Dispatch template according to the kind of request: ajax or normal.
"""
if self.request.is_ajax():
return [self.list_template_name]
else:
return super(UserMaps, self).get_template_names()
user_maps = UserMaps.as_view()
2012-12-16 08:10:00 -06:00
class Search(TemplateView, PaginatorMixin):
2013-01-02 08:49:20 -06:00
template_name = "umap/search.html"
list_template_name = "leaflet_storage/map_list.html"
2012-12-16 08:10:00 -06:00
def get_context_data(self, **kwargs):
q = self.request.GET.get('q')
results = []
if q:
results = pg_search(q)
if getattr(settings, 'UMAP_USE_UNACCENT', False):
# Add unaccent support
results.query.where.add(ExtraWhere(("ts @@ plainto_tsquery('simple', unaccent(%s))", ), [q, ]), OR)
results = results.order_by('-rank', '-start_publish')
results = self.paginate(results)
results.object_list = [Map.objects.get(pk=i.obj_pk) for i in results]
2012-12-16 08:10:00 -06:00
kwargs.update({
'maps': results,
2012-12-16 08:10:00 -06:00
'q': q
2013-05-01 06:49:24 -05:00
})
2012-12-16 08:10:00 -06:00
return kwargs
def get_template_names(self):
"""
Dispatch template according to the kind of request: ajax or normal.
"""
if self.request.is_ajax():
return [self.list_template_name]
else:
return super(Search, self).get_template_names()
search = Search.as_view()
class MapsShowCase(View):
2014-04-19 04:48:54 -05:00
def get(self, *args, **kwargs):
2014-04-20 17:02:10 -05:00
maps = Map.public.filter(center__distance_gt=(DEFAULT_CENTER, D(km=1))).order_by('-modified_at')[:2500]
def make(m):
description = m.description or ""
if m.owner:
description = u"{description}\n{by} [[{url}|{name}]]".format(
description=description,
by=_("by"),
url=reverse('user_maps', kwargs={"username": m.owner.username}),
name=m.owner,
)
description = u"{}\n[[{}|{}]]".format(description, m.get_absolute_url(), _("View the map"))
geometry = m.settings['geometry'] if "geometry" in m.settings else simplejson.loads(m.center.geojson)
return {
"type": "Feature",
"geometry": geometry,
"properties": {
"name": m.name,
"description": description
}
}
geojson = {
"type": "FeatureCollection",
"features": [make(m) for m in maps]
}
return HttpResponse(simplejson.dumps(geojson))
showcase = MapsShowCase.as_view()
2014-04-19 04:48:54 -05:00
2014-04-19 10:54:51 -05:00
from django.core.validators import URLValidator, ValidationError
def validate_url(request):
assert request.method == "GET"
assert request.is_ajax()
url = request.GET.get('url')
assert url
try:
URLValidator(url)
except ValidationError:
raise AssertionError()
assert 'HTTP_REFERER' in request.META
referer = urlparse(request.META.get('HTTP_REFERER'))
toproxy = urlparse(url)
local = urlparse(settings.SITE_URL)
assert toproxy.hostname
assert referer.hostname == local.hostname
assert toproxy.hostname != "localhost"
assert toproxy.netloc != local.netloc
2014-07-18 16:26:16 -05:00
try:
# clean this when in python 3.4
ipaddress = socket.gethostbyname(toproxy.hostname)
except:
raise AssertionError()
2014-04-19 12:44:56 -05:00
assert not ipaddress.startswith('127.')
assert not ipaddress.startswith('192.168.')
2014-04-19 10:54:51 -05:00
return url
2014-04-19 04:48:54 -05:00
class AjaxProxy(View):
def get(self, *args, **kwargs):
# You should not use this in production (use Nginx or so)
2014-04-19 10:54:51 -05:00
try:
url = validate_url(self.request)
except AssertionError:
return HttpResponseBadRequest()
2014-04-19 12:44:56 -05:00
headers = {
'User-Agent': 'uMapProxy +http://wiki.openstreetmap.org/wiki/UMap'
}
request = urllib2.Request(url, headers=headers)
opener = urllib2.build_opener()
2014-04-19 04:48:54 -05:00
try:
2014-04-19 12:44:56 -05:00
proxied_request = opener.open(request)
2014-04-19 04:48:54 -05:00
except urllib2.HTTPError as e:
return HttpResponse(e.msg, status=e.code, mimetype='text/plain')
else:
2014-04-19 12:44:56 -05:00
status_code = proxied_request.code
mimetype = proxied_request.headers.typeheader or mimetypes.guess_type(url)
content = proxied_request.read()
# Quick hack to prevent Django from adding a Vary: Cookie header
self.request.session.accessed = False
2014-04-19 04:48:54 -05:00
return HttpResponse(content, status=status_code, mimetype=mimetype)
ajax_proxy = AjaxProxy.as_view()