diff options
| author | Étienne Loks <etienne.loks@peacefrogs.net> | 2012-10-14 16:55:22 +0200 |
|---|---|---|
| committer | Étienne Loks <etienne.loks@peacefrogs.net> | 2012-10-14 16:55:22 +0200 |
| commit | ea65e5512c236b81e7f4b8757521facadae4b3b8 (patch) | |
| tree | 739cdf40fb6a89de90c4189936d695288a82849f /chimere | |
| parent | 4b0f0777c434f5fa1366ca408c34d257d4833fad (diff) | |
| parent | a55f77a246f99764ff6289686f80825526654e2b (diff) | |
| download | Chimère-ea65e5512c236b81e7f4b8757521facadae4b3b8.tar.bz2 Chimère-ea65e5512c236b81e7f4b8757521facadae4b3b8.zip | |
Merge branch 'master' into saclay
Conflicts:
chimere/admin.py
chimere/fixtures/initial_data.json
chimere/forms.py
chimere/locale/fr/LC_MESSAGES/django.po
chimere/models.py
chimere/static/chimere/css/styles.css
chimere/templates/chimere/detail.html
chimere/templatetags/chimere_tags.py
chimere/views.py
chimere/widgets.py
Diffstat (limited to 'chimere')
34 files changed, 1998 insertions, 504 deletions
diff --git a/chimere/admin.py b/chimere/admin.py index ae6fbc4..cc7925c 100644 --- a/chimere/admin.py +++ b/chimere/admin.py @@ -25,6 +25,7 @@ import datetime from django import forms from django.conf import settings from django.contrib import admin +from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render_to_response from django.utils.translation import ugettext_lazy as _ @@ -35,28 +36,16 @@ except ImportError: pass from chimere.forms import MarkerAdminForm, RouteAdminForm, AreaAdminForm,\ - SubCategoryAdminForm, NewsAdminForm, CategoryAdminForm, ImporterAdminForm,\ - PageAdminForm + NewsAdminForm, CategoryAdminForm, ImporterAdminForm,\ + PageAdminForm, PictureFileAdminForm, MultimediaFileAdminForm from chimere.models import Category, Icon, SubCategory, Marker, \ - PropertyModel, News, Route, Area, ColorTheme, Color, RouteFile,\ - MultimediaType, MultimediaFile, PictureFile, Importer, Layer, AreaLayers,\ - PropertyModelChoice, MultimediaExtension, Page + PropertyModel, News, Route, Area, ColorTheme, Color, \ + MultimediaFile, PictureFile, Importer, Layer, AreaLayers,\ + PropertyModelChoice, MultimediaExtension, Page,\ + get_areas_for_user, get_users_by_area from chimere.utils import unicode_normalize, ShapefileManager, KMLManager,\ CSVManager -def get_areas_for_user(user): - """ - Getting subcats for a specific user - """ - perms = user.get_all_permissions() - areas = set() - prefix = 'chimere.change_area_' - for perm in perms: - if perm.startswith(prefix): - area = Area.objects.get(urn=perm[len(prefix):]) - areas.add(area) - return areas - def validate(modeladmin, request, queryset): for item in queryset: item.status = 'A' @@ -101,10 +90,16 @@ export_to_csv.short_description = _(u"Export to CSV") class PictureInline(admin.TabularInline): model = PictureFile extra = 1 + ordering = ('order',) + form = PictureFileAdminForm + readonly_fields = ('height', 'width') + exclude = ('thumbnailfile', 'thumbnailfile_height', 'thumbnailfile_width') class MultimediaInline(admin.TabularInline): model = MultimediaFile extra = 1 + ordering = ('order',) + form = MultimediaFileAdminForm class MarkerAdmin(admin.ModelAdmin): """ @@ -125,13 +120,14 @@ class MarkerAdmin(admin.ModelAdmin): 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]) + contained = Q() + for area in areas: + contained = contained | area.getIncludeMarker() + qs = qs.filter(contained) ordering = self.ordering or () if ordering: qs = qs.order_by(*ordering) - return qs + return qs.distinct() class RouteAdmin(admin.ModelAdmin): """ @@ -143,16 +139,16 @@ class RouteAdmin(admin.ModelAdmin): exclude = ['height', 'width'] form = RouteAdminForm readonly_fields = ('associated_file',) - actions = [validate] + actions = [validate, export_to_kml, export_to_shapefile, export_to_csv] 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='"chimere_route".route') for area in areas]) - qs = qs.extra(where=[in_areas]) + contained = Q() + for area in areas: + contained = contained | area.getIncludeRoute() + qs = qs.filter(contained) ordering = self.ordering or () if ordering: qs = qs.order_by(*ordering) @@ -239,15 +235,6 @@ class ColorThemeAdmin(admin.ModelAdmin): class IconAdmin(admin.ModelAdmin): exclude = ['height', 'width'] -class MultimediaTypeAdmin(admin.ModelAdmin): - search_fields = ("name",) - list_display = ('name', 'media_type', 'mime_type', 'iframe', 'available') - list_filter = ('media_type', 'available') - -class MultimediaExtensionAdmin(admin.ModelAdmin): - list_display = ('name', 'multimedia_type') - list_filter = ('multimedia_type',) - class PropertyModelChoiceInline(admin.TabularInline): model = PropertyModelChoice extra = 1 @@ -264,6 +251,4 @@ admin.site.register(Route, RouteAdmin) admin.site.register(PropertyModel, PropertyModelAdmin) admin.site.register(Area, AreaAdmin) admin.site.register(ColorTheme, ColorThemeAdmin) -admin.site.register(MultimediaExtension, MultimediaExtensionAdmin) -admin.site.register(MultimediaType, MultimediaTypeAdmin) admin.site.register(Layer) diff --git a/chimere/feeds.py b/chimere/feeds.py index c4ee7a5..100dd6b 100644 --- a/chimere/feeds.py +++ b/chimere/feeds.py @@ -21,7 +21,8 @@ from django.conf import settings from django.contrib.gis.geos import * -from django.contrib.syndication.views import Feed, FeedDoesNotExist +from django.contrib.gis.feeds import Feed +from django.contrib.syndication.views import FeedDoesNotExist from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.utils.translation import ugettext as _ @@ -53,6 +54,9 @@ class BaseFeed(Feed): def description(self, obj): return "" + def item_geometry(self, obj): + return obj.point + class LatestPOIsByCategory(BaseFeed): ''' Last Points of interests by category in Feeds diff --git a/chimere/fixtures/default_data.json b/chimere/fixtures/default_data.json new file mode 100644 index 0000000..56df4c3 --- /dev/null +++ b/chimere/fixtures/default_data.json @@ -0,0 +1,69 @@ +[ + { + "pk": 1, + "model": "chimere.colortheme", + "fields": { + "name": "Blue" + } + }, + { + "pk": 1, + "model": "chimere.color", + "fields": { + "code": "0000FF", + "color_theme": 1, + "order": 10 + } + }, + { + "pk": 2, + "model": "chimere.color", + "fields": { + "code": "2222FF", + "color_theme": 1, + "order": 20 + } + }, + { + "pk": 3, + "model": "chimere.color", + "fields": { + "code": "4444FF", + "color_theme": 1, + "order": 30 + } + }, + { + "pk": 1, + "model": "chimere.category", + "fields": { + "available": true, + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc blandit porta eros, quis varius orci luctus nec. Suspendisse tempor sagittis tortor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus imperdiet consequat dolor. Etiam risus orci, auctor nec hendrerit ut, congue at ante. Aliquam et accumsan neque. Aliquam ac massa felis, ac porttitor nunc. Curabitur blandit odio id enim sodales blandit. Curabitur eleifend commodo lorem a feugiat. Nam at quam semper justo ultricies tempor.\r\n", + "name": "Default category", + "order": 10 + } + }, + { + "pk": 1, + "model": "chimere.icon", + "fields": { + "width": 21, + "image": "icons/marker.png", + "name": "Default icon", + "height": 25 + } + }, + { + "pk": 1, + "model": "chimere.subcategory", + "fields": { + "category": 1, + "available": true, + "name": "Default subcategory", + "item_type": "M", + "color_theme": null, + "order": 10, + "icon": 1 + } + } +] diff --git a/chimere/fixtures/initial_data.json b/chimere/fixtures/initial_data.json index 71f4972..20347a3 100644 --- a/chimere/fixtures/initial_data.json +++ b/chimere/fixtures/initial_data.json @@ -1,39 +1,5 @@ [ { - "pk": 1, - "model": "chimere.colortheme", - "fields": { - "name": "Blue" - } - }, - { - "pk": 1, - "model": "chimere.color", - "fields": { - "code": "0000FF", - "color_theme": 1, - "order": 10 - } - }, - { - "pk": 2, - "model": "chimere.color", - "fields": { - "code": "2222FF", - "color_theme": 1, - "order": 20 - } - }, - { - "pk": 3, - "model": "chimere.color", - "fields": { - "code": "4444FF", - "color_theme": 1, - "order": 30 - } - }, - { "pk": 7, "model": "chimere.multimediatype", "fields": { @@ -320,5 +286,49 @@ "layer_code": "new OpenLayers.Layer.MapQuestOSM()", "name": "OSM - MapQuest" } + }, + { + "pk": 1, + "model": "auth.group", + "fields": { + "name": "Application administrator", + "permissions": [ + 67, + 68, + 40, + 41, + 42, + 37, + 38, + 39, + 34, + 35, + 36, + 43, + 44, + 45, + 49, + 50, + 51, + 55, + 56, + 57, + 28, + 29, + 30, + 58, + 59, + 60, + 64, + 65, + 66, + 61, + 62, + 63, + 46, + 47, + 48 + ] + } } ] diff --git a/chimere/forms.py b/chimere/forms.py index b584f4f..8ce9ad2 100644 --- a/chimere/forms.py +++ b/chimere/forms.py @@ -36,7 +36,8 @@ from chimere.models import Marker, Route, PropertyModel, Property, Area,\ PictureFile, Importer, PropertyModelChoice, IFRAME_LINKS, \ MultimediaExtension, Page from chimere.widgets import AreaField, PointField, TextareaWidget, \ - FullTextareaWidget, DatePickerWidget, ButtonSelectWidget, NominatimWidget + FullTextareaWidget, DatePickerWidget, ButtonSelectWidget, NominatimWidget, \ + TextareaAdminWidget from datetime import timedelta, datetime, tzinfo @@ -113,7 +114,7 @@ class NewsAdminForm(forms.ModelForm): """ Main form for news """ - content = forms.CharField(widget=FullTextareaWidget) + content = forms.CharField(widget=TextareaAdminWidget) class Meta: model = News @@ -125,11 +126,31 @@ class ImporterAdminForm(forms.ModelForm): 'filtr': forms.TextInput(attrs={'size': 80}), } + def clean(self): + ''' + Verify that only one type of source is provided + Verify that shapefiles are zipped + ''' + if self.cleaned_data['importer_type'] == 'SHP' and \ + not self.cleaned_data['zipped']: + raise forms.ValidationError(_(u"Shapefiles must be provided in a "\ + u"zipped archive.")) + if self.cleaned_data['source'] and \ + self.cleaned_data['source_file']: + raise forms.ValidationError(_(u"You have to set \"source\" or " + u"\"source file\" but not both.")) + if not self.cleaned_data['source'] and \ + not self.cleaned_data['source_file'] and \ + self.cleaned_data['importer_type'] != 'OSM': + raise forms.ValidationError(_(u"You have to set \"source\" or " + u"\"source file\".")) + return self.cleaned_data + class CategoryAdminForm(forms.ModelForm): """ Main form for categories """ - description = forms.CharField(widget=TextareaWidget, required=False) + description = forms.CharField(widget=TextareaAdminWidget, required=False) class Media: js = list(settings.JQUERY_JS_URLS) + [ '%schimere/js/menu-sort.js' % settings.STATIC_URL, @@ -141,7 +162,7 @@ class MarkerAdminFormBase(forms.ModelForm): """ Main form for marker """ - description = forms.CharField(widget=TextareaWidget, required=False) + description = forms.CharField(widget=TextareaAdminWidget, required=False) class Meta: model = Marker @@ -246,6 +267,7 @@ class MarkerForm(MarkerBaseForm): """ ref_pk = forms.IntegerField(label=u" ", widget=forms.HiddenInput(), required=False) + description = forms.CharField(widget=TextareaWidget, required=False) class Meta: model = Marker exclude = ('status',) @@ -348,7 +370,6 @@ class RouteForm(RouteAdminForm): new_marker.saveProperties(properties) return new_route - class BaseFileForm(forms.ModelForm): id = forms.IntegerField(label=u"", widget=forms.HiddenInput(), required=False) @@ -383,6 +404,14 @@ class BaseFileForm(forms.ModelForm): else: instance = self._meta.model.objects.create(**self.cleaned_data) +class MultimediaFileAdminForm(forms.ModelForm): + class Meta: + model = MultimediaFile + class Media: + js = list(settings.JQUERY_JS_URLS) + [ + '%schimere/js/menu-sort.js' % settings.STATIC_URL, + ] + class MultimediaFileForm(BaseFileForm): """ Form for a multimedia file @@ -425,6 +454,14 @@ class MultimediaFileForm(BaseFileForm): MultimediaFileFormSet = formset_factory(MultimediaFileForm, can_delete=True) +class PictureFileAdminForm(forms.ModelForm): + class Meta: + model = PictureFile + class Media: + js = list(settings.JQUERY_JS_URLS) + [ + '%schimere/js/menu-sort.js' % settings.STATIC_URL, + ] + class PictureFileForm(BaseFileForm): """ Form for a picture file @@ -459,7 +496,8 @@ class AreaAdminForm(forms.ModelForm): Admin page to create an area """ area = AreaField(label=_("Area"), fields=(PointField(), PointField())) - welcome_message = forms.CharField(widget=TextareaWidget, required=False) + welcome_message = forms.CharField(widget=TextareaAdminWidget, + required=False) class Meta: model = Area diff --git a/chimere/locale/fr/LC_MESSAGES/django.po b/chimere/locale/fr/LC_MESSAGES/django.po index 9973efb..5956c20 100644 --- a/chimere/locale/fr/LC_MESSAGES/django.po +++ b/chimere/locale/fr/LC_MESSAGES/django.po @@ -7,17 +7,17 @@ msgid "" msgstr "" "Project-Id-Version: 2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-10-02 19:08+0200\n" +"POT-Creation-Date: 2012-10-14 16:46+0200\n" "Last-Translator: Étienne Loks <etienne.loks@peacefrogs.net>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: __init__.py:8 models.py:677 +#: __init__.py:8 models.py:734 msgid "Multimedia files" msgstr "Fichiers multimedias" -#: __init__.py:9 models.py:733 +#: __init__.py:9 models.py:790 msgid "Picture files" msgstr "Fichiers d'image" @@ -45,510 +45,545 @@ msgstr "Flux RSS" msgid "Contact us" msgstr "Nous contacter" -#: admin.py:64 templates/chimere/feeds/rss.html:69 +#: admin.py:53 templates/chimere/feeds/rss.html:69 msgid "Validate" msgstr "Valider" -#: admin.py:75 +#: admin.py:64 msgid "Export to KML" msgstr "Exporter en KML" -#: admin.py:89 +#: admin.py:78 msgid "Export to Shapefile" msgstr "Exporter en Shapefile" -#: admin.py:99 +#: admin.py:88 msgid "Export to CSV" msgstr "Exporter en CSV" -#: admin.py:182 +#: admin.py:174 msgid "Import" msgstr "Import" -#: admin.py:188 +#: admin.py:180 msgid "Cancel import" msgstr "Annuler l'import" -#: admin.py:194 +#: admin.py:186 msgid "Cancel export" msgstr "Annuler l'export" -#: admin.py:202 +#: admin.py:194 msgid "Export to osm" msgstr "Exporter vers osm" -#: feeds.py:124 feeds.py:211 +#: feeds.py:128 feeds.py:215 msgid "Last points of interest" msgstr "Derniers points d'intérêt" -#: feeds.py:130 +#: feeds.py:134 msgid "Latest points of interest from " msgstr "Nouveaux points d'intérêt de " -#: feeds.py:176 +#: feeds.py:180 msgid "Last points of interest by area" msgstr "Nouveaux points d'intérêt par zone" -#: forms.py:82 +#: forms.py:83 msgid "New submission for" msgstr "Nouvelle proposition pour" -#: forms.py:83 +#: forms.py:84 #, python-format msgid "The new item \"%s\" has been submited in the category: " msgstr "Le nouvel élément « %s » a été proposé dans la catégorie : " -#: forms.py:85 +#: forms.py:86 msgid "To valid, precise or unvalid this item: " msgstr "Pour valider, préciser ou rejeter cet élément : " -#: forms.py:95 +#: forms.py:96 msgid "Email (optional)" msgstr "Courriel (optionnel) " -#: forms.py:96 +#: forms.py:97 msgid "Object" msgstr "Objet" -#: forms.py:183 +#: forms.py:136 +msgid "Shapefiles must be provided in a zipped archive." +msgstr "" +"Les fichiers Shapefiles doivent être fournis regroupés dans une archive zip." + +#: forms.py:140 +msgid "You have to set \"source\" or \"source file\" but not both." +msgstr "" +"Vous devez spécifier le champ « Source » ou « Fichier source » mais pas les " +"deux." + +#: forms.py:145 +msgid "You have to set \"source\" or \"source file\"." +msgstr "Vous devez spécifier le champ « Source » ou « Fichier source »." + +#: forms.py:204 msgid "End date has been set with no start date" msgstr "Une date de fin a été donnée sans date de début" -#: forms.py:194 +#: forms.py:215 msgid "This field is mandatory for the selected categories" msgstr "Ce champ est obligatoire pour les catégories sélectionnées" -#: forms.py:441 +#: forms.py:478 msgid "File" msgstr "Fichier" -#: forms.py:447 +#: forms.py:484 msgid "Bad file format: this must be a GPX or KML file" msgstr "Mauvais format de fichier : KML et GPX sont supportés" -#: forms.py:452 models.py:50 models.py:98 models.py:158 models.py:179 -#: models.py:192 models.py:206 models.py:324 models.py:611 models.py:667 -#: models.py:710 models.py:826 models.py:1119 models.py:1131 models.py:1216 -#: utils.py:444 templates/chimere/edit.html:39 +#: forms.py:489 models.py:53 models.py:101 models.py:163 models.py:184 +#: models.py:197 models.py:212 models.py:352 models.py:668 models.py:724 +#: models.py:767 models.py:883 models.py:1199 models.py:1211 models.py:1384 +#: utils.py:454 templates/chimere/edit.html:39 #: templates/chimere/edit_route.html:36 #: templates/chimere/blocks/alternate_multimedia.html:39 msgid "Name" msgstr "Nom" -#: forms.py:461 models.py:1168 +#: forms.py:498 models.py:1248 msgid "Area" msgstr "Zone" -#: forms.py:520 +#: forms.py:558 msgid "Start" msgstr "Départ" -#: forms.py:521 +#: forms.py:559 msgid "Finish" msgstr "Arrivée :" -#: forms.py:522 +#: forms.py:560 msgid "Speed" msgstr "Vitesse" -#: models.py:51 +#: models.py:54 msgid "Mnemonic" msgstr "Mnémonique" -#: models.py:53 models.py:99 models.py:180 models.py:207 models.py:335 -#: models.py:615 models.py:1137 models.py:1218 models.py:1259 +#: models.py:56 models.py:102 models.py:185 models.py:213 models.py:363 +#: models.py:672 models.py:1217 models.py:1386 models.py:1427 msgid "Available" msgstr "Disponible" -#: models.py:54 models.py:168 models.py:181 models.py:215 models.py:669 -#: models.py:725 models.py:1136 models.py:1205 models.py:1217 +#: models.py:57 models.py:173 models.py:186 models.py:223 models.py:726 +#: models.py:782 models.py:1216 models.py:1373 models.py:1385 msgid "Order" msgstr "Ordre" -#: models.py:55 +#: models.py:58 msgid "Template path" msgstr "Chemin du patron" -#: models.py:62 models.py:63 +#: models.py:65 models.py:66 msgid "Page" msgstr "Page" -#: models.py:100 models.py:401 +#: models.py:103 models.py:443 msgid "Is front page" msgstr "Est en page principale" -#: models.py:102 models.py:1227 +#: models.py:105 models.py:1395 msgid "Date" msgstr "Date" -#: models.py:104 models.py:668 +#: models.py:107 models.py:725 msgid "Url" msgstr "Url" -#: models.py:109 models.py:110 templates/chimere/blocks/news.html:3 +#: models.py:108 +msgid "Associated areas" +msgstr "Zones associées" + +#: models.py:114 models.py:115 templates/chimere/blocks/news.html:3 #: templates/chimere/blocks/news.html:5 msgid "News" msgstr "Nouvelle" -#: models.py:119 +#: models.py:124 msgid "Parameters" msgstr "Paramètres" -#: models.py:123 +#: models.py:128 msgid "TinyUrl" msgstr "Mini-url" -#: models.py:162 models.py:169 models.py:213 +#: models.py:167 models.py:174 models.py:221 msgid "Color theme" msgstr "Thème de couleur" -#: models.py:167 +#: models.py:172 msgid "Code" msgstr "Code" -#: models.py:174 +#: models.py:179 msgid "Color" msgstr "Couleur" -#: models.py:187 models.py:205 templates/chimere/main_map.html:13 +#: models.py:192 models.py:210 templates/chimere/main_map.html:13 msgid "Category" msgstr "Catégorie" -#: models.py:193 models.py:607 models.py:711 models.py:891 +#: models.py:198 models.py:664 models.py:768 models.py:949 #: templates/chimere/blocks/alternate_multimedia.html:43 msgid "Image" msgstr "Image" -#: models.py:195 models.py:713 models.py:893 +#: models.py:200 models.py:770 models.py:951 msgid "Height" msgstr "Hauteur" -#: models.py:196 models.py:714 models.py:894 +#: models.py:201 models.py:771 models.py:952 msgid "Width" msgstr "Largeur" -#: models.py:200 models.py:210 +#: models.py:205 models.py:218 msgid "Icon" msgstr "Icône" -#: models.py:208 +#: models.py:214 msgid "Available for submission" msgstr "Disponible pour soumission" -#: models.py:211 +#: models.py:216 +msgid "Displayed in the layer menu" +msgstr "Apparaît dans le menu des couches ?" + +#: models.py:219 msgid "Hover icon" msgstr "Icône en survol" -#: models.py:216 +#: models.py:224 msgid "Is dated" msgstr "Est daté" -#: models.py:217 +#: models.py:225 msgid "Marker" msgstr "Point d'intérêt" -#: models.py:218 models.py:887 models.py:902 +#: models.py:226 models.py:945 models.py:960 #: templates/chimere/edit_route.html:27 msgid "Route" msgstr "Trajet" -#: models.py:219 +#: models.py:227 msgid "Both" msgstr "Mixte" -#: models.py:220 +#: models.py:228 msgid "Item type" msgstr "Type d'élément" -#: models.py:226 +#: models.py:234 msgid "Sub-category" msgstr "Sous-catégorie" -#: models.py:227 +#: models.py:235 msgid "Sub-categories" msgstr "Sous-catégories" -#: models.py:297 +#: models.py:311 msgid "Importer type" msgstr "Type d'import" -#: models.py:300 models.py:346 +#: models.py:314 models.py:374 msgid "Source" msgstr "Source" -#: models.py:302 +#: models.py:316 +msgid "Source file" +msgstr "Fichier source" + +#: models.py:318 msgid "Filter" msgstr "Filtre" -#: models.py:304 +#: models.py:320 msgid "Name by default" msgstr "Nom par défaut" -#: models.py:307 -msgid "Associated subcategories" -msgstr "Sous-catégories associées" - -#: models.py:308 utils.py:447 -msgid "State" -msgstr "État" - -#: models.py:310 +#: models.py:322 msgid "SRID" msgstr "SRID" -#: models.py:311 +#: models.py:323 msgid "Zipped file" msgstr "Fichier zippé" -#: models.py:314 +#: models.py:324 models.py:380 +msgid "Origin" +msgstr "Origine" + +#: models.py:326 models.py:382 +msgid "License" +msgstr "Licence" + +#: models.py:329 +msgid "Associated subcategories" +msgstr "Sous-catégories associées" + +#: models.py:330 utils.py:458 +msgid "State" +msgstr "État" + +#: models.py:334 msgid "Importer" msgstr "Import" -#: models.py:326 +#: models.py:354 msgid "Submitter session key" msgstr "Clé de session du demandeur" -#: models.py:328 +#: models.py:356 msgid "Submitter name or nickname" msgstr "Nom ou pseudo du demandeur" -#: models.py:330 +#: models.py:358 msgid "Submitter email" msgstr "Courriel du demandeur" -#: models.py:332 +#: models.py:360 msgid "Submitter comment" msgstr "Commentaire du demandeur" -#: models.py:334 +#: models.py:362 msgid "Submited" msgstr "Soumis" -#: models.py:336 +#: models.py:364 msgid "Modified" msgstr "Modifié" -#: models.py:337 +#: models.py:365 msgid "Disabled" msgstr "Désactivé" -#: models.py:338 +#: models.py:366 msgid "Imported" msgstr "Importé" -#: models.py:339 +#: models.py:367 msgid "Excluded" msgstr "Exclu" -#: models.py:341 +#: models.py:369 msgid "Status" msgstr "État" -#: models.py:342 +#: models.py:370 msgid "Import key" msgstr "Clé d'import" -#: models.py:344 +#: models.py:372 msgid "Import version" msgstr "Version de l'import" -#: models.py:348 +#: models.py:376 msgid "Modified since last import" msgstr "Modifié depuis le dernier import" -#: models.py:350 +#: models.py:378 msgid "Not to be imported inside OSM" msgstr "Ne pas importer dans OSM" -#: models.py:353 templates/chimere/edit.html:56 +#: models.py:385 templates/chimere/edit.html:56 #: templates/chimere/edit_route.html:52 msgid "Start date" msgstr "Date de début" -#: models.py:354 +#: models.py:386 msgid "Not mandatory. Set it for dated item such as event. Format YYYY-MM-DD" msgstr "" "Optionnel. Précisez ce champ pour les éléments datés comme un événement. " "Format du champ : AAAA-MM-JJ" -#: models.py:356 templates/chimere/edit.html:62 +#: models.py:388 templates/chimere/edit.html:62 #: templates/chimere/edit_route.html:58 msgid "End date" msgstr "Date de fin" -#: models.py:357 +#: models.py:389 msgid "" "Not mandatory. Set it only if you have a multi-day event. Format YYYY-MM-DD" msgstr "" "Optionnel. Précisez ce champ seulement pour des événements durant plusieurs " "jours. Format du champ : AAAA-MM-JJ" -#: models.py:393 +#: models.py:435 msgid "Reference marker" msgstr "Point d'intérêt de référence" -#: models.py:394 utils.py:449 utils.py:450 +#: models.py:436 utils.py:460 msgid "Localisation" msgstr "Localisation" -#: models.py:396 +#: models.py:438 msgid "Available Date" msgstr "Date de mise en disponibilité" -#: models.py:400 utils.py:448 templates/chimere/edit.html:49 +#: models.py:442 utils.py:459 templates/chimere/edit.html:49 #: templates/chimere/edit_route.html:46 msgid "Description" msgstr "Description" -#: models.py:461 models.py:1269 +#: models.py:506 models.py:1437 msgid "Point of interest" msgstr "Point d'intérêt" -#: models.py:605 +#: models.py:662 msgid "Audio" msgstr "Audio" -#: models.py:606 +#: models.py:663 msgid "Video" msgstr "Vidéo" -#: models.py:608 +#: models.py:665 msgid "Other" msgstr "Autre" -#: models.py:609 +#: models.py:666 msgid "Media type" msgstr "Type de media" -#: models.py:612 +#: models.py:669 msgid "Mime type" msgstr "Type mime" -#: models.py:614 +#: models.py:671 msgid "Inside an iframe" msgstr "À l'intérieur d'un iframe" -#: models.py:618 +#: models.py:675 msgid "Multimedia type" msgstr "Type de multimedia" -#: models.py:619 +#: models.py:676 msgid "Multimedia types" msgstr "Types de multimedia" -#: models.py:654 +#: models.py:711 msgid "Extension name" msgstr "Nom de l'extension" -#: models.py:656 +#: models.py:713 msgid "Associated multimedia type" msgstr "Type de multimedia associé" -#: models.py:660 +#: models.py:717 msgid "Multimedia extension" msgstr "Extension de fichier multimedia" -#: models.py:661 +#: models.py:718 msgid "Multimedia extensions" msgstr "Extensions de fichier multimedia" -#: models.py:671 models.py:715 +#: models.py:728 models.py:772 msgid "Display inside the description?" msgstr "Apparaît dans la description ?" -#: models.py:676 +#: models.py:733 msgid "Multimedia file" msgstr "Fichier multimedia" -#: models.py:717 +#: models.py:774 msgid "Thumbnail" msgstr "Miniature" -#: models.py:721 +#: models.py:778 msgid "Thumbnail height" msgstr "Hauteur de la miniature" -#: models.py:723 +#: models.py:780 msgid "Thumbnail width" msgstr "Largeur de la miniature" -#: models.py:732 +#: models.py:789 msgid "Picture file" msgstr "Fichier d'image" -#: models.py:827 +#: models.py:884 msgid "Raw file (gpx or kml)" msgstr "Fichier brut (gpx ou kml)" -#: models.py:828 +#: models.py:886 msgid "Simplified file" msgstr "Fichier simplifié" -#: models.py:830 +#: models.py:888 msgid "KML" msgstr "KML" -#: models.py:830 +#: models.py:888 msgid "GPX" msgstr "GPX" -#: models.py:835 +#: models.py:893 msgid "Route file" msgstr "Fichier de trajet" -#: models.py:836 +#: models.py:894 msgid "Route files" msgstr "Fichiers de trajet" -#: models.py:886 +#: models.py:944 msgid "Reference route" msgstr "Trajet de référence" -#: models.py:890 +#: models.py:948 msgid "Associated file" msgstr "Fichier associé" -#: models.py:1120 +#: models.py:1200 msgid "Layer code" msgstr "Code pour la couche" -#: models.py:1126 +#: models.py:1206 msgid "Layer" msgstr "Couche" -#: models.py:1132 +#: models.py:1212 msgid "Area urn" msgstr "Urn de la zone" -#: models.py:1134 templates/chimere/blocks/welcome.html:3 +#: models.py:1214 templates/chimere/blocks/welcome.html:3 msgid "Welcome message" msgstr "Message d'accueil" -#: models.py:1138 +#: models.py:1218 msgid "Upper left corner" msgstr "Coin en haut à gauche" -#: models.py:1140 +#: models.py:1220 msgid "Lower right corner" msgstr "Coin en bas à droite" -#: models.py:1142 +#: models.py:1222 msgid "Default area" msgstr "Zone par défaut" -#: models.py:1143 +#: models.py:1223 msgid "Only one area is set by default" msgstr "Seule une zone est définie par défaut" -#: models.py:1147 +#: models.py:1227 msgid "Sub-categories checked by default" msgstr "Sous-catégories cochées par défaut" -#: models.py:1149 +#: models.py:1229 msgid "Sub-categories dynamicaly displayed" msgstr "Sous-categories affichées dynamiquement" -#: models.py:1150 +#: models.py:1230 msgid "" "If checked, categories are only displayed in the menu if they are available " "on the current extent." @@ -556,76 +591,76 @@ msgstr "" "Si coché, les catégories sont disponibles sur le menu seulement si elles " "apparaissent sur la zone affichée." -#: models.py:1154 models.py:1221 +#: models.py:1234 models.py:1389 msgid "Restricted to theses sub-categories" msgstr "Restreindre à ces sous-categories" -#: models.py:1155 +#: models.py:1235 msgid "If no sub-category is set all sub-categories are available" msgstr "" "Si aucune sous-catégorie n'est définie toutes les sous-catégories sont " "disponibles" -#: models.py:1157 +#: models.py:1237 msgid "Link to an external CSS" msgstr "Lien vers une feuille de style externe" -#: models.py:1159 +#: models.py:1239 msgid "Restrict to the area extent" msgstr "Restreindre à l'étendue de la zone" -#: models.py:1206 +#: models.py:1374 widgets.py:86 msgid "Default layer" msgstr "Couche par défaut" -#: models.py:1210 models.py:1211 +#: models.py:1378 models.py:1379 msgid "Layers" msgstr "Couches" -#: models.py:1219 +#: models.py:1387 msgid "Mandatory" msgstr "Obligatoire" -#: models.py:1222 +#: models.py:1390 msgid "" "If no sub-category is set all the property applies to all sub-categories" msgstr "" "Si aucune sous-catégorie n'est précisée, cette propriété est disponible pour " "toutes les sous-catégories" -#: models.py:1224 +#: models.py:1392 msgid "Text" msgstr "Texte" -#: models.py:1225 +#: models.py:1393 msgid "Long text" msgstr "Texte long" -#: models.py:1226 +#: models.py:1394 msgid "Password" msgstr "Mot de passe" -#: models.py:1228 +#: models.py:1396 msgid "Choices" msgstr "Choix" -#: models.py:1236 +#: models.py:1404 msgid "Type" msgstr "Type" -#: models.py:1241 models.py:1257 models.py:1271 +#: models.py:1409 models.py:1425 models.py:1439 msgid "Property model" msgstr "Modèle de propriété" -#: models.py:1258 models.py:1272 +#: models.py:1426 models.py:1440 msgid "Value" msgstr "Valeur" -#: models.py:1264 +#: models.py:1432 msgid "Model property choice" msgstr "Choix pour les modèles de propriété" -#: models.py:1283 +#: models.py:1451 msgid "Property" msgstr "Propriété" @@ -679,14 +714,18 @@ msgstr "Export échoué" msgid "Export canceled" msgstr "Export annulé" -#: utils.py:118 utils.py:166 +#: utils.py:123 utils.py:172 msgid "Bad zip file" msgstr "Mauvais fichier zip" -#: utils.py:169 +#: utils.py:175 msgid "Missing file(s) inside the zip file" msgstr "Fichier(s) manquant(s) dans l'archive zip" +#: utils.py:216 +msgid "Bad XML file" +msgstr "Mauvais fichier XML" + #: utils.py:301 msgid "Error while reading the data source." msgstr "Erreur lors de la lecture de la source." @@ -697,28 +736,40 @@ msgstr "" "Les types des éléments géographiques de ce fichier Shapefile ne sont pas " "gérés par Chimère." -#: utils.py:393 +#: utils.py:356 +msgid "Bad Shapefile" +msgstr "Mauvais fichier Shapefile" + +#: utils.py:398 msgid "Could not create file!" msgstr "Ne peut pas créer le fichier !" -#: utils.py:404 +#: utils.py:409 msgid "Failed to create field" msgstr "Ne peut pas créer un champ" -#: utils.py:445 templates/chimere/edit.html:44 +#: utils.py:455 templates/chimere/edit.html:44 #: templates/chimere/edit_route.html:41 msgid "Categories" msgstr "Catégories" -#: utils.py:509 +#: utils.py:488 +msgid "Invalid CSV format" +msgstr "Fichier CSV non valide" + +#: utils.py:563 +msgid "RSS feed is not well formed" +msgstr "Flux RSS non valide" + +#: utils.py:633 msgid "Nothing to import" msgstr "Rien à importer" -#: utils.py:589 +#: utils.py:721 msgid "New items imported - validate them before exporting" msgstr "Nouveaux éléments importés - valider ceux-ci avant d'exporter" -#: utils.py:591 +#: utils.py:723 msgid "" "There are items from a former import not yet validated - validate them " "before exporting" @@ -726,15 +777,15 @@ msgstr "" "Il y a des éléments d'un import précédent pas encore validé - Validez les " "avant d'exporter" -#: utils.py:601 +#: utils.py:733 msgid "Bad param" msgstr "Mauvais paramètre" -#: utils.py:616 +#: utils.py:748 msgid "No non ambigious tag is defined in the XAPI request" msgstr "Aucun « tag » non ambigu n'est défini dans la requête XAPI" -#: utils.py:618 +#: utils.py:750 msgid "" "No bounding box is defined in the XAPI request.If you are sure to manage the " "entire planet set the bounding box to -180,-90,180,90" @@ -747,15 +798,15 @@ msgstr "" msgid "There are missing field(s) and/or errors in the submited form." msgstr "Il y a des champs manquants ou des erreurs dans ce formulaire." -#: views.py:350 +#: views.py:353 msgid "Bad file. Please check it with an external software." msgstr "Fichier incohérent. Merci de le vérifier avec un logiciel externe." -#: views.py:482 +#: views.py:465 msgid "Comments/request on the map" msgstr "Commentaires/requètes sur la carte" -#: views.py:485 +#: views.py:468 msgid "" "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." @@ -764,52 +815,52 @@ msgstr "" "laissé votre courriel vous serez peut-être contacté bientôt pour plus de " "détails." -#: views.py:489 +#: views.py:472 msgid "Temporary error. Renew your message later." msgstr "Erreur temporaire. Réenvoyez votre message plus tard." -#: views.py:641 +#: views.py:624 msgid "No category available in this area." msgstr "Pas de catégorie disponible sur cette zone." -#: views.py:785 +#: views.py:768 msgid "Incorrect choice in the list" msgstr "Choix incorrect dans la liste" -#: widgets.py:229 +#: widgets.py:245 msgid "Street, City, Country" msgstr "Rue, Commune, Pays" -#: widgets.py:295 +#: widgets.py:312 msgid "Latitude" msgstr "Latitude" -#: widgets.py:295 +#: widgets.py:312 msgid "Longitude" msgstr "Longitude" -#: widgets.py:320 +#: widgets.py:337 msgid "Invalid point" msgstr "Point invalide" -#: widgets.py:370 +#: widgets.py:390 msgid "Creation mode" msgstr "Mode création" -#: widgets.py:371 +#: widgets.py:391 msgid "To start drawing the route click on the toggle button: \"Draw\"." msgstr "" "Pour commencer le dessin cliquez sur le bouton : « Tracer »." -#: widgets.py:373 +#: widgets.py:393 msgid "Then click on the map to begin the drawing." msgstr "Puis cliquez sur la carte pour commencer le dessin." -#: widgets.py:374 +#: widgets.py:394 msgid "You can add points by clicking again." msgstr "Vous pouvez ajouter des points en cliquant de nouveau." -#: widgets.py:375 +#: widgets.py:395 msgid "" "To finish the drawing double click. When the drawing is finished you can " "edit it." @@ -817,7 +868,7 @@ msgstr "" "Pour finir le tracé double-cliquez. Quand le tracé est fini vous pouvez " "toujours l'éditer." -#: widgets.py:377 +#: widgets.py:397 msgid "" "While creating to undo a drawing click again on the toggle button \"Stop " "drawing\"." @@ -825,17 +876,17 @@ msgstr "" "En mode création vous pouvez annuler un tracé en appuyant sur le bouton " "« Arrêter le tracé »." -#: widgets.py:382 +#: widgets.py:402 msgid "Modification mode" msgstr "Mode modification" -#: widgets.py:383 +#: widgets.py:403 msgid "To move a point click on it and drag it to the desired position." msgstr "" "Pour bouger un point, cliquez dessus, maintenez le click pour le déposer à " "la position désirée." -#: widgets.py:384 +#: widgets.py:404 msgid "" "To delete a point move the mouse cursor over it and press the \"d\" or \"Del" "\" key." @@ -843,7 +894,7 @@ msgstr "" "Pour supprimer un point, mettez le curseur de la souris sur celui-ci et " "appuyez sur le touche « d » ou « Suppr »." -#: widgets.py:386 +#: widgets.py:406 msgid "" "To add a point click in the middle of a segment and drag the new point to " "the desired position" @@ -852,33 +903,39 @@ msgstr "" "maintenez le bouton appuyé et déplacez le nouveau point à la position " "désirée." -#: widgets.py:393 +#: widgets.py:413 msgid "Give a name and set category before uploading a file." msgstr "" "Renseignez le nom et choisissez au moins une catégorie avant de déposer un " "fichier." -#: widgets.py:396 +#: widgets.py:416 msgid "Upload a route file (GPX or KML)" msgstr "Déposer un trajet (fichier GPX ou KML)" -#: widgets.py:397 +#: widgets.py:417 msgid "or" msgstr "ou" -#: widgets.py:402 +#: widgets.py:422 msgid "Start \"hand\" drawing" msgstr "Commencer le tracé manuellement" -#: widgets.py:425 +#: widgets.py:445 msgid "Move on the map" msgstr "Se déplacer" -#: widgets.py:425 +#: widgets.py:445 msgid "Draw" msgstr "Tracer" -#: widgets.py:550 +#: widgets.py:525 +msgid "Hold CTRL, click and drag to select area on the map" +msgstr "" +"Maintenir la touche Control, cliquez puis glissez pour sélectionner une zone " +"sur la carte" + +#: widgets.py:591 msgid "Select..." msgstr "Sélectionner..." @@ -891,7 +948,7 @@ msgid "Internal server error" msgstr "Erreur interne du serveur" #: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7 -msgid "Administration de Chimère" +msgid "Chimère administration" msgstr "Administration de Chimère" #: templates/chimere/base.html:19 @@ -914,14 +971,26 @@ msgstr "Proposer" msgid "Date:" msgstr "Date :" +#: templates/chimere/detail.html:25 +msgid "Source:" +msgstr "Source :" + #: templates/chimere/detail.html:26 +msgid "License:" +msgstr "Licence :" + +#: templates/chimere/detail.html:28 msgid "Show multimedia gallery" msgstr "Montrer la galerie multimedia" -#: templates/chimere/detail.html:30 -msgid "Propose a modification" +#: templates/chimere/detail.html:32 templates/chimere/detail.html.py:33 +msgid "Propose amendment" msgstr "Proposer une modification" +#: templates/chimere/detail.html:32 +msgid "I would like to propose an amendment for this item:" +msgstr "Je souhaiterai proposer une modification pour cet élément :" + #: templates/chimere/edit.html:20 msgid "Error" msgstr "Erreur" @@ -991,7 +1060,7 @@ msgstr "Merci pour votre proposition !" msgid "Upload a file" msgstr "Déposer un fichier" -#: templates/chimere/upload_file.html:46 +#: templates/chimere/upload_file.html:47 msgid "Upload" msgstr "Déposer" @@ -1078,7 +1147,15 @@ msgstr "Carte" msgid "Loading of the map in progress" msgstr "Chargement de la carte en cours" -#: templates/chimere/blocks/map.html:18 +#: templates/chimere/blocks/map.html:13 +msgid "Display options" +msgstr "Options d'affichage" + +#: templates/chimere/blocks/map.html:15 +msgid "Map type" +msgstr "Type de carte" + +#: templates/chimere/blocks/map.html:24 msgid "Permalink" msgstr "Lien permanent" @@ -1233,7 +1310,10 @@ msgstr "Description :" msgid ":" msgstr " :" -#: templatetags/chimere_tags.py:65 +#: templatetags/chimere_tags.py:76 #, python-format msgid "Welcome to the %s" msgstr "Bienvenue sur %s" + +#~ msgid "Administration de Chimère" +#~ msgstr "Administration de Chimère" diff --git a/chimere/management/__init__.py b/chimere/management/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chimere/management/__init__.py diff --git a/chimere/management/commands/__init__.py b/chimere/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chimere/management/commands/__init__.py diff --git a/chimere/management/commands/chimere_export.py b/chimere/management/commands/chimere_export.py new file mode 100644 index 0000000..4e91956 --- /dev/null +++ b/chimere/management/commands/chimere_export.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import csv +import datetime, time + +from django.core.management.base import BaseCommand, CommandError +from django.core.exceptions import ObjectDoesNotExist + +from chimere import tasks +from chimere.admin import export_to_csv, export_to_kml, export_to_shapefile +from chimere.models import Category, SubCategory, Marker, Route + +EXPORTER = {'CSV':export_to_csv, + 'KML':export_to_kml, + 'SHP':export_to_shapefile} + +class Command(BaseCommand): + args = '<subcategory_id> <CSV|KML|SHP> <marker|route> <filename>' + help = "Export items from a subcategory in CSV, KML or ShapeFile" + + def handle(self, *args, **options): + subcat = None + if args and args[0]: + try: + subcat = SubCategory.objects.get(pk=int(args[0])) + except (ValueError, ObjectDoesNotExist) as e: + raise CommandError("Sub-category with ID '%s' doesn't exist." %\ + args[0]) + while not subcat: + self.stdout.write('Choose a sub-category:\n') + for cat in Category.objects.order_by('order'): + self.stdout.write('* %s\n' % cat.name) + for subcat in cat.subcategories.order_by('order').all(): + self.stdout.write(' %d - %s\n' % (subcat.pk, subcat.name)) + self.stdout.write('\nSub-category ID: ') + self.stdout.flush() + v = raw_input() + try: + subcat = SubCategory.objects.get(pk=v) + except (ValueError, ObjectDoesNotExist) as e: + subcat = None + self.stdout.write("Sub-category with ID '%s' doesn't exist.\n\n" + % v) + frmat = None + if args and args[1]: + try: + assert(args[1] in ('CSV', 'KML', 'SHP')) + except AssertionError: + raise CommandError("'%s' format is not managed." % args[1]) + frmat = args[1] + while frmat not in ('CSV', 'KML', 'SHP'): + self.stdout.write('Choose a format (CSV, KML or SHP): ') + frmat = raw_input().replace('\n', '') + exporter = EXPORTER[frmat] + cls = None + if args and args[2]: + try: + assert(args[2] in ('marker', 'route')) + except AssertionError: + raise CommandError("Exported item must be 'marker' or 'route'." + % args[1]) + if args[2] == 'marker': + cls = Marker + elif args[2] == 'route': + cls = Route + while not cls: + self.stdout.write('Choose an item type:\n 1 - marker\n 2 - route\n') + self.stdout.write('Number: ') + v = raw_input() + if v == '1': + cls = Marker + elif v == '2': + cls = Route + filename = '' + if args and args[3]: + filename = args[3] + else: + self.stdout.write('Filename: ') + filename = raw_input() + response = exporter(None, None, cls.objects.filter(categories=subcat)) + try: + with open(filename, 'w+') as fl: + fl.write(response.content) + except IOError as e: + raise CommandError(e) diff --git a/chimere/management/commands/chimere_import.py b/chimere/management/commands/chimere_import.py new file mode 100644 index 0000000..61ccd60 --- /dev/null +++ b/chimere/management/commands/chimere_import.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import csv +import datetime, time + +from django.core.management.base import BaseCommand, CommandError +from django.core.exceptions import ObjectDoesNotExist + +from chimere.models import Importer +from chimere import tasks + +class Command(BaseCommand): + args = '<import_id>' + help = "Launch import from an external source. Import configuration must "\ + "be beforehand inserted in the database with the web admin." + + def handle(self, *args, **options): + imports = dict([(imp.pk, imp) + for imp in Importer.objects.order_by('pk').all()]) + imprt = None + if args and args[0]: + try: + imprt = Importer.objects.get(pk=int(args[0])) + except (ValueError, ObjectDoesNotExist): + raise CommandError("Import with ID '%s' doesn't exist." % \ + args[0]) + if not args: + while not imprt: + self.stdout.write('* Choose the import: \n') + for k in imports: + self.stdout.write(' %s\n' % unicode(imports[k]).encode( + 'ascii', 'ignore')) + self.stdout.flush() + self.stdout.write('\nImport ID: ') + v = raw_input() + try: + imprt = Importer.objects.get(pk=int(v)) + except (ValueError, ObjectDoesNotExist): + self.stdout.write("Import with ID '%s' doesn't exist.\n\n" \ + % v) + pending_state = unicode(tasks.IMPORT_MESSAGES['import_pending'][0]) + imprt.state = pending_state + imprt.save() + tasks.importing(imprt.pk) + self.stdout.write("Import '%d' in progress...\n" % imprt.pk) + self.stdout.flush() + state = pending_state + while state == pending_state: + time.sleep(1) + state = Importer.objects.get(pk=int(imprt.pk)).state + self.stdout.write(state + '\n') + diff --git a/chimere/migrations/0028_auto__add_field_picturefile_thumbnailfile__add_field_picturefile_thumb.py b/chimere/migrations/0028_auto__add_field_picturefile_thumbnailfile__add_field_picturefile_thumb.py index 430cc2e..2f81645 100644 --- a/chimere/migrations/0028_auto__add_field_picturefile_thumbnailfile__add_field_picturefile_thumb.py +++ b/chimere/migrations/0028_auto__add_field_picturefile_thumbnailfile__add_field_picturefile_thumb.py @@ -23,7 +23,7 @@ class Migration(SchemaMigration): self.gf('django.db.models.fields.IntegerField')(null=True, blank=True), keep_default=False) - from chimere. models import picturefile_post_save + from chimere.models import picturefile_post_save for picture in orm.PictureFile.objects.all(): picturefile_post_save(orm.PictureFile, instance=picture, created=False) diff --git a/chimere/migrations/0041_auto__add_field_importer_source_file.py b/chimere/migrations/0041_auto__add_field_importer_source_file.py index 54d7f10..788d12c 100644 --- a/chimere/migrations/0041_auto__add_field_importer_source_file.py +++ b/chimere/migrations/0041_auto__add_field_importer_source_file.py @@ -103,7 +103,6 @@ class Migration(SchemaMigration): 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), - 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), @@ -117,12 +116,6 @@ class Migration(SchemaMigration): 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}) }, - 'chimere.multimediaextension': { - 'Meta': {'object_name': 'MultimediaExtension'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'extensions'", 'to': "orm['chimere.MultimediaType']"}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '6'}) - }, 'chimere.multimediafile': { 'Meta': {'object_name': 'MultimediaFile'}, 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), @@ -148,18 +141,6 @@ class Migration(SchemaMigration): 'content': ('django.db.models.fields.TextField', [], {}), 'date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}), - 'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}) - }, - 'chimere.page': { - 'Meta': {'object_name': 'Page'}, - 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'mnemonic': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), - 'order': ('django.db.models.fields.IntegerField', [], {'default': '10', 'null': 'True', 'blank': 'True'}), - 'template_path': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}), 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}) }, 'chimere.picturefile': { @@ -193,13 +174,6 @@ class Migration(SchemaMigration): 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}), 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'}) }, - 'chimere.propertymodelchoice': { - 'Meta': {'object_name': 'PropertyModelChoice'}, - 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}), - 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'}) - }, 'chimere.route': { 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'}, 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}), @@ -234,13 +208,9 @@ class Migration(SchemaMigration): }, 'chimere.subcategory': { 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'}, - 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Category']"}), 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}), - 'dated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'hover_icon': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'subcat_hovered'", 'null': 'True', 'to': "orm['chimere.Icon']"}), 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), diff --git a/chimere/migrations/0042_auto__add_field_importer_origin__add_field_importer_license__add_field.py b/chimere/migrations/0042_auto__add_field_importer_origin__add_field_importer_license__add_field.py new file mode 100644 index 0000000..757deab --- /dev/null +++ b/chimere/migrations/0042_auto__add_field_importer_origin__add_field_importer_license__add_field.py @@ -0,0 +1,274 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Importer.origin' + db.add_column('chimere_importer', 'origin', + self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True), + keep_default=False) + + # Adding field 'Importer.license' + db.add_column('chimere_importer', 'license', + self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True), + keep_default=False) + + # Adding field 'Marker.origin' + db.add_column('chimere_marker', 'origin', + self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True), + keep_default=False) + + # Adding field 'Marker.license' + db.add_column('chimere_marker', 'license', + self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True), + keep_default=False) + + # Adding field 'Route.origin' + db.add_column('chimere_route', 'origin', + self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True), + keep_default=False) + + # Adding field 'Route.license' + db.add_column('chimere_route', 'license', + self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Importer.origin' + db.delete_column('chimere_importer', 'origin') + + # Deleting field 'Importer.license' + db.delete_column('chimere_importer', 'license') + + # Deleting field 'Marker.origin' + db.delete_column('chimere_marker', 'origin') + + # Deleting field 'Marker.license' + db.delete_column('chimere_marker', 'license') + + # Deleting field 'Route.origin' + db.delete_column('chimere_route', 'origin') + + # Deleting field 'Route.license' + db.delete_column('chimere_route', 'license') + + + models = { + 'chimere.area': { + 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}), + 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}), + 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}), + 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}), + 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}), + 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.arealayers': { + 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'}, + 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}), + 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.category': { + 'Meta': {'ordering': "['order']", 'object_name': 'Category'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.color': { + 'Meta': {'ordering': "['order']", 'object_name': 'Color'}, + 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}), + 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.colortheme': { + 'Meta': {'object_name': 'ColorTheme'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.icon': { + 'Meta': {'object_name': 'Icon'}, + 'height': ('django.db.models.fields.IntegerField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'width': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.importer': { + 'Meta': {'object_name': 'Importer'}, + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'filtr': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'chimere.layer': { + 'Meta': {'object_name': 'Layer'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.marker': { + 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'}, + 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'point': ('chimere.widgets.PointField', [], {}), + 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}), + 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}) + }, + 'chimere.multimediafile': { + 'Meta': {'object_name': 'MultimediaFile'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}), + 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'chimere.multimediatype': { + 'Meta': {'object_name': 'MultimediaType'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.news': { + 'Meta': {'object_name': 'News'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.picturefile': { + 'Meta': {'object_name': 'PictureFile'}, + 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}), + 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.property': { + 'Meta': {'object_name': 'Property'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}), + 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}), + 'value': ('django.db.models.fields.TextField', [], {}) + }, + 'chimere.propertymodel': { + 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'}) + }, + 'chimere.route': { + 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'}, + 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}), + 'route': ('chimere.widgets.RouteField', [], {}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.routefile': { + 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'}, + 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + 'chimere.subcategory': { + 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Category']"}), + 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}), + 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}), + 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'chimere.tinyurl': { + 'Meta': {'object_name': 'TinyUrl'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'}) + } + } + + complete_apps = ['chimere']
\ No newline at end of file diff --git a/chimere/migrations/0043_area_permissions.py b/chimere/migrations/0043_area_permissions.py new file mode 100644 index 0000000..d396050 --- /dev/null +++ b/chimere/migrations/0043_area_permissions.py @@ -0,0 +1,230 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + from chimere.models import area_post_save + for area in orm.Area.objects.all(): + area_post_save(orm.Area, instance=area, created=False) + + def backwards(self, orm): + pass + + models = { + 'chimere.area': { + 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}), + 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}), + 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}), + 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}), + 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}), + 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.arealayers': { + 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'}, + 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}), + 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.category': { + 'Meta': {'ordering': "['order']", 'object_name': 'Category'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.color': { + 'Meta': {'ordering': "['order']", 'object_name': 'Color'}, + 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}), + 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.colortheme': { + 'Meta': {'object_name': 'ColorTheme'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.icon': { + 'Meta': {'object_name': 'Icon'}, + 'height': ('django.db.models.fields.IntegerField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'width': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.importer': { + 'Meta': {'object_name': 'Importer'}, + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'filtr': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'chimere.layer': { + 'Meta': {'object_name': 'Layer'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.marker': { + 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'}, + 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'point': ('chimere.widgets.PointField', [], {}), + 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}), + 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}) + }, + 'chimere.multimediafile': { + 'Meta': {'object_name': 'MultimediaFile'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}), + 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'chimere.multimediatype': { + 'Meta': {'object_name': 'MultimediaType'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.news': { + 'Meta': {'object_name': 'News'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.picturefile': { + 'Meta': {'object_name': 'PictureFile'}, + 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}), + 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.property': { + 'Meta': {'object_name': 'Property'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}), + 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}), + 'value': ('django.db.models.fields.TextField', [], {}) + }, + 'chimere.propertymodel': { + 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'}) + }, + 'chimere.route': { + 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'}, + 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}), + 'route': ('chimere.widgets.RouteField', [], {}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.routefile': { + 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'}, + 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + 'chimere.subcategory': { + 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}), + 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}), + 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}), + 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'chimere.tinyurl': { + 'Meta': {'object_name': 'TinyUrl'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'}) + } + } + + complete_apps = ['chimere'] diff --git a/chimere/migrations/0044_auto.py b/chimere/migrations/0044_auto.py new file mode 100644 index 0000000..bb93496 --- /dev/null +++ b/chimere/migrations/0044_auto.py @@ -0,0 +1,238 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding M2M table for field areas on 'News' + db.create_table('chimere_news_areas', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('news', models.ForeignKey(orm['chimere.news'], null=False)), + ('area', models.ForeignKey(orm['chimere.area'], null=False)) + )) + db.create_unique('chimere_news_areas', ['news_id', 'area_id']) + + + def backwards(self, orm): + # Removing M2M table for field areas on 'News' + db.delete_table('chimere_news_areas') + + + models = { + 'chimere.area': { + 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}), + 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}), + 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}), + 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}), + 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}), + 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.arealayers': { + 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'}, + 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}), + 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.category': { + 'Meta': {'ordering': "['order']", 'object_name': 'Category'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.color': { + 'Meta': {'ordering': "['order']", 'object_name': 'Color'}, + 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}), + 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.colortheme': { + 'Meta': {'object_name': 'ColorTheme'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.icon': { + 'Meta': {'object_name': 'Icon'}, + 'height': ('django.db.models.fields.IntegerField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'width': ('django.db.models.fields.IntegerField', [], {}) + }, + 'chimere.importer': { + 'Meta': {'object_name': 'Importer'}, + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'filtr': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'chimere.layer': { + 'Meta': {'object_name': 'Layer'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.marker': { + 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'}, + 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'point': ('chimere.widgets.PointField', [], {}), + 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}), + 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}) + }, + 'chimere.multimediafile': { + 'Meta': {'object_name': 'MultimediaFile'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}), + 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + }, + 'chimere.multimediatype': { + 'Meta': {'object_name': 'MultimediaType'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.news': { + 'Meta': {'object_name': 'News'}, + 'areas': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.Area']", 'symmetrical': 'False'}), + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'}) + }, + 'chimere.picturefile': { + 'Meta': {'object_name': 'PictureFile'}, + 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}), + 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.property': { + 'Meta': {'object_name': 'Property'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}), + 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}), + 'value': ('django.db.models.fields.TextField', [], {}) + }, + 'chimere.propertymodel': { + 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {}), + 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}), + 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'}) + }, + 'chimere.route': { + 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'}, + 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'license': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'modified_since_import': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'not_for_osm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}), + 'route': ('chimere.widgets.RouteField', [], {}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), + 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'chimere.routefile': { + 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'}, + 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}) + }, + 'chimere.subcategory': { + 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'category': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subcategories'", 'to': "orm['chimere.Category']"}), + 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}), + 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}), + 'submission': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'chimere.tinyurl': { + 'Meta': {'object_name': 'TinyUrl'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'}) + } + } + + complete_apps = ['chimere'] diff --git a/chimere/models.py b/chimere/models.py index 37355de..357a32a 100644 --- a/chimere/models.py +++ b/chimere/models.py @@ -27,22 +27,25 @@ from PIL import Image from subprocess import Popen, PIPE from BeautifulSoup import BeautifulSoup +from django import forms from django.conf import settings +from django.contrib import admin +from django.contrib.auth.models import User, Permission, ContentType, Group from django.contrib.gis.db import models from django.contrib.gis.gdal import SpatialReference -from django.contrib import admin from django.core.files import File -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, ObjectDoesNotExist from django.core.urlresolvers import reverse +from django.db.models import Q from django.db.models.signals import post_save, pre_save, m2m_changed -from django import forms from django.template import defaultfilters from django.utils.translation import ugettext_lazy as _ from chimere.widgets import PointField, RouteField, SelectMultipleField, \ TextareaWidget, DatePickerWidget from chimere.managers import BaseGeoManager -from chimere.utils import KMLManager, OSMManager, ShapefileManager +from chimere.utils import KMLManager, OSMManager, ShapefileManager, \ + GeoRSSManager, CSVManager class Page(models.Model): """Simple extra pages @@ -102,6 +105,8 @@ class News(models.Model): date = models.DateField(_(u"Date"), auto_now_add=True) content = models.TextField() url = models.URLField(_(u"Url"), max_length=200, blank=True, null=True) + areas = SelectMultipleField('Area', verbose_name=_(u"Associated areas"), + blank=True, null=True) def __unicode__(self): ordering = ["-date"] return self.title @@ -202,7 +207,8 @@ class Icon(models.Model): class SubCategory(models.Model): '''Sub-category ''' - category = models.ForeignKey(Category, verbose_name=_(u"Category")) + category = models.ForeignKey(Category, verbose_name=_(u"Category"), + related_name='subcategories') name = models.CharField(_(u"Name"), max_length=150) available = models.BooleanField(_(u"Available"), default=True) submission = models.BooleanField(_(u"Available for submission"), @@ -284,14 +290,20 @@ class SubCategory(models.Model): IMPORTERS = {'KML':KMLManager, 'OSM':OSMManager, - 'SHP':ShapefileManager + 'SHP':ShapefileManager, + 'RSS':GeoRSSManager, + 'CSV':CSVManager } IMPORTER_CHOICES = (('KML', 'KML'), ('OSM', 'OSM'), ('SHP', 'Shapefile'), + ('RSS', 'GeoRSS'), + ('CSV', 'CSV') ) +IMPORTER_CHOICES_DICT = dict(IMPORTER_CHOICES) + class Importer(models.Model): ''' Data importer for a specific subcategory @@ -301,20 +313,34 @@ class Importer(models.Model): # URL of a KML file or a XAPI service for OSM source = models.CharField(_(u"Source"), max_length=200, blank=True, null=True) + source_file = models.FileField(_(u"Source file"), + upload_to='import_files', blank=True, null=True) filtr = models.CharField(_(u"Filter"), max_length=200, blank=True, null=True) default_name = models.CharField(_(u"Name by default"), max_length=200, blank=True, null=True) + srid = models.IntegerField(_(u"SRID"), blank=True, null=True) + zipped = models.BooleanField(_(u"Zipped file"), default=False) + origin = models.CharField(_(u"Origin"), max_length=100, + blank=True, null=True) + license = models.CharField(_(u"License"), max_length=100, + blank=True, null=True) categories = SelectMultipleField(SubCategory, verbose_name=_(u"Associated subcategories")) state = models.CharField(_(u"State"), max_length=200, blank=True, null=True) - srid = models.IntegerField(_(u"SRID"), blank=True, null=True) - zipped = models.BooleanField(_(u"Zipped file"), default=False) class Meta: verbose_name = _(u"Importer") + def __unicode__(self): + vals = [IMPORTER_CHOICES_DICT[self.importer_type], + self.source, self.source_file.name, + u", ".join([unicode(cat) for cat in self.categories.all()]), + self.default_name] + return u' %d: %s' % (self.pk, u" - ".join([unicode(v) + for v in vals if v])) + @property def manager(self): return IMPORTERS[self.importer_type](self) @@ -351,6 +377,10 @@ class GeographicItem(models.Model): default=False) not_for_osm = models.BooleanField(_(u"Not to be imported inside OSM"), default=False) + origin = models.CharField(_(u"Origin"), max_length=100, + blank=True, null=True) + license = models.CharField(_(u"License"), max_length=100, + blank=True, null=True) if settings.CHIMERE_DAYS_BEFORE_EVENT: start_date = models.DateField(_(u"Start date"), blank=True, null=True, help_text=_(u"Not mandatory. Set it for dated item such as event. "\ @@ -388,6 +418,16 @@ class GeographicItem(models.Model): def properties(cls): return [pm for pm in PropertyModel.objects.filter(available=True)] +def property_setter(cls, propertymodel): + def setter(self, value): + marker = self + if cls == Route: + if not self.associated_marker.objects.count(): + return + marker = self.associated_marker.objects.all()[0] + marker.setProperty(propertymodel, value) + return setter + class Marker(GeographicItem): '''Marker for a POI ''' @@ -418,6 +458,9 @@ class Marker(GeographicItem): if property: val = property.python_value setattr(self, attr_name, val) + if not hasattr(self, attr_name + '_set'): + setattr(self, attr_name + '_set', + property_setter(self.__class__, pm)) def get_init_multi(self): multis = [forms.model_to_dict(multi) @@ -495,31 +538,37 @@ class Marker(GeographicItem): properties.append(property) return properties + def setProperty(self, pm, value): + u""" + Set a property + """ + properties = Property.objects.filter(marker=self, + propertymodel=pm).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() + # new property + if not properties: + new_property = Property.objects.create(marker=self, + propertymodel=pm, + value=value) + new_property.save() + else: + property = properties[0] + property.value = value + property.save() + 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() + self.setProperty(propertymodel, val) def getGeoJSON(self, categories_id=[]): '''Return a GeoJSON string @@ -559,6 +608,12 @@ class Marker(GeographicItem): url = reverse('chimere:tiny', args=[area_name, urn]) return url + +PRE_ATTRS = { + 'Marker':('name', 'geometry', 'import_version'), + 'Route':('name', 'geometry', 'import_version'), + 'Area':('urn', 'name'), + } def geometry_pre_save(cls, pre_save_geom_values): def geom_pre_save(sender, **kwargs): if not kwargs['instance'] or not kwargs['instance'].pk: @@ -566,8 +621,8 @@ def geometry_pre_save(cls, pre_save_geom_values): instance = kwargs['instance'] try: instance = cls.objects.get(pk=instance.pk) - pre_save_geom_values[instance.pk] = (instance.name, - instance.geometry, instance.import_version) + pre_save_geom_values[instance.pk] = [getattr(instance, attr) + for attr in PRE_ATTRS[cls.__name__]] except ObjectDoesNotExist: pass return geom_pre_save @@ -826,7 +881,8 @@ post_save.connect(picturefile_post_save, sender=PictureFile) class RouteFile(models.Model): name = models.CharField(_(u"Name"), max_length=150) - raw_file = models.FileField(_(u"Raw file (gpx or kml)"), upload_to='route_files') + raw_file = models.FileField(_(u"Raw file (gpx or kml)"), + upload_to='route_files') simplified_file = models.FileField(_(u"Simplified file"), upload_to='route_files', blank=True, null=True) TYPE = (('K', _(u'KML')), ('G', _(u'GPX'))) @@ -894,7 +950,7 @@ class Route(GeographicItem): null=True, height_field='height', width_field='width') height = models.IntegerField(_(u"Height"), blank=True, null=True) width = models.IntegerField(_(u"Width"), blank=True, null=True) - objects = BaseGeoManager() + objects = models.GeoManager() def __unicode__(self): return self.name @@ -903,9 +959,31 @@ class Route(GeographicItem): ordering = ('status', 'name') verbose_name = _(u"Route") + def __init__(self, *args, **kwargs): + super(Route, self).__init__(*args, **kwargs) + self.description = '' + try: + associated_marker = Marker.objects.get(route=self) + self.description = associated_marker.description + except: + associated_marker = None + # add read attributes for properties + for pm in self.properties(): + attr_name = pm.getAttrName() + if not hasattr(self, attr_name): + val = '' + if associated_marker: + property = associated_marker.getProperty(pm) + if property: + val = property.python_value + setattr(self, attr_name, val) + if not hasattr(self, attr_name + '_set'): + setattr(self, attr_name + '_set', + property_setter(self.__class__, pm)) + @property def geometry(self): - return self.point.wkt + return self.route.wkt def get_init_multi(self): if not self.associated_marker.count(): @@ -1175,20 +1253,34 @@ class Area(models.Model, SimpleArea): ''' return cls.objects.filter(available=True) - def getIncludeSql(self, geometry='"chimere_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, + def getWkt(self): + return "SRID=%d;POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f))" % ( + settings.CHIMERE_EPSG_DISPLAY_PROJECTION, + 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.CHIMERE_EPSG_DISPLAY_PROJECTION ) - sql = "ST_Contains(" + area + ", " + geometry + ")" - return sql + + def getIncludeMarker(self): + """ + Get the sql statement for the test if the point is included in the area + """ + return Q(point__contained=self.getWkt()) + + def getIncludeRoute(self): + """ + Get the sql statement for the test if the route is included in the area + """ + return Q(route__contained=self.getWkt()) + +pre_save_area_values = {} +def area_pre_save(sender, **kwargs): + if not kwargs['instance']: + return + geometry_pre_save(Area, pre_save_area_values)(sender, **kwargs) +pre_save.connect(area_pre_save, sender=Area) def area_post_save(sender, **kwargs): if not kwargs['instance']: @@ -1199,8 +1291,82 @@ def area_post_save(sender, **kwargs): for default in defaults: default.default = False default.save() + # manage permissions + old_urn, old_name = area.urn, area.name + if area.pk in pre_save_area_values: + old_urn, old_name = pre_save_area_values[area.pk] + perm, old_groups, old_users = None, [], [] + if area.urn != old_urn: + oldmnemo = 'change_area_' + old_urn + old_perm = Permission.objects.filter(codename=oldmnemo) + if old_perm.count(): + perm = old_perm.all()[0] + perm.codename = 'change_area_' + area.urn + perm.save() + if not area.urn: + area.urn = defaultfilters.slugify(area.name) + area.save() + mnemo = 'change_area_' + area.urn + perm = Permission.objects.filter(codename=mnemo) + lbl = "Can change " + area.name + if not perm.count(): + content_type = ContentType.objects.get(app_label="chimere", + model="area") + perm = Permission(name=lbl, content_type_id=content_type.id, + codename=mnemo) + perm.save() + else: + perm = perm.all()[0] + if old_name != area.name: + perm.name = lbl + perm.save() + # manage moderation group + groupname = area.name + " moderation" + if old_name != area.name: + old_groupname = old_name + " moderation" + old_gp = Group.objects.filter(name=old_groupname) + if old_gp.count(): + old_gp = old_gp.all()[0] + old_gp.name = groupname + old_gp.save() + group = Group.objects.filter(name=groupname) + if not group.count(): + group = Group.objects.create(name=groupname) + group.permissions.add(perm) + for app_label, model in (('chimere', 'marker'), + ('chimere', 'route'), + ('chimere', 'multimediafile'), + ('chimere', 'picturefile'), + ('chimere', 'routefile')): + ct = ContentType.objects.get(app_label=app_label, model=model) + for p in Permission.objects.filter(content_type=ct).all(): + group.permissions.add(p) + post_save.connect(area_post_save, sender=Area) +def get_areas_for_user(user): + """ + Getting subcats for a specific user + """ + perms = user.get_all_permissions() + areas = set() + prefix = 'chimere.change_area_' + for perm in perms: + if perm.startswith(prefix): + try: + area = Area.objects.get(urn=perm[len(prefix):]) + areas.add(area) + except ObjectDoesNotExist: + pass + return areas + +def get_users_by_area(area): + if not area: + return [] + perm = 'change_area_'+area.urn + return User.objects.filter(Q(groups__permissions__codename=perm)| + Q(user_permissions__codename=perm)).all() + class AreaLayers(models.Model): area = models.ForeignKey(Area) layer = models.ForeignKey(Layer) diff --git a/chimere/static/chimere/css/styles.css b/chimere/static/chimere/css/styles.css index 120e062..43dc3c6 100644 --- a/chimere/static/chimere/css/styles.css +++ b/chimere/static/chimere/css/styles.css @@ -329,6 +329,11 @@ ul#action-2 { max-width:280px; } +#detail_content p{ + padding:0.2em 0; + margin:0; +} + ul.share{ list-style-type:none; margin:0; @@ -577,6 +582,7 @@ ul.share li{ .simple #panel{ top:5px; + bottom:auto; } @@ -586,24 +592,30 @@ ul.share li{ z-index:5; } -/*.panel-minified {*/ #panel{ bottom:None; + height:auto; } #panel.panel-minified #categories > ul{ height:160px; overflow:auto; - /*width:285px;*/ } +.simple #panel.panel-minified #categories > ul{ + height:auto; +} + + #panel.panel-minified{ height:200px; bottom:auto; overflow:visible; } - +.simple #panel.panel-minified{ + height:auto; +} .simple #panel #categories{ display:None; diff --git a/chimere/static/chimere/js/edit_area.js b/chimere/static/chimere/js/edit_area.js index f22d6e3..9c3384f 100644 --- a/chimere/static/chimere/js/edit_area.js +++ b/chimere/static/chimere/js/edit_area.js @@ -18,12 +18,25 @@ See the file COPYING for details. /* area edit */ +var bbox_style = {fill: true, fillColor: "#FFFFFF", fillOpacity: 0.5, + stroke: true, strokeOpacity: 0.8, strokeColor: "#FF0000", strokeWidth: 2}; + var map; +var box_layer; + +function initForm(bounds){ + +} -/* update form fields on zoom action */ -function updateForm(){ - var bounds = map.getExtent().transform(epsg_projection, - epsg_display_projection); +/* update form fields on select action */ +function updateForm(bounds){ + if(!bounds.toGeometry) return; + var feature = new OpenLayers.Feature.Vector( + bounds.toGeometry(), {}, bbox_style); + box_layer.destroyFeatures() + box_layer.addFeatures(feature); + var bounds = bounds.clone().transform(epsg_projection, + epsg_display_projection); document.getElementById('upper_left_lat').value = bounds.top; document.getElementById('upper_left_lon').value = bounds.left; document.getElementById('lower_right_lat').value = bounds.bottom; @@ -34,15 +47,40 @@ function updateForm(){ function init(){ map = new OpenLayers.Map ('map_edit', { controls:[new OpenLayers.Control.Navigation(), - new OpenLayers.Control.PanPanel(), - new OpenLayers.Control.ZoomPanel(), - new OpenLayers.Control.Attribution()], + new OpenLayers.Control.SimplePanZoom()], maxResolution: 156543.0399, units: 'm', projection: epsg_projection, displayProjection: epsg_display_projection } ); - map.addLayers([map_layer]); + box_layer = new OpenLayers.Layer.Vector("Box layer"); + map.addLayers([map_layer, box_layer]); + var selectControl = new OpenLayers.Control(); + OpenLayers.Util.extend(selectControl, { + draw: function() { + this.box = new OpenLayers.Handler.Box(selectControl, + {'done': this.notice}, + {keyMask: navigator.platform.match(/Mac/) ? + OpenLayers.Handler.MOD_ALT :OpenLayers.Handler.MOD_CTRL}); + this.box.activate(); + }, + + notice: function(pxbounds) { + ltpixel = map.getLonLatFromPixel( + new OpenLayers.Pixel(pxbounds.left, pxbounds.top)); + rbpixel = map.getLonLatFromPixel( + new OpenLayers.Pixel(pxbounds.right, pxbounds.bottom)); + if (ltpixel.equals(rbpixel)) + return; + if (!ltpixel || !rbpixel) return; + bounds = new OpenLayers.Bounds(); + bounds.extend(ltpixel); + bounds.extend(rbpixel); + updateForm(bounds); + } + }); + map.addControl(selectControl); + map.events.register('zoomend', map, updateForm); map.events.register('moveend', map, updateForm); /* zoom to the appropriate extent */ diff --git a/chimere/static/chimere/js/jquery.chimere.js b/chimere/static/chimere/js/jquery.chimere.js index 9889367..e2aa6b2 100644 --- a/chimere/static/chimere/js/jquery.chimere.js +++ b/chimere/static/chimere/js/jquery.chimere.js @@ -1348,6 +1348,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, { saveExtent: function(){ var extent_key = 'MAP_EXTENT'; //if (area_name){ extent_key = extent_key + '_' + area_name; } + if (!settings.map) return; var extent = settings.map.getExtent().transform(EPSG_PROJECTION, EPSG_DISPLAY_PROJECTION); document.cookie = extent_key + "=" + extent.toArray().join('_') diff --git a/chimere/static/chimere/js/menu-sort.js b/chimere/static/chimere/js/menu-sort.js index ad1da39..37d0ddd 100644 --- a/chimere/static/chimere/js/menu-sort.js +++ b/chimere/static/chimere/js/menu-sort.js @@ -11,10 +11,14 @@ jQuery(function($) { } }); $('div.inline-group tbody tr').css('cursor', 'move'); - $('div.inline-group tbody tr td').each(function (idx){ - if($(this).is('*.field-order')){ - $(this).hide(); - $('div.inline-group thead th:nth-child('+idx+')').hide(); - } + $('div.inline-group').each(function(){ + var par = $(this); + par.find('tbody tr td').each( + function (idx){ + if($(this).is('*.field-order')){ + $(this).hide(); + par.find('thead th:nth-child('+idx+')').hide(); + } + }); }); }); diff --git a/chimere/static/chimere/js/textareas.js b/chimere/static/chimere/js/textareas.js index e15e7f2..22b68c8 100644 --- a/chimere/static/chimere/js/textareas.js +++ b/chimere/static/chimere/js/textareas.js @@ -16,13 +16,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. See the file COPYING for details. */ - -tinyMCE.init({ - mode : "textareas", - theme : "advanced", - editor_selector : "mceEditor", - relative_urls : false, - theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,hr,separator,link,image", - theme_advanced_buttons2 : "", - theme_advanced_buttons3 : "" -}); +if (!window.tinymce_init){ + window.tinymce_init = true; + tinyMCE.init({ + mode : "textareas", + theme : "advanced", + editor_selector : "mceEditor", + relative_urls : false, + theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,hr,separator,link", + theme_advanced_buttons2 : "", + theme_advanced_buttons3 : "" + }) +}; diff --git a/chimere/static/chimere/js/textareas_admin.js b/chimere/static/chimere/js/textareas_admin.js new file mode 100644 index 0000000..7acec97 --- /dev/null +++ b/chimere/static/chimere/js/textareas_admin.js @@ -0,0 +1,30 @@ +/* base function shared by some pages */ +/* Copyright (C) 2009 É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. +*/ +if (!window.tinymce_init){ + window.tinymce_init = true; + tinyMCE.init({ + mode : "textareas", + theme : "advanced", + editor_selector : "mceEditor", + relative_urls : false, + theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,hr,separator,link,image", + theme_advanced_buttons2 : "", + theme_advanced_buttons3 : "" + }); +}; diff --git a/chimere/templates/admin/base_site.html b/chimere/templates/admin/base_site.html index fa537ef..d0cf4bf 100644 --- a/chimere/templates/admin/base_site.html +++ b/chimere/templates/admin/base_site.html @@ -1,10 +1,10 @@ {% extends "admin/base.html" %} {% load i18n %} -{% block title %}{{ title }} | {% trans 'Administration de Chimère' %}{% endblock %} +{% block title %}{{ title }} | {% trans 'Chimère administration' %}{% endblock %} {% block branding %} -<h1 id="site-name">{% trans 'Administration de Chimère' %}</h1> +<h1 id="site-name">{% trans 'Chimère administration' %}</h1> {% endblock %} {% block nav-global %}{% endblock %} diff --git a/chimere/templates/chimere/detail.html b/chimere/templates/chimere/detail.html index b03dcf2..858a7ae 100644 --- a/chimere/templates/chimere/detail.html +++ b/chimere/templates/chimere/detail.html @@ -22,17 +22,18 @@ {% for property in marker.getProperties %} <p id='{{property.propertymodel.getNamedId}}'>{{ property.value|sanitize:"p b i br hr strong em img:src:alt span:style a:href:target ul li ol h1 h2 h3 h4 table td tr th"|safe}}</p> {% endfor %} + {% if marker.origin %}<p class='detail_source'><strong>{% trans "Source:" %}</strong> <span>{{marker.origin}}</span></p>{% endif %} + {% if marker.license %}<p class='detail_license'><strong>{% trans "License:" %}</strong> <span>{{marker.license}}</span></p>{% endif %} {% if marker.multimedia_items %} <a href='#' id='show_gallery_link'>{% trans "Show multimedia gallery" %}</a> {% endif %} </div> + {% if moderator_emails %} + <a href="mailto:?from={{moderator_emails}}&subject={% trans "Propose amendment" %}&body={% trans "I would like to propose an amendment for this item:"%} {{share_url}}"> + {% trans "Propose amendment" %} + </a>{%endif%} {% share_bar marker.name %} - <a href="{{modif_by_email}}">{% trans "Propose a modification" %}</a> - {% comment %} - <a href='{% if marker.route %}{% url chimere:editroute-item area_name_slash|default_if_none:"" marker.route.pk "" %}{%else%}{% url chimere:edit-item area_name_slash|default_if_none:"" marker.pk "" %}{%endif%}'> - {% trans "Submit a modification" %} - </a> - {% endcomment %} +{% endif %} </div> {% if marker.multimedia_items %} <div id='gallery-{{marker.pk}}' class='gallery'> diff --git a/chimere/templates/chimere/export_marker.csv b/chimere/templates/chimere/export.csv index 619b872..619b872 100644 --- a/chimere/templates/chimere/export_marker.csv +++ b/chimere/templates/chimere/export.csv diff --git a/chimere/templates/chimere/export.kml b/chimere/templates/chimere/export.kml index 55d671d..b59bc7c 100644 --- a/chimere/templates/chimere/export.kml +++ b/chimere/templates/chimere/export.kml @@ -10,7 +10,8 @@ {% if location.description %}<description> <![CDATA[{{ location.description|safe }}]]> </description>{% endif %} - {{location.point.kml|safe}} + {% if location.point %}{{location.point.kml|safe}}{% endif %} + {% if location.route %}{{location.route.kml|safe}}{% endif %} </Placemark> {% endfor %} diff --git a/chimere/templates/chimere/upload_file.html b/chimere/templates/chimere/upload_file.html index b0fbafc..91a1444 100644 --- a/chimere/templates/chimere/upload_file.html +++ b/chimere/templates/chimere/upload_file.html @@ -22,6 +22,7 @@ <div class="fieldWrapper"> {% if gpx_id %} <script type="text/javascript"><!-- +jQuery(document).ready(function() { jQuery.get("{% url chimere:process_route_file gpx_id %}", function(data) { var data = eval(data); var main_page = opener.document; @@ -36,9 +37,9 @@ opener.focus(); self.close(); }).error(function (xhr, ajaxOptions, thrownError){ - alert(xhr.status); - alert(thrownError); + alert(xhr.responseText); } ); +}); // --></script> {% else %} <form enctype="multipart/form-data" method='post' action='.'> diff --git a/chimere/templatetags/chimere_tags.py b/chimere/templatetags/chimere_tags.py index 78e148a..084904f 100644 --- a/chimere/templatetags/chimere_tags.py +++ b/chimere/templatetags/chimere_tags.py @@ -9,7 +9,7 @@ from django import template from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse -from django.db.models import Q +from django.db.models import Q, Count from django.template import defaultfilters from django.utils.translation import ugettext as _ @@ -40,9 +40,12 @@ def submited(context): return {"edit_url":reverse('chimere:edit'), "index_url":reverse('chimere:index')} -def get_news(): +def get_news(area=None): # Retrieve news - news = list(News.objects.filter(available=True, is_front_page=True)) + news = News.objects.filter(available=True, is_front_page=True) + if area: + news = news.filter(Q(areas__isnull=True)|Q(areas__in=[area.pk])) + news = list(news.all()) if settings.CHIMERE_DAYS_BEFORE_EVENT: # Retrieve active markers today = date.today() @@ -59,10 +62,7 @@ def display_welcome(context, display=False, title=''): Welcome message and active news. """ context_data = {'display':display} - context_data['news_lst'] = get_news()[:3] - context_data['STATIC_URL'] = settings.STATIC_URL - context_data['title'] = title if title \ - else _(u"Welcome to the %s") % settings.PROJECT_NAME + area = None if "area_name" in context: try: area = Area.objects.get(urn=context["area_name"]) @@ -70,6 +70,10 @@ def display_welcome(context, display=False, title=''): context_data['welcome_message'] = area.welcome_message except ObjectDoesNotExist: pass + context_data['news_lst'] = get_news(area)[:3] + context_data['STATIC_URL'] = settings.STATIC_URL + context_data['title'] = title if title \ + else _(u"Welcome to the %s") % settings.PROJECT_NAME return context_data @register.inclusion_tag('chimere/blocks/news.html', takes_context=True) @@ -77,7 +81,15 @@ def display_news(context, title=''): """ All news. """ - context_data = {'news_lst': get_news(), + area = None + if "area_name" in context: + try: + area = Area.objects.get(urn=context["area_name"]) + context_data['area_name'] = context['area_name'] + context_data['welcome_message'] = area.welcome_message + except ObjectDoesNotExist: + pass + context_data = {'news_lst': get_news(area), 'STATIC_URL':settings.STATIC_URL} return context_data diff --git a/chimere/tests.py b/chimere/tests.py index b3ad3fb..ddd59b1 100644 --- a/chimere/tests.py +++ b/chimere/tests.py @@ -117,7 +117,7 @@ class KMLImporterTest(TestCase, ImporterTest): source=test_dir_path+'tests/sample.kml.zip', zipped=True) importer4.categories.add(subcategory_1) - self.marker_importers = [(importer1, 1), (importer2, 2), (importer3, 0), + self.marker_importers = [(importer1, 1), (importer2, 3), (importer3, 0), (importer4, 4)] class ShapefileImporterTest(TestCase, ImporterTest): @@ -152,6 +152,15 @@ class OSMImporterTest(TestCase, ImporterTest): self.marker_importers = [(importer1, 19), (importer2, 8)] +class GeoRSSImporterTest(TestCase, ImporterTest): + def setUp(self): + subcategory_1, subcategory_2 = subcategory_setup() + importer1 = Importer.objects.create(importer_type='RSS', + source=test_dir_path+'tests/georss.xml') + importer1.categories.add(subcategory_1) + + self.marker_importers = [(importer1, 1)] + class FeedsTest(TestCase): def setUp(self): self.area = area_setup() diff --git a/chimere/tests/georss.xml b/chimere/tests/georss.xml new file mode 100644 index 0000000..8697f16 --- /dev/null +++ b/chimere/tests/georss.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<feed xmlns="http://www.w3.org/2005/Atom" + xmlns:georss="http://www.georss.org/georss"> + <title>Earthquakes</title> + <subtitle>International earthquake observation labs</subtitle> + <link href="http://example.org/"/> + <updated>2005-12-13T18:30:02Z</updated> + <author> + <name>Dr. Thaddeus Remor</name> + <email>tremor@quakelab.edu</email> + </author> + <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id> + <entry> + <title>M 3.2, Mona Passage</title> + <link href="http://example.org/2005/09/09/atom01"/> + <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id> + <updated>2005-08-17T07:02:32Z</updated> + <summary>We just had a big one.</summary> + <georss:point>45.256 -71.92</georss:point> + </entry> +</feed> diff --git a/chimere/tests/sample.kml b/chimere/tests/sample.kml index 665d861..cc9f108 100644 --- a/chimere/tests/sample.kml +++ b/chimere/tests/sample.kml @@ -35,6 +35,16 @@ <coordinates>-4.69242,48.57501,0</coordinates> </Point> </Placemark> + <Placemark id='4'> + <name>Place 22</name> + <Snippet>snippet</Snippet> + <description>Place 44 description</description> + <LineString> + <coordinates>-112.0814237830345,36.10677870477137,0 + -112.0870267752693,36.0905099328766,0 + </coordinates> + </LineString> + </Placemark> </Folder> </Folder> <Folder> diff --git a/chimere/utils.py b/chimere/utils.py index 4cd6f45..75c0ad4 100644 --- a/chimere/utils.py +++ b/chimere/utils.py @@ -23,6 +23,7 @@ Utilitaries import csv import datetime +import feedparser import os import re import StringIO @@ -69,16 +70,21 @@ class ImportManager: def put(self): pass - def create_or_update_item(self, cls, values, import_key, version=None): + def create_or_update_item(self, cls, values, import_key, version=None, + key='', pk=None): updated, created, item = False, False, None - if import_key: + import_key = unicode(import_key).replace(':', '^') + if not key: + key = self.importer_instance.importer_type + if import_key or pk: dct_import = { - 'import_key__icontains':'%s:%s;' % ( - self.importer_instance.importer_type, - import_key), + 'import_key__icontains':'%s:%s;' % (key, import_key), 'import_source':self.importer_instance.source} try: - item = cls.objects.get(**dct_import) + if pk: + item = cls.objects.get(pk=pk) + else: + item = cls.objects.get(**dct_import) if version and item.import_version == int(version): # no update since the last import return item, None, None @@ -103,8 +109,7 @@ class ImportManager: return None, False, False created = True if import_key: - item.set_key(self.importer_instance.importer_type, - import_key) + item.set_key(key, import_key) item.categories.clear() for cat in self.importer_instance.categories.all(): item.categories.add(cat) @@ -138,8 +143,9 @@ class ImportManager: files.append(None) return files - def get_source_file(self, source, suffixes, dest_dir=None, + def get_source_file(self, suffixes, dest_dir=None, extra_url=None): + source = self.importer_instance.source_file if not hasattr(source, 'read'): if not source: source = self.importer_instance.source \ @@ -157,7 +163,7 @@ class ImportManager: source = open(source) except IOError, msg: return (None, msg) - except urllib2.URLError as error: + except (urllib2.URLError, AttributeError) as error: return (None, error.message) if self.importer_instance.zipped: try: @@ -182,21 +188,18 @@ class KMLManager(ImportManager): self.importer_instance = importer_instance self.ns = ns - def get(self, source=None): + def get(self): u""" - Get data from the source - Args: - - source (None): input file if not provided get it from the distant - source provided in the importer instance. + Get data from a KML source Return a tuple with: - number of new item ; - number of item updated ; - error detail on error """ - from models import Marker + from models import Marker, Route new_item, updated_item, msg = 0, 0, '' - source, msg = self.get_source_file(source, ['.kml']) + source, msg = self.get_source_file(['.kml']) if msg: return (0, 0, msg) doc = source @@ -207,7 +210,10 @@ class KMLManager(ImportManager): if line.strip(): break doc = StringIO.StringIO("\n".join(splitted[idx:])) - tree = etree.parse(doc) + try: + tree = etree.parse(doc) + except: + return (0, 0, _(u"Bad XML file")) # try to get default namespace if not self.ns: self.ns = tree.getroot().nsmap[None] @@ -215,7 +221,7 @@ class KMLManager(ImportManager): if self.importer_instance.filtr else self.DEFAULT_XPATH for placemark in tree.xpath(xpath, namespaces={'kml':self.ns}): - name, point = None, None + name, point, line = None, None, None pl_id = placemark.attrib.get('id') pl_key = 'kml-%d' % self.importer_instance.pk ns = '{%s}' % self.ns @@ -232,34 +238,32 @@ class KMLManager(ImportManager): if coord.tag == ns + 'coordinates': x, y, z = coord.text.split(',') point = 'SRID=4326;POINT(%s %s)' % (x, y) + elif item.tag == ns + 'LineString': + for coord in item: + if coord.tag == ns + 'coordinates': + points = coord.text.replace('\n', ' ').split(' ') + points = ",".join([" ".join(p.split(',')[:2]) + for p in points if p]) + line = 'SRID=4326;LINESTRING(%s)' % points + cls = None + dct = {'description':description, + 'name':name, + 'origin':self.importer_instance.origin, + 'license':self.importer_instance.license} if point: - dct = {'point':point, - 'description':description, - 'name':name,} - m = None - if pl_id: - dct_import = { - 'import_key__icontains':'%s:%s;' % (pl_key, pl_id), - 'import_source':self.importer_instance.source} - try: - m = Marker.objects.get(**dct_import) - for k in dct: - setattr(m, k, dct[k]) - m.save() - updated_item += 1 - except ObjectDoesNotExist: - m = None - dct.update({ - 'import_source':self.importer_instance.source}) - if not m: - dct['status'] = 'I' - m = Marker.objects.create(**dct) + dct['point'] = point + cls = Marker + if line: + dct['route'] = line + dct.pop('description') + cls = Route + if cls: + item, updated, created = self.create_or_update_item( + cls, dct, pl_id, key=pl_key) + if updated: + updated_item += 1 + if created: new_item += 1 - if pl_id: - m.set_key(pl_key, pl_id) - m.categories.clear() - for cat in self.importer_instance.categories.all(): - m.categories.add(cat) return (new_item, updated_item, msg) @classmethod @@ -277,12 +281,9 @@ class ShapefileManager(ImportManager): u""" Shapefile importer """ - def get(self, source=None): + def get(self): u""" - Get data from the source - Args: - - source (None): input file if not provided get it from the distant - source provided in the importer instance. + Get data from a Shapefile source Return a tuple with: - number of new item ; @@ -292,8 +293,7 @@ class ShapefileManager(ImportManager): from models import Marker, Route new_item, updated_item, msg = 0, 0, '' tmpdir = tempfile.mkdtemp() - sources, msg = self.get_source_file(source, - ['.shp', '.dbf', '.prj', '.shx'], + sources, msg = self.get_source_file(['.shp', '.dbf', '.prj', '.shx'], dest_dir=tmpdir) if msg: return (0, 0, msg) @@ -350,13 +350,18 @@ class ShapefileManager(ImportManager): name.decode(settings.CHIMERE_SHAPEFILE_ENCODING)) except: continue - geoms = [feat.geom.wkt] + try: + geoms = [feat.geom.wkt] + except: + return (0, 0, _(u"Bad Shapefile")) if feat.geom.geom_type == 'MultiLineString': geoms = [geom.wkt for geom in feat.geom] import_key = feat.get(id_name) if id_name and len(geoms) == 1 else '' for geom in geoms: dct = {geom_key:'SRID=%s;%s' % (srid, geom), - 'name':name + 'name':name, + 'origin':self.importer_instance.origin, + 'license':self.importer_instance.license } item, updated, created = self.create_or_update_item( geom_cls, dct, import_key) @@ -441,26 +446,91 @@ class CSVManager(ImportManager): u""" CSV importer """ - _COLS = [("Id", 'pk'), (_(u"Name"), 'name'), + @classmethod + def set_categories(value): + return + + # (label, getter, setter) + COLS = [("Id", 'pk', 'pk'), (_(u"Name"), 'name', 'name'), (_(u"Categories"), lambda obj:", ".join( - [c.name for c in obj.categories.all()])), - (_(u"State"), 'status')] - COLS = {'marker':_COLS+[(_(u"Description"), 'description'), - (_(u"Localisation"), lambda obj: obj.point.wkt)], - 'route':_COLS+[(_(u"Localisation"), lambda obj: obj.route.wkt)]} + [c.name for c in obj.categories.all()]), + set_categories), + (_(u"State"), 'status', lambda x: x), + (_(u"Description"), 'description', 'description'), + (_(u"Localisation"), 'geometry', 'geometry')] + + def get(self): + u""" + Get data from a CSV source + + Return a tuple with: + - number of new item ; + - number of item updated ; + - error detail on error + """ + from models import Marker, Route + new_item, updated_item, msg = 0, 0, '' + source, msg = self.get_source_file(['.csv']) + if msg: + return (0, 0, msg) + reader = csv.reader(source, delimiter=';', quotechar='"') + prop_cols = [] + for pm in Marker.properties(): + prop_cols.append((pm.name, pm.getAttrName(), + pm.getAttrName()+'_set')) + cols = self.COLS + prop_cols + datas = [] + for idx, row in enumerate(reader): + if not idx: # first row + try: + assert(len(row) >= len(cols)) + except AssertionError: + return (0, 0, _(u"Invalid CSV format")) + continue + if len(row) < len(cols): + continue + pk, name, cats, state = row[0], row[1], row[2], row[3] + description, geom = row[4], row[5] + COL_INDEX = 6 + dct = {'description':description, + 'name':name, + 'origin':self.importer_instance.origin, + 'license':self.importer_instance.license} + cls = None + if 'POINT' in geom: + cls = Marker + dct['point'] = geom + elif 'LINE' in geom: + cls = Route + dct['route'] = geom + else: + continue + import_key = pk if pk else name + item, updated, created = self.create_or_update_item(cls, dct, + import_key, pk=pk) + if updated: + updated_item += 1 + if created: + new_item += 1 + for idx, col in enumerate(cols[COL_INDEX:]): + name, getter, setter_val = col + setter = getattr(item, setter_val) + val = row[idx+COL_INDEX] + setter(item, val) + return (new_item, updated_item, msg) @classmethod def export(cls, queryset): dct = {'description':unicode(datetime.date.today()), 'data':[]} cls_name = queryset.model.__name__.lower() - cols = cls.COLS[cls_name][:] + cols = cls.COLS for pm in queryset.model.properties(): - cols.append((pm.name, pm.getAttrName())) - header = [lbl for lbl, attr in cols] + cols.append((pm.name, pm.getAttrName(), pm.getAttrName()+'_set')) + header = [col[0] for col in cols] dct['data'].append(header) for item in queryset.all(): data = [] - for lbl, attr in cols: + for (lbl, attr, setr) in cols: if callable(attr): data.append(attr(item)) else: @@ -468,9 +538,66 @@ class CSVManager(ImportManager): dct['data'].append(data) filename = unicode_normalize(settings.PROJECT_NAME + dct['description']\ + '.csv') - result = render_to_response('chimere/export_%s.csv' % cls_name, dct) + result = render_to_response('chimere/export.csv', dct) return filename, result +class GeoRSSManager(ImportManager): + u""" + RSS importer. + This manager only gets and do not produce GeoRSSFeed + """ + + def get(self): + u""" + Get data from a GeoRSS simple source + + Return a tuple with: + - number of new item ; + - number of item updated ; + - error detail on error + """ + from models import Marker + new_item, updated_item, msg = 0, 0, '' + feed = feedparser.parse(self.importer_instance.source) + if feed['bozo']: + return (0, 0, _(u"RSS feed is not well formed")) + for item in feed['items']: + if "georss_point" not in item and 'georss_line' not in item: + continue + cls = None + dct = {'origin':self.importer_instance.origin, + 'license':self.importer_instance.license} + if 'georss_point' in item: + cls = Marker + try: + y, x = item['georss_point'].split(' ') + except ValueError: + continue + dct['point'] = 'SRID=4326;POINT(%s %s)' % (x, y) + for k in ['description', 'summary', 'value']: + if k in item: + dct['description'] = item[k] + break + else: + cls = Route + points = item['georss_line'].split(' ') + reordered_points = [] + # lat, lon -> x, y + for idx in xrange(len(points)/2): + reordered_points.append("%s %s" % (points[idx*2+1], + points[idx*2])) + dct['route'] = 'SRID=4326;LINESTRING(%s)' % \ + ",".join(reordered_points) + + dct['name'] = item['title'] + pl_id = item['id'] if 'id' in item else item['title'] + it, updated, created = self.create_or_update_item(cls, dct, pl_id) + if updated: + updated_item += 1 + if created: + new_item += 1 + return (new_item, updated_item, msg) + RE_HOOK = re.compile('\[([^\]]*)\]') # TODO: manage deleted item from OSM @@ -483,19 +610,16 @@ class OSMManager(ImportManager): """ default_source = settings.CHIMERE_XAPI_URL - def get(self, source=None): + def get(self): u""" Get data from the source - Args: - - source (None): input file if not provided get it from the distant - source provided in the importer instance. Return a tuple with: - new items; - updated items; - error detail on error. """ - source, msg = self.get_source_file(source, ['.osm'], + source, msg = self.get_source_file(['.osm'], extra_url=self.importer_instance.filtr) if not source: return (0, 0, msg) @@ -538,6 +662,10 @@ class OSMManager(ImportManager): for point_id in points if point_id in nodes]) dct = {'route':wkt, 'name':name, + 'origin':self.importer_instance.origin \ + or u'OpenStreetMap.org', + 'license':self.importer_instance.license \ + or u'ODbL', 'import_version':version} item, updated, created = self.create_or_update_item( Route, dct, node_id, version) @@ -567,6 +695,10 @@ class OSMManager(ImportManager): node.get('lat')) dct = {'point':point, 'name':name, + 'origin':self.importer_instance.origin \ + or u'OpenStreetMap.org', + 'license':self.importer_instance.license \ + or u'ODbL', 'import_version':version} item, updated, created = self.create_or_update_item( Marker, dct, node_id, version) diff --git a/chimere/views.py b/chimere/views.py index 7c983a3..fdc4da0 100644 --- a/chimere/views.py +++ b/chimere/views.py @@ -294,6 +294,9 @@ def edit(request, area_name="", item_id=None, submited=False): declared_fields = PropertyModel.objects.filter(available=True).all() filtered_properties = PropertyModel.objects.filter(available=True, subcategories__id__isnull=False).all() + point_value = init_item.point if init_item else None + if request.POST and request.POST.get('point'): + point_value = request.POST.get('point') response_dct.update({ 'actions':actions(response_dct['area_name']), 'action_selected':('contribute', 'edit'), @@ -306,7 +309,7 @@ def edit(request, area_name="", item_id=None, submited=False): 'marker_id':item_id, 'sub_categories':sub_categories, 'point_widget':PointChooserWidget().render('point', - init_item.point if init_item else None, + point_value, area_name=response_dct['area_name']), 'properties':declared_fields, 'filtered_properties':filtered_properties, @@ -377,8 +380,8 @@ def processRouteFile(request, area_name='', file_id=None): return HttpResponse('('+simplejson.dumps({'wkt':route, 'file_id':file_id})+')', 'application/javascript', status=200) - except: - return HttpResponse(status=500) + except OSError as e: + return HttpResponse(e.strerror, status=500) else: return HttpResponse(status=400) @@ -399,6 +402,9 @@ def editRoute(request, area_name="", item_id=None, submited=False): declared_fields = form.declared_fields.keys() if 'description' in declared_fields: declared_fields.pop(declared_fields.index('description')) + route_value = init_item.route if init_item else None + if request.POST and request.POST.get('route'): + route_value = request.POST.get('route') response_dct.update({ 'actions':actions(response_dct['area_name']), 'action_selected':('contribute', 'edit-route'), @@ -410,8 +416,7 @@ def editRoute(request, area_name="", item_id=None, submited=False): 'dated':settings.CHIMERE_DAYS_BEFORE_EVENT, 'extra_head':form.media, 'sub_categories':sub_categories, - 'route_widget':RouteChooserWidget().render('route', - init_item.route if init_item else None, + 'route_widget':RouteChooserWidget().render('route', route_value, area_name=response_dct['area_name'], routefile_id='',), 'properties':declared_fields, 'submited':submited @@ -422,28 +427,6 @@ def editRoute(request, area_name="", item_id=None, submited=False): return render_to_response('chimere/edit_route.html', response_dct, context_instance=RequestContext(request)) -def welcome(request, display=None): - """ - Welcome string - """ - response_dct = {'display':display} - news = list(News.objects.filter(available=True, is_front_page=True).all()) - if settings.CHIMERE_DAYS_BEFORE_EVENT: - q = checkDate(Q(status='A', start_date__isnull=False, - is_front_page=True)) - news += list(Marker.objects.filter(q).all()) - news.sort(key=lambda x:x.date, reverse=True)[:3] - response_dct['news_lst'] = news - if "area_name" in context: - try: - area = Area.objects.get(urn=context["area_name"]) - context_data['area_name'] = context['area_name'] - context_data['welcome_message'] = area.welcome_message - except ObjectDoesNotExist: - pass - return loader.render_to_string('chimere/blocks/welcome.html', response_dct, - context_instance=RequestContext(request)) - def submited(request, area_name="", action=""): """ Successful submission page diff --git a/chimere/widgets.py b/chimere/widgets.py index 01a4bdb..41b2f92 100644 --- a/chimere/widgets.py +++ b/chimere/widgets.py @@ -22,13 +22,14 @@ Extra widgets and fields """ from django import conf from django import forms -from django.core.exceptions import ObjectDoesNotExist from django.conf import settings from django.contrib.gis.db import models from django.contrib.gis.geos import fromstr -from django.utils.html import conditional_escape +from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse from django.forms.widgets import RadioInput, RadioFieldRenderer from django.utils.encoding import force_unicode +from django.utils.html import conditional_escape from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ @@ -143,13 +144,10 @@ class ButtonSelectWidget(forms.RadioSelect): u"</script>\n</div>\n" % kwargs['attrs']['id'] return mark_safe(rendered) -class TextareaWidget(forms.Textarea): +class TextareaWidgetBase(forms.Textarea): """ Manage the edition of a text using TinyMCE """ - class Media: - js = ["%stiny_mce.js" % settings.TINYMCE_URL] - def render(self, *args, **kwargs): if 'attrs' not in kwargs: kwargs['attrs'] = {} @@ -173,7 +171,7 @@ tinyMCE.init({ """ return mark_safe(rendered) -class FullTextareaWidget(forms.Textarea): +class FullTextareaWidget(TextareaWidgetBase): """ Manage the edition of a text using TinyMCE """ @@ -200,6 +198,19 @@ tinyMCE.init({ """ return mark_safe(rendered) +class TextareaWidget(TextareaWidgetBase): + """ + Manage the edition of a text using TinyMCE + """ + class Media: + js = ["%stiny_mce.js" % settings.TINYMCE_URL, + "%schimere/js/textareas.js" % settings.STATIC_URL,] + +class TextareaAdminWidget(TextareaWidgetBase): + class Media: + js = ["%stiny_mce.js" % settings.TINYMCE_URL, + "%schimere/js/textareas_admin.js" % settings.STATIC_URL,] + class DatePickerWidget(forms.TextInput): """ Manage the edition of dates. @@ -347,6 +358,7 @@ class RouteChooserWidget(forms.TextInput): map_layers, default_area = get_map_layers(area_name) map_layers = [js for name, js, default in map_layers] js = """ + var extra_url = "%s"; OpenLayers.ImgPath = '%schimere/img/'; var EPSG_DISPLAY_PROJECTION = epsg_display_projection = new OpenLayers.Projection('EPSG:%s'); var EPSG_PROJECTION = epsg_projection = new OpenLayers.Projection('EPSG:%s'); @@ -358,7 +370,8 @@ class RouteChooserWidget(forms.TextInput): chimere_init_options['edition'] = true; chimere_init_options['edition_type_is_route'] = true; chimere_init_options["checked_categories"] = []; - """ % (settings.STATIC_URL, settings.CHIMERE_EPSG_DISPLAY_PROJECTION, + """ % ( reverse("chimere:index"), settings.STATIC_URL, + settings.CHIMERE_EPSG_DISPLAY_PROJECTION, settings.CHIMERE_EPSG_PROJECTION, settings.CHIMERE_DEFAULT_CENTER, settings.CHIMERE_DEFAULT_ZOOM, ", ".join(map_layers)) if default_area: @@ -463,9 +476,11 @@ class AreaWidget(forms.TextInput): """ class Media: css = { - "all": settings.OSM_CSS_URLS + ["%schimere/css/forms.css" % settings.STATIC_URL,] + "all": settings.OSM_CSS_URLS + \ + ["%schimere/css/forms.css" % settings.STATIC_URL,] } - js = settings.OSM_JS_URLS + ["%schimere/js/edit_area.js" % settings.STATIC_URL, + js = settings.OSM_JS_URLS + [ + "%schimere/js/edit_area.js" % settings.STATIC_URL, "%schimere/js/base.js" % settings.STATIC_URL,] def render(self, name, value, attrs=None): @@ -480,11 +495,24 @@ class AreaWidget(forms.TextInput): 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 + elif len(upper_left) == 2: + try: + upper_left_lon = float(upper_left[0]) + upper_left_lat = float(upper_left[1]) + except ValueError: + pass if hasattr(lower_right, 'x') and hasattr(lower_right, 'y'): lower_right_lon, lower_right_lat = lower_right.x, \ lower_right.y + elif len(lower_right) == 2: + lower_right_lon, lower_right_lat = lower_right + try: + lower_right_lon = float(lower_right[0]) + lower_right_lat = float(lower_right[1]) + except ValueError: + pass tpl = getMapJS() - tpl += u"<div id='map_edit'></div>\n"\ + tpl += u"</div>\n"\ u"<input type='hidden' name='upper_left_lat' id='upper_left_lat' "\ u"value='%f'/>\n"\ u"<input type='hidden' name='upper_left_lon' id='upper_left_lon' "\ @@ -494,13 +522,19 @@ class AreaWidget(forms.TextInput): u"<input type='hidden' name='lower_right_lon' id='lower_right_lon' "\ u"value='%f'/>\n" % ( upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon) - tpl += u"<script type='text/javascript'>\ninit();" + help_msg = _(u"Hold CTRL, click and drag to select area on the map") + tpl += u"<p>%s</p>\n" % help_msg + tpl += u"<script type='text/javascript'>\n" + tpl += u"$(document).ready(function($) {\ninit();\n" if value: tpl += u"var extent = new OpenLayers.Bounds(%f, %f, %f, %f);\n"\ u"extent.transform(epsg_display_projection, epsg_projection);\n"\ - u"map.zoomToExtent(extent, true);""" % (upper_left_lon, - upper_left_lat, lower_right_lon, lower_right_lat) - tpl += u"</script>\n<hr class='spacer'/>\n" + u"updateForm(extent);\n"\ + u"map.zoomToExtent(extent, true);\n"\ + u"map.zoomOut();" % (upper_left_lon, upper_left_lat, + lower_right_lon, lower_right_lat) + tpl += u"});\n</script>\n<hr class='spacer'/>\n" + tpl += u"<div id='map_edit'>\n" return mark_safe(tpl) def value_from_datadict(self, data, files, name): |
