# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.conf import settings from django.core.urlresolvers import reverse_lazy from django.http import HttpResponse, JsonResponse from django.shortcuts import render, get_object_or_404 from django.views.generic import CreateView, DetailView, RedirectView, ListView, TemplateView from django.contrib.auth.mixins import LoginRequiredMixin from .models import Point, Panorama, ReferencePoint from .forms import SelectReferencePointForm, CustomPointForm, PanoramaForm, ReferencePointForm class CelutzLoginMixin(LoginRequiredMixin): """Mixin that acts like LoginRequiredMixin if settings.LOGIN_REQUIRED is True, and does nothing otherwise. It allows to choose whether accessing celutz requires an account or is open to anybody. """ login_url = '/admin/login/' def dispatch(self, request, *args, **kwargs): """Small hack: either call our parent (LoginRequiredMixin) or bypass it""" if settings.LOGIN_REQUIRED: return super(CelutzLoginMixin, self).dispatch(request, *args, **kwargs) else: return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs) class PanoramaUpload(CelutzLoginMixin, CreateView): model = Panorama fields = ('name', 'image', 'loop', 'latitude', 'longitude', 'altitude') template_name = "panorama/new.html" prefix = 'newpano' def get_success_url(self): return reverse_lazy("panorama:gen_tiles", kwargs={"pk": self.object.id}) class PanoramaView(CelutzLoginMixin, DetailView): model = Panorama template_name = "panorama/view.html" context_object_name = "panorama" def get_context_data(self, **kwargs): context = super(PanoramaView, self).get_context_data(**kwargs) pano = context['panorama'] context['panoramas'] = [p for p in Panorama.objects.all() if pano.great_circle_distance(p) <= settings.PANORAMA_MAX_DISTANCE] context['poi_list'] = [poi for poi in ReferencePoint.objects.all() if not hasattr(poi, 'panorama') and pano.great_circle_distance(poi) <= settings.PANORAMA_MAX_DISTANCE] return context class PanoramaGenTiles(CelutzLoginMixin, RedirectView): permanent = False pattern_name = "panorama:view_pano" def get_redirect_url(self, *args, **kwargs): pano = get_object_or_404(Panorama, pk=kwargs['pk']) pano.generate_tiles() return super(PanoramaGenTiles, self).get_redirect_url(*args, **kwargs) class MainView(CelutzLoginMixin, TemplateView): template_name = "panorama/main.html" def get_context_data(self, **kwargs): context = super(MainView, self).get_context_data(**kwargs) context['refpoints_form'] = SelectReferencePointForm context['custom_point_form'] = CustomPointForm context['newpanorama_form'] = PanoramaForm context['newrefpoint_form'] = ReferencePointForm context['panoramas'] = Panorama.objects.all() context['poi_list'] = [poi for poi in ReferencePoint.objects.all() if not hasattr(poi, 'panorama')] return context def compute_interesting_panoramas(self, point): """Compute all panoramas that see the given point, along with the distance and direction from each panorama towards the point. Returns a list of (panorama, distance, bearing, elevation) triples. """ if isinstance(point, ReferencePoint): queryset = Panorama.objects.exclude(id=point.id) else: queryset = Panorama.objects l = [(pano, pano.line_distance(point), pano.bearing(point), pano.elevation(point)) for pano in queryset.all() if pano.is_visible(point)] # Sort by increasing distance return sorted(l, key=lambda x: x[1]) class CreateReferencePoint(CelutzLoginMixin, CreateView): model = ReferencePoint fields = ('name', 'latitude', 'longitude', 'altitude') template_name = 'panorama/new-refpoint.html' prefix = 'newrefpoint' def get_success_url(self): return reverse_lazy("panorama:main") class LocateReferencePointView(MainView): """Displays a located reference point""" template_name = 'panorama/locate_point.html' def post(self, request, *args, **kwargs): context = self.get_context_data() form = SelectReferencePointForm(request.POST) if form.is_valid(): point = form.cleaned_data['reference_point'] context['located_panoramas'] = self.compute_interesting_panoramas(point) context['located_point_name'] = point.name context['located_point_lat'] = point.latitude context['located_point_lon'] = point.longitude return super(LocateReferencePointView, self).render_to_response(context) class LocateCustomPointView(MainView): """Displays a located custom GPS point""" template_name = 'panorama/locate_point.html' def post(self, request, *args, **kwargs): context = self.get_context_data() form = CustomPointForm(request.POST) if form.is_valid(): point = Point(**form.cleaned_data) context['located_panoramas'] = self.compute_interesting_panoramas(point) context['located_point_lat'] = point.latitude context['located_point_lon'] = point.longitude return super(LocateCustomPointView, self).render_to_response(context)