diff options
| 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 |
| commit | f88541bedcffdfaff485ef71287be88a58c745c2 (patch) | |
| tree | 87e9fcd59da5d687d2954ae99d9f511df55058f2 /chimere/main | |
| parent | 8ccdaf23128fbe563658ca0d9d74d2ffd831b68d (diff) | |
| download | Chimè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__.py | 0 | ||||
| -rw-r--r-- | chimere/main/actions.py | 43 | ||||
| -rw-r--r-- | chimere/main/admin.py | 142 | ||||
| -rw-r--r-- | chimere/main/forms.py | 331 | ||||
| -rw-r--r-- | chimere/main/models.py | 612 | ||||
| -rw-r--r-- | chimere/main/templatetags/__init__.py | 1 | ||||
| -rw-r--r-- | chimere/main/templatetags/sanitize.py | 31 | ||||
| -rw-r--r-- | chimere/main/templatetags/unlocalize_point.py | 16 | ||||
| -rw-r--r-- | chimere/main/views.py | 470 | ||||
| -rw-r--r-- | chimere/main/widgets.py | 354 |
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) - |
