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) | 
