diff options
Diffstat (limited to 'chimere/views.py')
| -rw-r--r-- | chimere/views.py | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/chimere/views.py b/chimere/views.py new file mode 100644 index 0000000..24948ad --- /dev/null +++ b/chimere/views.py @@ -0,0 +1,470 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2008-2011 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Views of the project +""" + +import datetime +from itertools import groupby + +from django.utils.translation import ugettext as _ +from django.shortcuts import render_to_response +from django.template import loader +from django.http import HttpResponseRedirect, HttpResponse +from django.core import serializers +from django.utils.http import urlquote +from django.db.models import Q +from django.utils import simplejson + +from chimere import settings +from chimere.actions import actions +from chimere.models import Category, SubCategory, PropertyModel, \ + Marker, Route, News, SimpleArea, Area, Color, TinyUrl, RouteFile + +from chimere.widgets import getMapJS, PointChooserWidget, \ + RouteChooserWidget, URL_OSM_JS, URL_OSM_CSS +from chimere.forms import MarkerForm, RouteForm, ContactForm, \ + FileForm, FullFileForm, notifySubmission, notifyStaff + +def get_base_response(area_name=""): + """ + Get the base url + """ + base_response_dct = {'media_path':settings.MEDIA_URL,} + base_url = settings.EXTRA_URL + if not base_url.startswith('/'): + base_url = '/' + base_url + if area_name: + if base_url[-1] != '/': + base_url += '/' + base_url += area_name + '/' + base_response_dct['extra_url'] = base_url + if settings.CSS_AREAS and area_name: + base_response_dct['css_area'] = area_name + ".css" + base_response_dct['area_name'] = area_name + base_response_dct['JQUERY_URL'] = settings.JQUERY_URL + return base_response_dct + +def index(request, area_name=None, default_area=None, simple=False): + """ + Main page + """ + extra = "" + tab = " "*4 + for url in URL_OSM_CSS: + extra += tab + '<link rel="stylesheet" href="%s" />' % url + for url in URL_OSM_JS + ["%sbase.js" % settings.MEDIA_URL, + "%smain_map.js" % settings.MEDIA_URL,]: + extra += tab + '<script src="%s"></script>\n' % url + # show the welcome page + today = datetime.date.today().strftime('%y-%m-%d') + display_welcome = None + if not 'last_visit' in request.session or \ + request.session['last_visit'] != today: + request.session['last_visit'] = today + display_welcome = True + response_dct = get_base_response(area_name) + areas = None + if settings.DISPLAY_AREAS: + areas = Area.getAvailable() + response_dct.update({'actions':actions, 'action_selected':('view',), + 'error_message':'', 'default_area':default_area, + 'extra_head':extra + getMapJS(area_name), + 'welcome':welcome(request, display_welcome), + 'areas':areas, 'map_layer':settings.MAP_LAYER, + 'dynamic_categories':settings.DYNAMIC_CATEGORIES, + }) + # manage permalink + if request.GET: + for key in ('zoom', 'lon', 'lat', 'display_submited', + 'current_feature'): + if key in request.GET and request.GET[key]: + response_dct['p_'+key] = request.GET[key] + else: + response_dct['p_'+key] = None + if 'checked_categories' in request.GET \ + and request.GET['checked_categories']: + cats = request.GET['checked_categories'].split('_') + response_dct['p_checked_categories'] = ",".join(cats) + else: + response_dct['p_checked_categories'] = ''; + tpl = 'main_map.html' + if simple: + tpl = 'main_map_simple.html' + return render_to_response(tpl, response_dct) + +def edit(request, area_name=""): + """ + Edition page + """ + # If the form has been submited + if request.method == 'POST': + form = MarkerForm(request.POST, request.FILES) + # All validation rules pass + if form.is_valid(): + marker = form.save() + # set the submited status + marker.status = 'S' + marker.save() + notifySubmission(marker) + response_dct = get_base_response(area_name) + return HttpResponseRedirect(response_dct['extra_url'] + \ + 'submited/edit') + else: + # An unbound form + form = MarkerForm() + # get the « manualy » declared_fields. Ie: properties + declared_fields = form.declared_fields.keys() + response_dct = get_base_response(area_name) + response_dct.update({'actions':actions, + 'action_selected':('contribute', 'edit'), + 'error_message':'', + 'map_layer':settings.MAP_LAYER, + 'form':form, + 'dated':settings.DAYS_BEFORE_EVENT, + 'extra_head':form.media, + 'sub_categories':SubCategory.getAvailable(['M', 'B'], + area_name), + 'point_widget':PointChooserWidget().render('point', None, + area_name=area_name), + 'properties':declared_fields, + }) + # manualy populate the custom widget + if 'subcategory' in form.data and form.data['subcategory']: + response_dct['current_category'] = int(form.data['subcategory']) + return render_to_response('edit.html', response_dct) + +def uploadFile(request, category_id='', area_name=''): + response_dct = get_base_response(area_name) + Form = FileForm if not category_id else FullFileForm + category = None + if category_id: + try: + category = SubCategory.objects.get(pk=category_id) + response_dct['category'] = unicode(category) + except: + pass + # If the form has been submited + if request.method == 'POST': + form = Form(request.POST, request.FILES) + # All validation rules pass + if form.is_valid(): + raw_file = form.cleaned_data['raw_file'] + name = raw_file.name.split('.')[0] + file_type = raw_file.name.split('.')[-1][0].upper() + routefile = RouteFile(raw_file=raw_file, name=name, + file_type=file_type) + routefile.save() + if not category_id: + response_dct['gpx_id'] = routefile.pk + return render_to_response('upload_file.html', response_dct) + routefile.process() + if not routefile.route: + response_dct['errors'] = _(u"Bad file. Please check it with an " + u"external software.") + response_dct.update({'form':form}) + return render_to_response('upload_file.html', response_dct) + route = Route(name=form.cleaned_data['name'], route=routefile.route, + associated_file=routefile, status='S') + route.save() + route.categories.add(category) + route.save() + response_dct['thanks'] = True + form = Form() + else: + # An unbound form + form = Form() + response_dct.update({'form':form}) + return render_to_response('upload_file.html', response_dct) + +def processRouteFile(request, area_name='', file_id=None): + if file_id: + try: + route_file = RouteFile.objects.get(pk=file_id) + route_file.process() + route = route_file.route + if not route: + return HttpResponse(status=500) + return HttpResponse(simplejson.dumps({'wkt':route, + 'file_id':file_id}), + 'application/javascript', status=200) + except: + return HttpResponse(status=500) + else: + return HttpResponse(status=400) + +def editRoute(request, area_name=""): + """ + Route edition page + """ + # If the form has been submited + if request.method == 'POST': + form = RouteForm(request.POST, request.FILES) + # All validation rules pass + if form.is_valid(): + route = form.save() + # set the submited status + route.status = 'S' + route.save() + notifySubmission(route) + response_dct = get_base_response(area_name) + return HttpResponseRedirect(response_dct['extra_url'] + \ + 'submited/edit') + else: + # An unbound form + form = RouteForm() + # get the "manualy" declared_fields. Ie: properties + declared_fields = form.declared_fields.keys() + response_dct = get_base_response(area_name) + response_dct.update({'actions':actions, + 'action_selected':('contribute', 'edit_route'), + 'error_message':'', + 'map_layer':settings.MAP_LAYER, + 'form':form, + 'dated':settings.DAYS_BEFORE_EVENT, + 'extra_head':form.media, + 'sub_categories':SubCategory.getAvailable(['R', 'B'], + area_name), + 'route_widget':RouteChooserWidget().render('route', '', + area_name=area_name, + routefile_id='',), + 'properties':declared_fields + }) + # manualy populate the custom widget + if 'subcategory' in form.data and form.data['subcategory']: + response_dct['current_category'] = int(form.data['subcategory']) + return render_to_response('edit_route.html', response_dct) + +def welcome(request, display=None): + """ + Welcome string + """ + response_dct = {'display':display} + news = list(News.objects.filter(available=True).all()) + if settings.DAYS_BEFORE_EVENT: + q = checkDate(Q(status='A', start_date__isnull=False)) + news += list(Marker.objects.filter(q).all()) + news.sort(key=lambda x:x.date) + response_dct['news_lst'] = news + return loader.render_to_string('welcome.html', response_dct) + +def submited(request, area_name="", action=""): + """ + Successful submission page + """ + response_dct = get_base_response(area_name) + response_dct.update({'actions':actions, 'action_selected':action,}) + return render_to_response('submited.html', response_dct) + +def charte(request, area_name=""): + """ + Affichage de la charte + """ + response_dct = get_base_response(area_name) + response_dct.update({'actions':actions, 'action_selected':('charte',)}) + return render_to_response('charte.html', response_dct) + +def contactus(request, area_name=""): + """ + Contact page + """ + form = None + msg = '' + # If the form has been submited + if request.method == 'POST': + form = ContactForm(request.POST) + # All validation rules pass + if form.is_valid(): + response = notifyStaff(_(u"Comments/request on the map"), + form.cleaned_data['content'], form.cleaned_data['email']) + if response: + msg = _(u"Thank you for your contribution. It will be taken \ +into account. If you have left your email you may be contacted soon for more \ +details.") + else: + msg = _(u"Temporary error. Renew your message later.") + else: + form = ContactForm() + response_dct = get_base_response(area_name) + response_dct.update({'actions':actions, 'action_selected':('contact',), + 'contact_form':form, 'message':msg}) + return render_to_response('contactus.html', response_dct) + +def getDetail(request, area_name, marker_id): + ''' + Get the detail for a marker + ''' + try: + marker = Marker.objects.filter(id=int(marker_id), status__in=['A', 'S'])[0] + except (ValueError, IndexError): + return HttpResponse('no results') + response_dct = get_base_response() + response_dct['marker'] = marker + if request.method == 'GET': + if 'simple' in request.GET and request.GET['simple']: + response_dct['simple'] = True + parameters = u'current_feature=%s' % marker_id + parameters += u"&checked_categories=%s" % "_".join([str(m.id) \ + for m in marker.categories.all()]) + net_dct = getTinyfiedUrl(parameters, area_name) + share_networks = [] + for network in settings.SHARE_NETWORKS: + share_networks.append((network[0], network[1] % net_dct, network[2])) + response_dct['share_networks'] = share_networks + response_dct['dated'] = settings.DAYS_BEFORE_EVENT and marker.start_date + return render_to_response('detail.html', response_dct) + +def getDescriptionDetail(request, area_name, category_id): + ''' + Get the description for a category + ''' + try: + category = Category.objects.filter(id=int(category_id))[0] + except (ValueError, IndexError): + return HttpResponse('no results') + response_dct = get_base_response(area_name) + response_dct['category'] = category + return render_to_response('category_detail.html', response_dct) + +def checkDate(q): + """ + Filter a queryset to manage dates + """ + if not settings.DAYS_BEFORE_EVENT: + return q + today = datetime.date.today() + after = today + datetime.timedelta(settings.DAYS_BEFORE_EVENT) + + q = q & ( Q(start_date__isnull=True) + | Q(start_date__gte=today, start_date__lte=after) + | Q(start_date__lte=today, end_date__gte=today) + ) + return q + +def getGeoObjects(request, area_name, category_ids, status): + ''' + Get the JSON for markers and routes + ''' + if not status: + status = 'A' + status = status.split('_') + category_ids = category_ids.split('_') + try: + q = checkDate(Q(status__in=status, categories__in=category_ids)) + query = Route.objects.filter(q) + except: + return HttpResponse('no results') + query.order_by('categories') + routes = list(query) + jsons = [] + current_cat, colors, idx = None, None, 0 + for route in routes: + c_cat = route.categories.all()[0] + if not current_cat or current_cat != c_cat: + idx = 0 + current_cat = c_cat + colors = list(Color.objects.filter(color_theme = c_cat.color_theme)) + if colors: + jsons.append(route.getGeoJSON(color=colors[idx % len(colors)].code)) + else: + jsons.append(route.getGeoJSON(color='000')) + idx += 1 + try: + q = checkDate(Q(status__in=status, categories__in=category_ids)) + query = Marker.objects.filter(q) + except: + return HttpResponse('no results') + category_ids = [int(cat_id) for cat_id in category_ids] + jsons += [geo_object.getGeoJSON(category_ids) for geo_object in list(query)] + if not jsons: + return HttpResponse('no results') + data = '{"type": "FeatureCollection", "features":[%s]}' % ",".join(jsons) + return HttpResponse(data) + +def getAvailableCategories(request, area_name=None, area=None, status='A', + force=None): + ''' + Get categories for a designed area + ''' + if settings.DYNAMIC_CATEGORIES and not area: + return "" + response_dct = get_base_response('area_name') + if not settings.DYNAMIC_CATEGORIES: + subcategories = SubCategory.getAvailable() + response_dct['sub_categories'] = subcategories + return render_to_response('categories.html', response_dct) + default_message = "<p class='warning'>%s</p>" % \ + _("No category available in this area.") + if not status: # there must be a status + status = 'A' + try: + status = status.split('_') + area = area.replace('M', '-').replace('D', '.') + area = SimpleArea([float(pt) for pt in area.split('_')]) + except: + # bad area format + return HttpResponse(default_message) + # if not force and area.isIn(SimpleArea(cookie.AREA):return + categories = area.getCategories(status) + if not categories: + return HttpResponse(default_message) + get_cat = lambda subcat: subcat.category + get_cat_order = lambda subcat: (subcat.category.order, subcat.category, + subcat.order) + categories = sorted(categories, key=get_cat_order) + subcategories = [(cat, list(subcats)) \ + for cat, subcats in groupby(categories, get_cat)] + response_dct['sub_categories'] = subcategories + return render_to_response('categories.html', response_dct) + +def getTinyfiedUrl(parameters, area_name=''): + ''' + Get the tinyfied version of parameters + ''' + data = {"urn": "", "url":"", "text":""} + try: + urn = TinyUrl.getUrnByParameters(parameters) + except: + return {} + response_dct = get_base_response(area_name) + url = settings.SERVER_URL + if url[-1] == '/': + url = url[:-1] + url += response_dct['extra_url'] + 'ty/' + urn + text = settings.PROJECT_NAME + if 'current_feature' in parameters: + for item in parameters.split('&'): + if 'current_feature' in item: + try: + text = unicode(Marker.objects.get(id=item.split('=')[1])) + except (IndexError, Marker.DoesNotExist): + pass + data["urn"] = urlquote(urn) + data["url"] = urlquote(url) + data["text"] = urlquote(text) + return data + +def redirectFromTinyURN(request, area_name='', tiny_urn=''): + """ + Redirect from a tiny Urn + """ + parameters = '?' + TinyUrl.getParametersByUrn(tiny_urn) + response_dct = get_base_response(area_name) + return HttpResponseRedirect(response_dct['extra_url'] + parameters) |
