#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2008-2011 Étienne Loks # 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 . # 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.main.actions import actions from chimere.main.models import Category, SubCategory, PropertyModel, \ Marker, Route, News, SimpleArea, Area, Color, TinyUrl, RouteFile from chimere.main.widgets import getMapJS, PointChooserWidget, \ RouteChooserWidget, URL_OSM_JS, URL_OSM_CSS from chimere.main.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 + '' % url for url in URL_OSM_JS + ["%sbase.js" % settings.MEDIA_URL, "%smain_map.js" % settings.MEDIA_URL,]: extra += tab + '\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 = "

%s

" % \ _("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)