summaryrefslogtreecommitdiff
path: root/chimere/main
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@peacefrogs.net>2012-02-15 16:59:28 +0100
committerÉtienne Loks <etienne.loks@peacefrogs.net>2012-02-15 16:59:28 +0100
commitf88541bedcffdfaff485ef71287be88a58c745c2 (patch)
tree87e9fcd59da5d687d2954ae99d9f511df55058f2 /chimere/main
parent8ccdaf23128fbe563658ca0d9d74d2ffd831b68d (diff)
downloadChimère-f88541bedcffdfaff485ef71287be88a58c745c2.tar.bz2
Chimère-f88541bedcffdfaff485ef71287be88a58c745c2.zip
Large reorganization (refs #316), south migration script to new model names (refs #319)
Diffstat (limited to 'chimere/main')
-rw-r--r--chimere/main/__init__.py0
-rw-r--r--chimere/main/actions.py43
-rw-r--r--chimere/main/admin.py142
-rw-r--r--chimere/main/forms.py331
-rw-r--r--chimere/main/models.py612
-rw-r--r--chimere/main/templatetags/__init__.py1
-rw-r--r--chimere/main/templatetags/sanitize.py31
-rw-r--r--chimere/main/templatetags/unlocalize_point.py16
-rw-r--r--chimere/main/views.py470
-rw-r--r--chimere/main/widgets.py354
10 files changed, 0 insertions, 2000 deletions
diff --git a/chimere/main/__init__.py b/chimere/main/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chimere/main/__init__.py
+++ /dev/null
diff --git a/chimere/main/actions.py b/chimere/main/actions.py
deleted file mode 100644
index 6f82028..0000000
--- a/chimere/main/actions.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008-2010 É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.
-
-"""
-Actions available in the main interface
-"""
-from django.utils.translation import ugettext_lazy as _
-from django.contrib.auth import models
-
-from chimere.settings import EXTRA_URL, EMAIL_HOST, INSTALLED_APPS
-
-class Action:
- def __init__(self, id, path, label):
- self.id, self.path, self.label = id, path, label
-
-actions = [(Action('view', '', _('View')), []),
- (Action('contribute', 'edit', _('Contribute')),
- (Action('edit', 'edit', _('Add a new point of interest')),
- Action('edit_route', 'edit_route', _('Add a new route'))),
- ),]
-
-if 'chimere.rss' in INSTALLED_APPS:
- actions.append((Action('rss', 'rss', _('RSS feeds')), []))
-
-if EMAIL_HOST:
- actions.append((Action('contact', 'contact', _('Contact us')), []),)
-
diff --git a/chimere/main/admin.py b/chimere/main/admin.py
deleted file mode 100644
index c3333c7..0000000
--- a/chimere/main/admin.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# Copyright (C) 2008-2010 É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.
-
-"""
-Settings for administration pages
-"""
-
-from chimere import settings
-from chimere.main.models import Category, Icon, SubCategory, Marker, \
- PropertyModel, News, Route, Area, ColorTheme, Color, RouteFile
-from chimere.main.forms import MarkerAdminForm, RouteAdminForm, AreaAdminForm,\
- NewsAdminForm, CategoryAdminForm
-from chimere.main.widgets import TextareaWidget
-
-from django.contrib import admin
-
-def get_areas_for_user(user):
- """
- Getting subcats for a specific user
- """
- perms = user.get_all_permissions()
- areas = set()
- prefix = 'main.change_area_'
- for perm in perms:
- if perm.startswith(prefix):
- area = Area.objects.get(urn=perm[len(prefix):])
- areas.add(area)
- return areas
-
-class MarkerAdmin(admin.ModelAdmin):
- """
- Specialized the Point field.
- """
- search_fields = ("name",)
- list_display = ('name', 'status')
- list_filter = ('status', 'categories')
- exclude = ['height', 'width']
- if 'chimere.rss' in settings.INSTALLED_APPS:
- exclude.append('available_date')
- form = MarkerAdminForm
-
- def queryset(self, request):
- qs = self.model._default_manager.get_query_set()
- if not request.user.is_superuser:
- areas = get_areas_for_user(request.user)
- if areas:
- in_areas = " or ".join([area.getIncludeSql() for area in areas])
- qs = qs.extra(where=[in_areas])
- ordering = self.ordering or ()
- if ordering:
- qs = qs.order_by(*ordering)
- return qs
-
-class RouteAdmin(admin.ModelAdmin):
- """
- Specialized the Route field.
- """
- search_fields = ("name",)
- list_display = ('name', 'status')
- list_filter = ('status', 'categories')
- exclude = ['height', 'width']
- form = RouteAdminForm
- readonly_fields = ('associated_file',)
-
- def queryset(self, request):
- qs = self.model._default_manager.get_query_set()
- if not request.user.is_superuser:
- areas = get_areas_for_user(request.user)
- if areas:
- in_areas = " or ".join([area.getIncludeSql(
- geometry='"main_route".route') for area in areas])
- qs = qs.extra(where=[in_areas])
- ordering = self.ordering or ()
- if ordering:
- qs = qs.order_by(*ordering)
- return qs
-
-class AreaAdmin(admin.ModelAdmin):
- """
- Specialized the area field.
- """
- form = AreaAdminForm
- exclude = ['upper_left_corner', 'lower_right_corner']
-
-class SubCategoryAdmin(admin.ModelAdmin):
- """
- Specialized the subcategory admin
- """
- list_display = ('name', 'category', 'available')
- list_filter = ('category',)
-
-class NewsAdmin(admin.ModelAdmin):
- """
- Use the TinyMCE widget for the news content
- """
- form = NewsAdminForm
-
-class CategoryAdmin(admin.ModelAdmin):
- """
- Use the TinyMCE widget for categories
- """
- form = CategoryAdminForm
-
-class ColorInline(admin.TabularInline):
- model = Color
-
-class ColorThemeAdmin(admin.ModelAdmin):
- inlines = [ColorInline,]
-
-class IconAdmin(admin.ModelAdmin):
- exclude = ['height', 'width']
-
-class RouteFileAdmin(admin.ModelAdmin):
- list_display = ['name', 'file_type']
-
-# register of differents database fields
-admin.site.register(News, NewsAdmin)
-admin.site.register(Category, CategoryAdmin)
-admin.site.register(Icon, IconAdmin)
-admin.site.register(SubCategory, SubCategoryAdmin)
-admin.site.register(Marker, MarkerAdmin)
-admin.site.register(RouteFile, RouteFileAdmin)
-admin.site.register(Route, RouteAdmin)
-admin.site.register(PropertyModel)
-admin.site.register(Area, AreaAdmin)
-admin.site.register(ColorTheme, ColorThemeAdmin)
diff --git a/chimere/main/forms.py b/chimere/main/forms.py
deleted file mode 100644
index 20027ee..0000000
--- a/chimere/main/forms.py
+++ /dev/null
@@ -1,331 +0,0 @@
-#!/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.
-
-"""
-Forms
-"""
-from django import forms
-from django.contrib.gis.db import models
-from django.utils.translation import ugettext as _
-from django.contrib.auth.models import User, Permission, ContentType
-from django.contrib.admin.widgets import AdminDateWidget
-from django.core.mail import EmailMessage, BadHeaderError
-
-from chimere import settings
-
-from chimere.main.models import Marker, Route, PropertyModel, Property, Area,\
- News, Category, SubCategory, RouteFile
-from chimere.main.widgets import AreaField, PointField, TextareaWidget
-
-from datetime import timedelta, datetime, tzinfo
-
-ZERO = timedelta(0)
-
-class UTC(tzinfo):
- """UTC time zone"""
-
- def utcoffset(self, dt):
- return ZERO
-
- def tzname(self, dt):
- return settings.TIME_ZONE
-
- def dst(self, dt):
- return ZERO
-
-def notifyStaff(subject, body, sender=None):
- if not settings.EMAIL_HOST:
- return
- if settings.PROJECT_NAME:
- subject = u'[%s] %s' % (settings.PROJECT_NAME, subject)
- user_list = [u.email for u in
- User.objects.filter(is_staff=True).exclude(email="").order_by('id')]
- headers = {}
- if sender:
- headers['Reply-To'] = sender
- email = EmailMessage(subject, body, user_list[0], user_list,
- headers=headers)
- try:
- email.send()
- except BadHeaderError:
- return False
- return True
-
-def notifySubmission(geo_object):
- category = u" - ".join([unicode(cat) for cat in geo_object.categories.all()])
- subject = u'%s %s' % (_(u"New submission for"), category)
- message = _(u'The new item "%s" has been submited in the category: ') % \
- geo_object.name + category
- message += "\n\n" + _(u"To valid, precise or unvalid this item: ")
- message += settings.BASE_URL + 'admin'
- message += u"\n\n--\nChimère"
- return notifyStaff(subject, message)
-
-class ContactForm(forms.Form):
- """
- Main form for categories
- """
- email = forms.EmailField(label=_("Email (optional)"), required=False)
- content = forms.CharField(label=_("Object"), widget=forms.Textarea)
-
-class NewsAdminForm(forms.ModelForm):
- """
- Main form for news
- """
- content = forms.CharField(widget=TextareaWidget)
- class Meta:
- model = News
-
-class CategoryAdminForm(forms.ModelForm):
- """
- Main form for categories
- """
- description = forms.CharField(widget=TextareaWidget, required=False)
- class Meta:
- model = Category
-
-class MarkerAdminForm(forms.ModelForm):
- """
- Main form for marker
- """
- # declare properties
- for property in PropertyModel.objects.filter(available=True):
- exec('property_%d_%d = forms.CharField(label="%s", widget=%s, '\
- 'required=False)' % (property.order, property.id, property.name,
- PropertyModel.TYPE_WIDGET[property.type]))
- class Meta:
- model = Marker
-
- def __init__(self, *args, **keys):
- """
- Custom initialization method in order to manage properties
- """
- if 'instance' in keys and keys['instance']:
- instance = keys['instance']
- property_dct = {}
- for pm in PropertyModel.objects.filter(available=True):
- property = instance.getProperty(pm)
- if property:
- property_dct[pm.getNamedId()] = property.value
- if 'initial' in keys:
- keys['initial'].update(property_dct)
- else:
- keys['initial'] = property_dct
- super(MarkerAdminForm, self).__init__(*args, **keys)
- if settings.DAYS_BEFORE_EVENT:
- self.fields['start_date'].widget = AdminDateWidget()
- self.fields['end_date'].widget = AdminDateWidget()
-
- def clean(self):
- '''
- Verify that a start date is provided when an end date is set
- '''
- if not settings.DAYS_BEFORE_EVENT:
- return self.cleaned_data
- if self.cleaned_data['end_date'] and \
- not self.cleaned_data['start_date']:
- msg = _(u"End date has been set with no start date")
- self._errors["end_date"] = self.error_class([msg])
- del self.cleaned_data['end_date']
- return self.cleaned_data
-
- def save(self, *args, **keys):
- """
- Custom save method in order to manage associated properties
- """
- new_marker = super(MarkerAdminForm, self).save(*args, **keys)
- if 'status' not in self.cleaned_data:
- new_marker.status = 'S'
- if new_marker.status == 'A':
- tz = UTC()
- new_marker.available_date = datetime.replace(datetime.utcnow(),
- tzinfo=tz)
- new_marker.save()
- # save properties
- properties = dict([(k.split('_')[-1], self.cleaned_data[k]) \
- for k in self.cleaned_data.keys() if k.startswith('property_')])
- new_marker.saveProperties(properties)
- return new_marker
-
-class MarkerForm(MarkerAdminForm):
- """
- Form for the edit page
- """
- class Meta:
- model = Marker
- exclude = ('status',)
-
-class RouteAdminForm(forms.ModelForm):
- """
- Main form for route
- """
- class Meta:
- model = Route
-
- def __init__(self, *args, **keys):
- """
- Custom initialization method in order to manage properties
- """
- if 'instance' in keys and keys['instance']:
- instance = keys['instance']
- property_dct = {}
- for pm in PropertyModel.objects.filter(available=True):
- property = instance.getProperty(pm)
- if property:
- property_dct[pm.getNamedId()] = property.value
- if 'initial' in keys:
- keys['initial'].update(property_dct)
- else:
- keys['initial'] = property_dct
- super(RouteAdminForm, self).__init__(*args, **keys)
- if settings.DAYS_BEFORE_EVENT:
- self.fields['start_date'].widget = AdminDateWidget()
- self.fields['end_date'].widget = AdminDateWidget()
-
- def save(self, *args, **keys):
- """
- Custom save method in order to manage status
- """
- new_route = super(RouteAdminForm, self).save(*args, **keys)
- if 'status' not in self.cleaned_data:
- new_route.status = 'S'
- new_route.save()
- return new_route
-
-class RouteForm(RouteAdminForm):
- """
- Form for the edit page
- """
- picture = forms.ImageField(label=_("Image"), required=False)
- point = forms.CharField(label=" ", required=False, widget=forms.HiddenInput)
- associated_file_id = forms.CharField(label=" ", required=False,
- widget=forms.HiddenInput)
- class Meta:
- model = Route
- exclude = ('status',)
- # marker properties
- for property in PropertyModel.objects.filter(available=True):
- exec('property_%d_%d = forms.CharField(label="%s", widget=%s, '\
- 'required=False)' % (property.order, property.id, property.name,
- PropertyModel.TYPE_WIDGET[property.type]))
-
- def save(self, *args, **keys):
- """
- Custom save method in order to manage associated marker and file
- """
- new_route = super(RouteForm, self).save(*args, **keys)
- # associate a route file
- if 'associated_file_id' in self.cleaned_data and \
- self.cleaned_data['associated_file_id']:
- #try:
- file_pk = int(self.cleaned_data['associated_file_id'])
- new_route.associated_file = RouteFile.objects.get(pk=file_pk)
- new_route.save()
- #except:
- #pass
- marker_fields = [f.attname for f in Marker._meta.fields]
- marker_dct = dict([(k, self.cleaned_data[k]) for k in self.cleaned_data
- if k in marker_fields])
- marker_dct['route'] = new_route
- if 'status' not in marker_dct:
- marker_dct['status'] = "S"
- categories = []
- new_marker = Marker(**marker_dct)
- new_marker.save()
- for category in self.cleaned_data['categories']:
- new_marker.categories.add(category)
- new_marker.save()
- # save properties
- properties = dict([(k.split('_')[-1], self.cleaned_data[k]) \
- for k in self.cleaned_data.keys() if k.startswith('property_')])
- new_marker.saveProperties(properties)
- return new_route
-
-class FileForm(forms.Form):
- raw_file = forms.FileField(label=_(u"File"))
-
- def clean_raw_file(self):
- data = self.cleaned_data['raw_file']
- if '.' not in data.name or \
- data.name.split('.')[-1].lower() not in ('kml', 'gpx'):
- raise forms.ValidationError(_(u"Bad file format: this must be a "\
- u"GPX or KML file"))
- return data
-
-class FullFileForm(FileForm):
- name = forms.CharField(label=_(u"Name"), max_length=150)
- def __init__(self, *args, **kwargs):
- super(FullFileForm, self).__init__(*args, **kwargs)
- self.fields.keyOrder = ['name', 'raw_file']
-
-class AreaAdminForm(forms.ModelForm):
- """
- Admin page to create an area
- """
- area = AreaField(label=_("Area"), fields=(PointField(), PointField()))
- class Meta:
- model = Area
-
- def __init__(self, *args, **keys):
- """
- Custom initialization method in order to manage area
- """
- if 'instance' in keys and keys['instance']:
- instance = keys['instance']
- dct = {'area':(instance.upper_left_corner,
- instance.lower_right_corner)}
- if 'initial' in keys:
- keys['initial'].update(dct)
- else:
- keys['initial'] = dct
- super(AreaAdminForm, self).__init__(*args, **keys)
-
- def save(self, *args, **keys):
- """
- Custom save method in order to manage area
- """
- new_area = super(AreaAdminForm, self).save(*args, **keys)
- area = self.cleaned_data['area']
- new_area.upper_left_corner = 'POINT(%s %s)' % (area[0][0], area[0][1])
- new_area.lower_right_corner = 'POINT(%s %s)' % (area[1][0],
- area[1][1])
- content_type = ContentType.objects.get(app_label="main",
- model="area")
- if new_area.urn:
- mnemo = 'change_area_' + new_area.urn
- perm = Permission.objects.filter(codename=mnemo)
- if not perm:
- perm = Permission(name='Can change ' + new_area.name,
- content_type_id=content_type.id, codename=mnemo)
- perm.save()
- else:
- if 'urn' in self.initial:
- mnemo = 'change_area_' + self.initial['urn']
- perm = Permission.objects.filter(codename=mnemo)
- if perm:
- perm[0].delete()
- return new_area
-
-class AreaForm(AreaAdminForm):
- """
- Form for the edit page
- """
- class Meta:
- model = Area
-
diff --git a/chimere/main/models.py b/chimere/main/models.py
deleted file mode 100644
index 144b49d..0000000
--- a/chimere/main/models.py
+++ /dev/null
@@ -1,612 +0,0 @@
-#!/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.
-
-"""
-Models description
-"""
-import os, string, json
-import lxml.etree as ElementTree
-from datetime import datetime, timedelta
-from subprocess import Popen, PIPE
-
-from django.core.files import File
-
-from django.utils.translation import ugettext_lazy as _
-
-from django.contrib.gis.db import models
-from django.contrib.gis.gdal import SpatialReference
-from django.contrib import admin
-
-from chimere import settings
-from chimere.main.widgets import PointField, RouteField, SelectMultipleField
-
-class News(models.Model):
- """News of the site
- """
- title = models.CharField(_("Name"), max_length=150)
- available = models.BooleanField(_("Available"))
- date = models.DateField(_("Date"), auto_now_add=True)
- content = models.TextField()
- def __unicode__(self):
- ordering = ["-date"]
- return self.title
- class Meta:
- verbose_name = _("News")
- verbose_name_plural = _("News")
-
-class TinyUrl(models.Model):
- """Tinyfied version of permalink parameters
- """
- parameters = models.CharField(_("Parameters"), max_length=500)
- def __unicode__(self):
- return self.parameters
- class Meta:
- verbose_name = _("TinyUrl")
- digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- base = len(digits)
-
- @classmethod
- def getParametersByUrn(cls, urn):
- c_id = 0
- for idx, char in enumerate(reversed(urn)):
- c_id += cls.digits.index(char)*pow(cls.base, idx)
- try:
- params = cls.objects.get(id=c_id).parameters
- except cls.DoesNotExist:
- return ''
- return params
-
- @classmethod
- def getUrnByParameters(cls, parameters):
- try:
- obj = cls.objects.get(parameters=parameters)
- except cls.DoesNotExist:
- obj = cls(parameters=parameters)
- obj.save()
- n = obj.id
- urn = ''
- while 1:
- idx = n % cls.base
- urn = cls.digits[idx] + urn
- n = n / cls.base
- if n == 0:
- break
- return urn
-
-class ColorTheme(models.Model):
- """Color theme
- """
- name = models.CharField(_("Name"), max_length=150)
- def __unicode__(self):
- return self.name
- class Meta:
- verbose_name = _("Color theme")
-
-class Color(models.Model):
- """Color
- """
- code = models.CharField(_("Code"), max_length=6)
- order = models.IntegerField(_("Order"))
- color_theme = models.ForeignKey(ColorTheme, verbose_name=_("Color theme"))
- def __unicode__(self):
- return self.code
- class Meta:
- ordering = ["order"]
- verbose_name = _("Color")
-
-class Category(models.Model):
- """Category of Point Of Interest (POI)
- """
- name = models.CharField(_("Name"), max_length=150)
- available = models.BooleanField(_("Available"))
- order = models.IntegerField(_("Order"))
- description = models.TextField(blank=True, null=True)
- def __unicode__(self):
- return self.name
- class Meta:
- ordering = ["order"]
- verbose_name = _("Category")
-
-class Icon(models.Model):
- '''Icon
- '''
- name = models.CharField(_("Name"), max_length=150)
- image = models.ImageField(_("Image"), upload_to='icons',
- height_field='height', width_field='width')
- height = models.IntegerField(_("Height"))
- width = models.IntegerField(_("Width"))
- def __unicode__(self):
- return self.name
- class Meta:
- verbose_name = _("Icon")
-
-class SubCategory(models.Model):
- '''Sub-category
- '''
- category = models.ForeignKey(Category, verbose_name=_("Category"))
- name = models.CharField(_("Name"), max_length=150)
- available = models.BooleanField(_("Available"))
- areas = SelectMultipleField('Area', related_name='areas', blank=True)
- icon = models.ForeignKey(Icon, verbose_name=_("Icon"))
- color_theme = models.ForeignKey(ColorTheme, verbose_name=_("Color theme"),
- blank=True, null=True)
- order = models.IntegerField(_("Order"))
- TYPE = (('M', _('Marker')),
- ('R', _('Route')),
- ('B', _('Both')),)
- item_type = models.CharField(_("Item type"), max_length=1, choices=TYPE)
- def __unicode__(self):
- return u"%s / %s" % (self.category.name, self.name)
- class Meta:
- ordering = ["category", "order"]
- verbose_name = _("Subcategory")
-
- @classmethod
- def getAvailable(cls, item_types=None, area_name=None):
- '''Get list of tuples with first the category and second the associated
- subcategories
- '''
- sub_categories = {}
- subcategories = cls.objects.filter(category__available=True)
- if not item_types:
- subcategories = subcategories.filter(available=True)
- else:
- subcategories = subcategories.filter(item_type__in=item_types)
- if area_name:
- area = Area.objects.get(urn=area_name)
- # if there some restrictions with categories limit them
- if area.subcategory_set.count():
- sub_ids = [sub.id for sub in area.subcategory_set.all()]
- # if no area is defined for a category don't filter it
- sub_ids += [sub.id for sub in subcategories
- if not sub.areas.count()]
- subcategories = subcategories.filter(id__in=sub_ids)
- for sub_category in subcategories:
- if sub_category.category not in sub_categories:
- sub_categories[sub_category.category] = []
- if sub_category.id in settings.DEFAULT_CATEGORIES:
- sub_category.selected = True
- sub_category.category.selected = True
- sub_categories[sub_category.category].append(sub_category)
- return [(category, sub_cats) for category, sub_cats \
- in sub_categories.items()]
-
-class Marker(models.Model):
- '''Marker for a POI
- '''
- name = models.CharField(_("Name"), max_length=150)
- categories = SelectMultipleField(SubCategory)
- point = PointField(_("Localisation"), srid=settings.EPSG_DISPLAY_PROJECTION)
- picture = models.ImageField(_("Image"), upload_to='upload', blank=True,
- null=True, height_field='height', width_field='width')
- height = models.IntegerField(_("Height"), blank=True, null=True)
- width = models.IntegerField(_("Width"), blank=True, null=True)
- STATUS = (('S', _('Submited')),
- ('A', _('Available')),
- ('D', _('Disabled')),)
- STATUS_DCT = {}
- for key, label in STATUS:
- STATUS_DCT[key] = label
- status = models.CharField(_("Status"), max_length=1, choices=STATUS)
- if settings.DAYS_BEFORE_EVENT:
- start_date = models.DateField(_("Start date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it for dated item such as event. "\
- u"Format YYYY-MM-DD"))
- end_date = models.DateField(_("End date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it only if you have a multi-day "\
- u"event. Format YYYY-MM-DD"))
- if 'chimere.rss' in settings.INSTALLED_APPS:
- available_date = models.DateTimeField(_("Available Date"), blank=True,
- null=True)
- route = models.ForeignKey("Route", blank=True, null=True)
- objects = models.GeoManager()
-
- def __unicode__(self):
- return self.name
-
- @property
- def date(self):
- if settings.DAYS_BEFORE_EVENT:
- return self.start_date
-
- class Meta:
- ordering = ('status', 'name')
- verbose_name = _("Point of interest")
-
- def getLatitude(self):
- '''Return the latitude
- '''
- return self.point.y
-
- def getLongitude(self):
- '''Return the longitude
- '''
- return self.point.x
-
- def getProperty(self, propertymodel, safe=None):
- """Get the property of an associated property model.
- If safe set to True, verify if the property is available
- """
- if safe and not propertymodel.available:
- return
- try:
- property = Property.objects.get(propertymodel=propertymodel,
- marker=self)
- except Property.DoesNotExist:
- return
- return property
-
- def getProperties(self):
- """Get all the property availables
- """
- properties = []
- for pm in PropertyModel.objects.filter(available=True):
- property = self.getProperty(pm)
- if property:
- properties.append(property)
- return properties
-
- def saveProperties(self, values):
- """
- Save properties
- """
- for propertymodel in PropertyModel.objects.filter(available=True):
- properties = Property.objects.filter(marker=self,
- propertymodel=propertymodel).all()
- # in case of multiple edition as the same time delete arbitrary
- # the others
- if len(properties) > 1:
- for property in properties[1:]:
- property.delete()
- val = u""
- if unicode(propertymodel.id) in values:
- val = values[unicode(propertymodel.id)]
- # new property
- if not properties:
- new_property = Property.objects.create(marker=self,
- propertymodel=propertymodel,
- value=val)
- new_property.save()
- else:
- property = properties[0]
- property.value = val
- property.save()
-
- def getGeoJSON(self, categories_id=[]):
- '''Return a GeoJSON string
- '''
- jsons = []
- for cat in self.categories.all():
- if categories_id and cat.id not in categories_id:
- continue
- items = {'id':self.id, 'name':json.dumps(self.name),
- 'geometry':self.point.geojson,
- 'icon_path':cat.icon.image,
- 'icon_width':cat.icon.image.width,
- 'icon_height':cat.icon.image.height,}
- jsons.append(u'{"type":"Feature", "geometry":%(geometry)s, '\
- u'"properties":{"pk": %(id)d, "name": %(name)s, '\
- u'"icon_path":"%(icon_path)s", "icon_width":%(icon_width)d, '\
- u'"icon_height":%(icon_height)d}}' % items)
- return ",".join(jsons)
-
- def get_absolute_url(self):
- parameters = 'current_feature=%d&checked_categories=%s' % (self.id,
- self.categories.all()[0].id)
- return settings.BASE_URL + 'ty/' + TinyUrl.getUrnByParameters(parameters)
-
-class RouteFile(models.Model):
- name = models.CharField(_(u"Name"), max_length=150)
- raw_file = models.FileField(_(u"Raw file (gpx or kml)"), upload_to='upload')
- simplified_file = models.FileField(_(u"Simplified file"),
- upload_to='upload', blank=True, null=True)
- TYPE = (('K', _(u'KML')), ('G', _(u'GPX')))
- file_type = models.CharField(max_length=1, choices=TYPE)
-
- def __unicode__(self):
- return self.name
-
- def process(self):
- if self.simplified_file:
- return
- input_name = settings.MEDIA_ROOT + self.raw_file.name
- output_name = settings.MEDIA_ROOT + self.raw_file.name[:-4] + \
- "_simplified" + ".gpx"
- cli_args = [settings.GPSBABEL, '-i']
- if self.file_type == 'K':
- cli_args.append('kml')
- elif self.file_type == 'G':
- cli_args.append('gpx')
- cli_args += ['-f', input_name, '-x', settings.GPSBABEL_OPTIONS,
- '-o', 'gpx', '-F', output_name]
- p = Popen(cli_args, stderr=PIPE)
- p.wait()
- if p.returncode:
- print p.stderr.read()
- #logger.error(p.stderr.read())
- else:
- self.simplified_file = File(open(output_name))
- self.save()
- os.remove(output_name)
-
- @property
- def route(self):
- if not self.simplified_file:
- return
- mainNS = string.Template("{http://www.topografix.com/GPX/1/0}$tag")
- trkpt = mainNS.substitute(tag="trkpt")
- file_name = settings.MEDIA_ROOT + self.simplified_file.name
- et = ElementTree.parse(open(file_name))
- pts = []
- for pt in et.findall("//" + trkpt):
- pts.append((pt.get("lon"), pt.get("lat")))
- geojson_tpl = u'{"type":"Feature", "geometry":{ "type": "LineString", '\
- '"coordinates":[%s]}}'
- wkt_tpl = u'LINESTRING(%s)'
- return wkt_tpl % u','.join([u'%s %s' % (pt[0], pt[1]) \
- for pt in pts])
-
-class Route(models.Model):
- '''Route on the map
- '''
- name = models.CharField(_("Name"), max_length=150)
- categories = SelectMultipleField(SubCategory)
- route = RouteField(_("Route"), srid=settings.EPSG_DISPLAY_PROJECTION)
- associated_file = models.ForeignKey(RouteFile, blank=True, null=True,
- verbose_name=_(u"Associated file"))
- picture = models.ImageField(_("Image"), upload_to='upload', blank=True,
- null=True, height_field='height', width_field='width')
- height = models.IntegerField(_("Height"), blank=True, null=True)
- width = models.IntegerField(_("Width"), blank=True, null=True)
- STATUS = (('S', _('Submited')),
- ('A', _('Available')),
- ('D', _('Disabled')),)
- STATUS_DCT = {}
- for key, label in STATUS:
- STATUS_DCT[key] = label
- if settings.DAYS_BEFORE_EVENT:
- start_date = models.DateField(_("Start date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it for dated item such as event. "\
- u"Format YYYY-MM-DD"))
- end_date = models.DateField(_("End date"), blank=True, null=True,
- help_text=_(u"Not mandatory. Set it only if you have a multi-day "\
- u"event. Format YYYY-MM-DD"))
- status = models.CharField(_("Status"), max_length=1, choices=STATUS)
- objects = models.GeoManager()
-
- def __unicode__(self):
- return self.name
-
- class Meta:
- ordering = ('status', 'name')
- verbose_name = _("Route")
-
- def getProperty(self, propertymodel, safe=None):
- """Get the property of an associated property model.
- If safe set to True, verify if the property is available
- """
- if safe and not propertymodel.available:
- return
- try:
- property = Property.objects.get(propertymodel=propertymodel,
- marker=self)
- except Property.DoesNotExist:
- return
- return property
-
- def getProperties(self):
- """Get all the property availables
- """
- properties = []
- for pm in PropertyModel.objects.filter(available=True):
- property = self.getProperty(pm)
- if property:
- properties.append(property)
- return properties
-
- def getGeoJSON(self, color="#000"):
- '''Return a GeoJSON string
- '''
- if '#' not in color:
- color = '#' + color
- attributes = {'id':self.id, 'name':json.dumps(self.name),
- 'color':color, 'geometry':self.route.geojson,}
- return u'{"type":"Feature", "geometry":%(geometry)s, '\
- u'"properties":{"pk": %(id)d, "name": %(name)s, '\
- u'"color":"%(color)s"}}' % attributes
-
- def getTinyUrl(self):
- parameters = 'current_feature=%d&checked_categories=%s' % (self.id,
- self.categories[0].id)
- return TinyUrl.getUrnByParameters(parameters)
-
-def getDateCondition():
- '''
- Return an SQL condition for apparition of dates
- '''
- if not settings.DAYS_BEFORE_EVENT:
- return ""
- now = datetime.now().strftime('%Y-%m-%d')
- after = (datetime.now() + timedelta(settings.DAYS_BEFORE_EVENT)
- ).strftime('%Y-%m-%d')
- date_condition = " and %(alias)s.start_date is null or "
- date_condition += "(%(alias)s.start_date >= '" + now + "' and "
- date_condition += "%(alias)s.start_date <='" + after + "')"
- date_condition += " or (%(alias)s.start_date <='" + now + "' and "
- date_condition += "%(alias)s.end_date >='" + now + "') "
- return date_condition
-
-class SimplePoint:
- """
- Point in the map (not in the database)
- """
- def __init__(self, x, y):
- self.x, self.y = x, y
-
-class SimpleArea:
- """
- Rectangular area of a map (not in the database)
- """
- def __init__(self, area):
- """
- Defining upper left corner ans lower right corner from a tuple
- """
- assert len(area) == 4
- x1, y1, x2, y2 = area
- self.upper_left_corner = SimplePoint(x1, y1)
- self.lower_right_corner = SimplePoint(x2, y2)
-
- def isIn(self, area):
- """
- Verify if the current area is in the designated area
- """
- if self.upper_left_corner.x >= area.upper_left_corner.x and \
- self.upper_left_corner.y <= area.upper_left_corner.x and \
- self.lower_right_corner.x <= area.lower_right_corner.x and \
- self.lower_right_corner.y >= area.lower_right_corner.y:
- return True
- return False
-
- def getCategories(self, status='A', filter_available=True):
- """
- Get categories for this area
- """
- equal_status = ''
- if len(status) == 1:
- equal_status = "='%s'" % status[0]
- elif status:
- equal_status = " in ('%s')" % "','".join(status)
- area = u"ST_GeometryFromText('POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f"\
- u"))', %d)" % (self.upper_left_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.upper_left_corner.y,
- settings.EPSG_DISPLAY_PROJECTION
- )
- date_condition = getDateCondition()
- sql_main = '''select subcat.id as id, subcat.category_id as category_id,
- subcat.name as name, subcat.available as available,
- subcat.icon_id as icon_id, subcat.color_theme_id as color_theme_id,
- subcat.order as order, subcat.item_type as item_type
- from main_subcategory subcat
- inner join main_category cat on cat.id=subcat.category_id'''
- sql = sql_main + '''
- inner join main_marker mark on ST_Contains(%s, mark.point)''' % area
- if equal_status:
- sql += ' and mark.status' + equal_status
- sql += date_condition % {'alias':'mark'}
- sql += '''
- inner join main_marker_categories mc on mc.subcategory_id=subcat.id and
- mc.marker_id=mark.id'''
- if filter_available:
- sql += ' where subcat.available = TRUE and cat.available = TRUE'
- subcats = set(SubCategory.objects.raw(sql))
- sql = sql_main + '''
- inner join main_route rt on (ST_Intersects(%s, rt.route) or
- ST_Contains(%s, rt.route))''' % (area, area)
- if equal_status:
- sql += ' and rt.status' + equal_status
- sql += date_condition % {'alias':'rt'}
- sql += '''
- inner join main_route_categories rc on rc.subcategory_id=subcat.id and
- rc.route_id=rt.id'''
- if filter_available:
- sql += ' where subcat.available = TRUE and cat.available = TRUE'
- subcats.union(SubCategory.objects.raw(sql))
- return subcats
-
-class Area(models.Model, SimpleArea):
- """Rectangular area of the map
- """
- name = models.CharField(_("Name"), max_length=150)
- urn = models.SlugField(_("Area urn"), max_length=50, blank=True,
- unique=True)
- order = models.IntegerField(_("Order"))
- available = models.BooleanField(_("Available"))
- upper_left_corner = models.PointField(_("Upper left corner"),
- default='POINT(0 0)', srid=settings.EPSG_DISPLAY_PROJECTION)
- lower_right_corner = models.PointField(_("Lower right corner"),
- default='POINT(0 0)', srid=settings.EPSG_DISPLAY_PROJECTION)
- objects = models.GeoManager()
-
- def __unicode__(self):
- return self.name
-
- class Meta:
- ordering = ('order', 'name')
- verbose_name = _("Area")
-
- @classmethod
- def getAvailable(cls):
- '''Get available areas
- '''
- return cls.objects.filter(available=True)
-
- def getIncludeSql(self, geometry='"main_marker".point'):
- """
- Get the sql statement for the test if the point is included in the area
- """
- area = "ST_GeometryFromText('POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f"\
- "))', %d)" % (self.upper_left_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.upper_left_corner.y,
- self.lower_right_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.lower_right_corner.y,
- self.upper_left_corner.x, self.upper_left_corner.y,
- settings.EPSG_DISPLAY_PROJECTION
- )
- sql = "ST_Contains(" + area + ", " + geometry + ")"
- return sql
-
-class PropertyModel(models.Model):
- '''Model for a property
- '''
- name = models.CharField(_("Name"), max_length=150)
- order = models.IntegerField(_("Order"))
- available = models.BooleanField(_("Available"))
- TYPE = (('T', _('Text')),
- ('L', _('Long text')),
- ('P', _('Password')))
- TYPE_WIDGET = {'T':'forms.TextInput',
- 'L':'TextareaWidget',
- 'P':'forms.PasswordInput'}
- type = models.CharField(_("Type"), max_length=1, choices=TYPE)
- def __unicode__(self):
- return self.name
- class Meta:
- ordering = ('order',)
- verbose_name = _("Property model")
-
- def getNamedId(self):
- '''Get the name used as named id (easily sortable)
- '''
- return 'property_%d_%d' % (self.order, self.id)
-
-class Property(models.Model):
- '''Property for a POI
- '''
- marker = models.ForeignKey(Marker, verbose_name=_("Point of interest"))
- propertymodel = models.ForeignKey(PropertyModel,
- verbose_name=_("Property model"))
- value = models.TextField(_("Value"))
- def __unicode__(self):
- return "%s : %s" % (str(self.propertymodel), self.value)
- class Meta:
- verbose_name = _("Property")
-
diff --git a/chimere/main/templatetags/__init__.py b/chimere/main/templatetags/__init__.py
deleted file mode 100644
index 792d600..0000000
--- a/chimere/main/templatetags/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-#
diff --git a/chimere/main/templatetags/sanitize.py b/chimere/main/templatetags/sanitize.py
deleted file mode 100644
index ccb936c..0000000
--- a/chimere/main/templatetags/sanitize.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from django import template
-from BeautifulSoup import BeautifulSoup, Comment
-import re
-
-register = template.Library()
-
-def sanitize(value, allowed_tags):
- """Argument should be in form 'tag2:attr1:attr2 tag2:attr1 tag3', where tags
- are allowed HTML tags, and attrs are the allowed attributes for that tag.
- """
- js_regex = re.compile(r'[\s]*(&#x.{1,7})?'.join(list('javascript')))
- allowed_tags = [tag.split(':') for tag in allowed_tags.split()]
- allowed_tags = dict((tag[0], tag[1:]) for tag in allowed_tags)
-
- soup = BeautifulSoup(value)
- for comment in soup.findAll(text=lambda text: isinstance(text, Comment)):
- comment.extract()
-
- for tag in soup.findAll(True):
- if tag.name not in allowed_tags:
- tag.hidden = True
- else:
- tag.attrs = [(attr, js_regex.sub('', val)) for attr, val in tag.attrs
- if attr in allowed_tags[tag.name]]
- return soup.renderContents().decode('utf8')
-
-register.filter(sanitize)
-
diff --git a/chimere/main/templatetags/unlocalize_point.py b/chimere/main/templatetags/unlocalize_point.py
deleted file mode 100644
index f52a90a..0000000
--- a/chimere/main/templatetags/unlocalize_point.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from django import template
-import re
-
-register = template.Library()
-
-def unlocalize_point(value):
- """
- Basic unlocalize filter for django 1.2
- """
- return unicode(value).replace(',', '.')
-
-register.filter(unlocalize_point)
-
diff --git a/chimere/main/views.py b/chimere/main/views.py
deleted file mode 100644
index 25ad630..0000000
--- a/chimere/main/views.py
+++ /dev/null
@@ -1,470 +0,0 @@
-#!/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.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 + '<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)
diff --git a/chimere/main/widgets.py b/chimere/main/widgets.py
deleted file mode 100644
index 1af6637..0000000
--- a/chimere/main/widgets.py
+++ /dev/null
@@ -1,354 +0,0 @@
-#!/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.
-
-"""
-Extra widgets and fields
-"""
-
-from django import forms
-from django.utils.safestring import mark_safe
-from django.utils.translation import ugettext as _
-from django.contrib.gis.geos import fromstr
-
-from chimere import settings
-from django.contrib.gis.db import models
-
-URL_OSM_CSS = ["http://www.openlayers.org/api/theme/default/style.css"]
-URL_OSM_JS = [settings.MEDIA_URL+"OpenLayers.js",
- "http://www.openstreetmap.org/openlayers/OpenStreetMap.js"]
-
-def getMapJS(area_name=''):
- '''Variable initialization for drawing the map
- '''
- # projection, center and bounds definitions
- js = u"var epsg_display_projection = new OpenLayers.Projection('EPSG:%d')\
-;\n" % settings.EPSG_DISPLAY_PROJECTION
- js += u"var epsg_projection = new OpenLayers.Projection('EPSG:%d');\n" % \
- settings.EPSG_PROJECTION
- js += u"var centerLonLat = new OpenLayers.LonLat(%f,\
-%f).transform(epsg_display_projection, epsg_projection);\n" % \
- settings.DEFAULT_CENTER
- js += u"var media_path = '%s';\n" % settings.MEDIA_URL
- js += u"var map_layer = %s;\n" % settings.MAP_LAYER
- js += u"var restricted_extent;\n"
-
- if area_name:
- js += u"var area_name='%s';\n" % area_name
- if settings.RESTRICTED_EXTENT:
- restricted_extent_str = [str(coord) \
- for coord in settings.RESTRICTED_EXTENT]
- js += u"restricted_extent = new OpenLayers.Bounds(%s);\n" %\
- ", ".join(restricted_extent_str)
- js = u"""<script type="text/javascript"><!--
-%s// !--></script>
-""" % js
- return js
-
-class TextareaWidget(forms.Textarea):
- """
- Manage the edition of a text using TinyMCE
- """
- class Media:
- js = ["%stiny_mce.js" % settings.TINYMCE_URL,
- "%stextareas.js" % settings.MEDIA_URL,]
-
-class PointChooserWidget(forms.TextInput):
- """
- Manage the edition of point on a map
- """
- class Media:
- css = {
- "all": URL_OSM_CSS + ["%sforms.css" % settings.MEDIA_URL,]
- }
- js = URL_OSM_JS + ["%sedit_map.js" % settings.MEDIA_URL,
- "%sbase.js" % settings.MEDIA_URL,]
-
- def render(self, name, value, attrs=None, area_name=''):
- '''
- Render a map and latitude, longitude information field
- '''
- val = '0'
- value_x, value_y = 0, 0
- if value:
- val = str(value)
- if hasattr(value, 'x') and hasattr(value, 'y'):
- value_x, value_y = value.x, value.y
- elif isinstance(value, unicode) and value.startswith('POINT('):
- try:
- value_x, value_y = value.split('(')[1][:-1].split(' ')
- value_x, value_y = float(value_x), float(value_y)
- except:
- value = None
- else:
- value = None
- tpl = getMapJS(area_name)
- tpl += u'<script src="%sedit_map.js"></script>\n' % settings.MEDIA_URL
- tpl += u"""<div id='map_edit'></div>
-<div id='live_lonlat'>
-<p><label for='live_latitude'>%s</label>\
-<input type='texte' name='live_latitude' id='live_latitude' size='8' \
-disabled='true' value='%f'/></p>
-<p><label for='live_longitude'>%s</label><input type='texte' \
-name='live_longitude' id='live_longitude' size='8' disabled='true' \
-value='%f'/></p>
-</div>
-<input type='hidden' name='%s' id='id_%s' value="%s"/>
-""" % (_("Latitude"), value_y, _("Longitude"), value_x, name, name, val)
- tpl += "<script type='text/javascript'><!--\n"
- tpl += "init();\n"
- if value:
- tpl += '''var mylonlat = new OpenLayers.LonLat(%f,%f);
-putMarker(mylonlat.transform(epsg_display_projection,
- map.getProjectionObject()).clone(), true);
-''' % (value_x, value_y)
- tpl += """// --></script>
-<hr class='spacer'/>
-"""
- return mark_safe(tpl)
-
-class PointField(models.PointField):
- '''
- Set the widget for the form field
- '''
- def formfield(self, **keys):
- defaults = {'widget': PointChooserWidget}
- keys.update(defaults)
- return super(PointField, self).formfield(**keys)
-
- def clean(self, value, instance=None):
- if len(value) != 2 and self.required:
- raise ValidationError(_("Invalid point"))
- return value
-
-class RouteChooserWidget(forms.TextInput):
- """
- Manage the edition of route on a map
- """
- class Media:
- css = {
- "all": URL_OSM_CSS + ["%sforms.css" % settings.MEDIA_URL,]
- }
- js = ["%sedit_route_map.js" % settings.MEDIA_URL,
- "%sbase.js" % settings.MEDIA_URL,] + URL_OSM_JS
-
- def render(self, name, value, attrs=None, area_name='', routefile_id=None):
- '''
- Render a map and latitude, longitude information field
- '''
- tpl = getMapJS(area_name)
- help_create = ''
- if not value:
- help_create = """<h3>%s</h3>
-<p>%s</p>
-<p>%s</p>
-<p>%s</p>
-<p>%s</p>
-<p>%s</p>""" % (_(u"Creation mode"),
-_(u"To start drawing the route click on the toggle button: \"Draw\"."),
-_(u"Then click on the map to begin the drawing."),
-_(u"You can add points by clicking again."),
-_(u"To finish the drawing double click. When the drawing is finished you can \
-edit it."),
-_(u"While creating to undo a drawing click again on the toggle button \"Stop \
-drawing\"."))
- help_modify = """<h3>%s</h3>
-<p>%s</p>
-<p>%s</p>
-<p>%s</p>""" % (_(u"Modification mode"),
-_(u"To move a point click on it and drag it to the desired position."),
-_(u"To delete a point move the mouse cursor over it and press the \"d\" or \
-\"Del\" key."),
-_(u"To add a point click in the middle of a segment and drag the new point to \
-the desired position"))
- tpl += u'<script src="%sedit_route_map.js"></script>\n' % \
- settings.MEDIA_URL
- if not value:
- # upload a file
- tpl += u"""<script type='text/javascript'><!--
- var error_msg = "%s";
-// --></script>
-""" % _(u"Give a name and set category before uploading a file.")
- tpl += u'<div id="upload"><a href="#" class="upload-button" '\
- u'onclick="uploadFile(error_msg);return false;">%s</a></div>' % (
- _(u"Upload a route file (GPX or KML)"))
- tpl += u"""\n<p id='draw-or'>%s</p>\n""" % _(u"or")
- tpl += u"""<div id='draw-label'><div id='draw-toggle-off' \
-onclick='toggleDraw();'>
-<a href='#' onclick='return false;'>%s</a></div>
-</div>
-<hr class='spacer'/>""" % (_(u"Start \"hand\" drawing"))
- if value:
- tpl += """
-<div id='map_edit'></div>"""
- else:
- tpl += """
-<div id='map_edit'>
- <div class='map_button'>
- <a href='#' id='button-move-map' class='toggle-button toggle-button-active' onclick='toggleDrawOff();return false;'>%s</a>
- <a href='#' id='button-draw-map' class='toggle-button toggle-button-inactive' onclick='toggleDrawOn();return false;'>%s</a></div>
- </div>""" % (_(u"Move on the map"), _(u"Draw"))
- tpl += '''
-<div class='help-route' id='help-route-create'>%s</div>''' % help_create
- style = ''
- if value:
- style = " style='display:block'"
- tpl += """
-<div class='help-route' id='help-route-modify'%s>%s</div>
-<hr class='spacer'/>
-<input type='hidden' name='%s' id='id_%s' value="%s"/>
-<input type='hidden' name='associated_file_id' id='id_associated_file_id' \
-value="%s"/>
-""" % (style, help_modify, name, name, value, routefile_id)
- tpl += "<script type='text/javascript'><!--\n"
- if not value:
- tpl += "document.getElementById('map_edit').style.display = 'None';"
- if value:
- tpl += "init();\n"
- val = value
- if type(value) == unicode:
- try:
- val = fromstr(value)
- except:
- pass
- if hasattr(val, 'json'):
- tpl += """
-var geometry='%s';
-initFeature(geometry);""" % val.json
- tpl += """
-// --></script>
-"""
- return mark_safe(tpl)
-
-class RouteField(models.LineStringField):
- '''
- Set the widget for the form field
- '''
- def formfield(self, **keys):
- defaults = {'widget': RouteChooserWidget}
- keys.update(defaults)
- return super(RouteField, self).formfield(**keys)
-
-class AreaWidget(forms.TextInput):
- """
- Manage the edition of an area on the map
- """
- class Media:
- css = {
- "all": URL_OSM_CSS + ["%sforms.css" % settings.MEDIA_URL,]
- }
- js = URL_OSM_JS + ["%sedit_area.js" % settings.MEDIA_URL,
- "%sbase.js" % settings.MEDIA_URL,]
-
- def render(self, name, value, attrs=None):
- """
- Render a map
- """
- upper_left_lat, upper_left_lon = 0, 0
- lower_right_lat, lower_right_lon = 0, 0
- if value:
- if len(value) == 2:
- upper_left = value[0]
- lower_right = value[1]
- if hasattr(upper_left, 'x') and hasattr(upper_left, 'y'):
- upper_left_lon, upper_left_lat = upper_left.x, upper_left.y
- if hasattr(lower_right, 'x') and hasattr(lower_right, 'y'):
- lower_right_lon, lower_right_lat = lower_right.x, \
- lower_right.y
- tpl = getMapJS()
- tpl += u"""<div id='map_edit'></div>
-<input type='hidden' name='upper_left_lat' id='upper_left_lat' value='%f'/>
-<input type='hidden' name='upper_left_lon' id='upper_left_lon' value='%f'/>
-<input type='hidden' name='lower_right_lat' id='lower_right_lat' value='%f'/>
-<input type='hidden' name='lower_right_lon' id='lower_right_lon' value='%f'/>
-""" % (upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon)
- tpl += """<script type='text/javascript'><!--
-init();"""
- if value:
- tpl += """var extent = new OpenLayers.Bounds(%f, %f, %f, %f);
-extent.transform(epsg_display_projection, epsg_projection);
-map.zoomToExtent(extent, true);""" % (upper_left_lon, upper_left_lat,
- lower_right_lon, lower_right_lat)
- tpl += """// --></script>
-<hr class='spacer'/>
-"""
- return mark_safe(tpl)
-
- def value_from_datadict(self, data, files, name):
- """
- Return the appropriate values
- """
- values = []
- for keys in (('upper_left_lon', 'upper_left_lat',),
- ('lower_right_lon', 'lower_right_lat')):
- value = []
- for key in keys:
- val = data.get(key, None)
- if not val:
- return []
- value.append(val)
- values.append(value)
- return values
-
-class AreaField(forms.MultiValueField):
- '''
- Set the widget for the form field
- '''
- widget = AreaWidget
-
- def compress(self, data_list):
- if not data_list:
- return None
- return data_list
-
-class MultiSelectWidget(forms.SelectMultiple):
- class Media:
- css = {'all': (
- settings.MEDIA_URL + 'jquery/bsmSelect/css/jquery.bsmselect.css',
- settings.MEDIA_URL + 'jquery/css/jquery.bsmselect.custom.css',
- )
- }
- js = (
- settings.MEDIA_URL + 'jquery/bsmSelect/js/jquery.bsmselect.js',
- settings.MEDIA_URL + 'jquery/bsmSelect/js/jquery.bsmselect.compatibility.js',
- )
-
- def render(self, name, value, attrs=None):
- rendered = super(MultiSelectWidget, self).render(name, value, attrs)
- return mark_safe(rendered + u'''<hr class='spacer'/><script type="text/javascript">
-$.bsmSelect.conf['title'] = "%(title)s";
-$("#id_%(name)s").bsmSelect({
- removeLabel: '<strong>X</strong>',
- containerClass: 'bsmContainer',
- listClass: 'bsmList-custom',
- listItemClass: 'bsmListItem-custom',
- listItemLabelClass: 'bsmListItemLabel-custom',
- removeClass: 'bsmListItemRemove-custom'
-});
-</script>''' % {'name':name, 'title':_("Select...")})
-
-class SelectMultipleField(models.ManyToManyField):
- '''
- Set the widget for the category field
- '''
- def formfield(self, **keys):
- self.help_text = ""
- defaults = {'widget': MultiSelectWidget}
- keys.update(defaults)
- return super(SelectMultipleField, self).formfield(**keys)
-