diff options
Diffstat (limited to 'chimere')
26 files changed, 2456 insertions, 1349 deletions
diff --git a/chimere/actions.py b/chimere/actions.py index 824b14f..e83d8c3 100644 --- a/chimere/actions.py +++ b/chimere/actions.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2008-2013 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2008-2010 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as @@ -22,60 +22,53 @@ Actions available in the main interface """ from django.conf import settings from django.contrib.auth import models -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, NoReverseMatch from django.utils.translation import ugettext_lazy as _ -from chimere.models import Page, Map +from models import Page class Action: - def __init__(self, id, path, label, extra_url_args=[], - condition=None): + def __init__(self, id, path, label, extra_url_args=[]): self.id, self.path, self.label = id, path, label self.extra_url_args, self.url = extra_url_args, None - self.condition = condition - def update_url(self, map_name): - self.url = reverse(self.path, - args=[map_name + '/' if map_name else ''] + self.extra_url_args) + def update_url(self, area_name): + try: + self.url = reverse(self.path, + args=[area_name if area_name else ''] + self.extra_url_args) + except NoReverseMatch: + # backward url management + self.url = reverse(self.path, + args=[area_name + '/' if area_name else ''] + self.extra_url_args) -DEFAULT_ACTIONS = [[Action('view', 'chimere:index', _('View')), []], - [Action('contribute', 'chimere:edit', _('Contribute'), - condition=lambda user, map_name:bool( - Map.getAvailable(user=user, urn=map_name, single=True, - propose=True))), +default_actions = [(Action('view', 'chimere:index', _('View')), []), + (Action('contribute', 'chimere:edit', _('Contribute')), (Action('edit', 'chimere:edit', _('Add a new point of interest')), Action('edit-route', 'chimere:editroute', _('Add a new route'))), - ], - ] + ),] + +if hasattr(settings, 'CHIMERE_DIRECTORY') and settings.CHIMERE_DIRECTORY: + default_actions.append((Action('categories', 'chimere:category-directory', + _('Directory')), [])) if settings.CHIMERE_FEEDS: - DEFAULT_ACTIONS.append([Action('rss', 'chimere:feeds-form', - _('RSS feeds')), []]) + default_actions.append((Action('rss', 'chimere:feeds-form', + _('RSS feeds')), [])) if settings.EMAIL_HOST: - DEFAULT_ACTIONS.append([Action('contact', 'chimere:contact', - _('Contact us')), []],) + default_actions.append((Action('contact', 'chimere:contact', + _('Contact us')), []),) + -def actions(user, map_name='', default_actions=DEFAULT_ACTIONS): - acts, idx = [], -1 +def actions(area_name=''): + acts = default_actions[:] for act, childs in default_actions: - if act.id not in settings.CHIMERE_DEFAULT_ACTIONS: - continue - idx += 1 - if act.condition: - if not act.condition(user, map_name): - continue - act.update_url(map_name) + act.update_url(area_name) for child_act in childs: - child_act.update_url(map_name) - if "CHIMERE_DEFAULT_ACTION_LABEL" in dir(settings): - if len(settings.CHIMERE_DEFAULT_ACTION_LABEL) > idx: - act.label = settings.CHIMERE_DEFAULT_ACTION_LABEL[idx] - acts.append((act, childs)) + child_act.update_url(area_name) for page in Page.objects.filter(available=True).order_by('order'): act = Action(page.mnemonic, 'chimere:extra_page', page.title, [page.mnemonic]) - act.update_url(map_name) + act.update_url(area_name) acts.append((act, [])) - return acts diff --git a/chimere/admin.py b/chimere/admin.py index 2672306..60d1141 100644 --- a/chimere/admin.py +++ b/chimere/admin.py @@ -25,8 +25,7 @@ import datetime from django import forms from django.conf import settings from django.contrib import admin, messages -from django.contrib.auth.models import User, Group -from django.contrib.auth.admin import GroupAdmin +from django.contrib.admin import SimpleListFilter from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect @@ -38,30 +37,18 @@ try: except ImportError: pass -from chimere.forms import MarkerAdminForm, RouteAdminForm, MapAdminForm,\ +from chimere.forms import MarkerAdminForm, RouteAdminForm, AreaAdminForm,\ NewsAdminForm, CategoryAdminForm, ImporterAdminForm, OSMForm, \ PageAdminForm, PictureFileAdminForm, MultimediaFileAdminForm +from chimere import models from chimere.models import Category, Icon, SubCategory, Marker, \ - PropertyModel, News, Route, Map, ColorTheme, Color, \ - MultimediaFile, PictureFile, Importer, Layer, MapLayers,\ - PropertyModelChoice, MultimediaExtension, Page, MapUsers, MapGroups,\ - get_maps_for_user, get_users_by_map, ImporterKeyCategories + PropertyModel, News, Route, Area, ColorTheme, Color, \ + MultimediaFile, PictureFile, Importer, Layer, AreaLayers,\ + PropertyModelChoice, MultimediaExtension, Page,\ + get_areas_for_user, get_users_by_area, ImporterKeyCategories from chimere.utils import unicode_normalize, ShapefileManager, KMLManager,\ CSVManager -admin.site.unregister(Group) - -class UserInline(admin.StackedInline): - model = User.groups.through - verbose_name = _(u'User') - verbose_name_plural = _(u'User') - extra = 1 - -class GroupAdmin(GroupAdmin): - inlines = [ UserInline, ] - -admin.site.register(Group, GroupAdmin) - def disable(modeladmin, request, queryset): for item in queryset: item.status = 'D' @@ -99,18 +86,14 @@ def export_to_shapefile(modeladmin, request, queryset): return response export_to_shapefile.short_description = _(u"Export to Shapefile") -def _export_to_csv(cols=[]): - def func(modeladmin, request, queryset): - u""" - Export data to CSV - """ - filename, result = CSVManager.export(queryset, cols=cols) - response = HttpResponse(result, mimetype='text/csv') - response['Content-Disposition'] = 'attachment; filename=%s' % filename - return response - return func - -export_to_csv = _export_to_csv() +def export_to_csv(modeladmin, request, queryset): + u""" + Export data to CSV + """ + filename, result = CSVManager.export(queryset) + response = HttpResponse(result, mimetype='text/csv') + response['Content-Disposition'] = 'attachment; filename=%s' % filename + return response export_to_csv.short_description = _(u"Export to CSV") def managed_modified(modeladmin, request, queryset): @@ -195,13 +178,53 @@ class MultimediaInline(admin.TabularInline): ordering = ('order',) form = MultimediaFileAdminForm +class AreaMarkerListFilter(admin.SimpleListFilter): + title = _('area') + parameter_name = 'area' + + def lookups(self, request, model_admin): + return [(area.urn, area.name) for area in models.Area.objects.all()] + + def queryset(self, request, queryset): + try: + area = models.Area.objects.get(urn=self.value()) + except models.Area.DoesNotExist: + return queryset + return queryset.filter(area.getIncludeMarker()) + +class AreaRouteListFilter(AreaMarkerListFilter): + def queryset(self, request, queryset): + try: + area = models.Area.objects.get(urn=self.value()) + except models.Area.DoesNotExist: + return queryset + return queryset.filter(area.getIncludeRoute()) + +class HasCategoriesListFilter(SimpleListFilter): + title = _('Has categories') + parameter_name = 'has_category' + + def lookups(self, request, model_admin): + return ( + ('true', _('Yes')), + ('false', _('No')), + ) + + def queryset(self, request, queryset): + if self.value() == 'false': + return queryset.filter(categories__isnull=True) + elif self.value() == 'true': + return queryset.exclude(categories__isnull=True) + return queryset + class MarkerAdmin(admin.ModelAdmin): """ Specialized the Point field. """ search_fields = ("name",) list_display = ('name', 'status', 'start_date', 'end_date') - list_filter = ('status', 'categories', 'start_date', 'end_date') + list_filter = ('status', AreaMarkerListFilter, 'categories', + HasCategoriesListFilter, 'start_date', 'end_date') actions = [validate, disable, managed_modified, export_to_kml, export_to_shapefile, export_to_csv] exclude = ['submiter_session_key', 'import_key', 'import_version', @@ -211,7 +234,7 @@ class MarkerAdmin(admin.ModelAdmin): form = MarkerAdminForm fieldsets = ((None, { 'fields': ['point', 'name', 'status', 'categories', - 'description', 'weight', 'keywords', 'start_date', 'end_date'] + 'description', 'keywords', 'start_date', 'end_date'] }), (_(u"Submitter"), { 'classes':('collapse',), @@ -247,10 +270,10 @@ class MarkerAdmin(admin.ModelAdmin): def queryset(self, request): qs = self.model._default_manager.get_query_set() if not request.user.is_superuser: - maps = get_maps_for_user(request.user) + areas = get_areas_for_user(request.user) contained = Q() - for map in maps: - contained = contained | map.getIncludeMarker() + for area in areas: + contained = contained | area.getIncludeMarker() qs = qs.filter(contained) ordering = self.ordering or () if ordering: @@ -280,7 +303,7 @@ class RouteAdmin(MarkerAdmin): """ search_fields = ("name",) list_display = ('name', 'status') - list_filter = ('status', 'categories') + list_filter = ('status', AreaRouteListFilter, 'categories') exclude = ['height', 'width'] form = RouteAdminForm readonly_fields = ('associated_file', 'ref_item', 'has_associated_marker') @@ -312,10 +335,10 @@ class RouteAdmin(MarkerAdmin): def queryset(self, request): qs = self.model._default_manager.get_query_set() if not request.user.is_superuser: - maps = get_maps_for_user(request.user) + areas = get_areas_for_user(request.user) contained = Q() - for map in maps: - contained = contained | map.getIncludeRoute() + for area in areas: + contained = contained | area.getIncludeRoute() qs = qs.filter(contained) ordering = self.ordering or () if ordering: @@ -330,24 +353,16 @@ class RouteAdmin(MarkerAdmin): Route.objects.filter(pk=item_id)) class LayerInline(admin.TabularInline): - model = MapLayers - extra = 1 - -class UserInline(admin.TabularInline): - model = MapUsers - extra = 1 - -class GroupInline(admin.TabularInline): - model = MapGroups + model = AreaLayers extra = 1 -class MapAdmin(admin.ModelAdmin): +class AreaAdmin(admin.ModelAdmin): """ - Specialized the map field. + Specialized the area field. """ - form = MapAdminForm + form = AreaAdminForm exclude = ['upper_left_corner', 'lower_right_corner'] - inlines = [UserInline, GroupInline, LayerInline] + inlines = [LayerInline] list_display = ['name', 'order', 'available', 'default'] def importing(modeladmin, request, queryset): @@ -422,6 +437,7 @@ class ImporterAdmin(admin.ModelAdmin): readonly_fields = ('state',) actions = [importing, cancel_import, export_to_osm, cancel_export] inlines = [ImporterKeyInline] +admin.site.register(Importer, ImporterAdmin) class PageAdmin(admin.ModelAdmin): """ @@ -466,25 +482,15 @@ class PropertyModelChoiceInline(admin.TabularInline): class PropertyModelAdmin(admin.ModelAdmin): inlines = [PropertyModelChoiceInline] -# only register if not yet registered: this mecanism allow to specialized admin -# in projects -registered_models = admin.site._registry.keys() -for model, modeladmin in ((Importer, ImporterAdmin), - (Page, PageAdmin), - (News, NewsAdmin), - (Category, CategoryAdmin), - (Icon, IconAdmin), - (Marker, MarkerAdmin), - (Route, RouteAdmin), - (Map, MapAdmin), - (ColorTheme, ColorThemeAdmin), - (Layer, None)): - if model not in registered_models: - if modeladmin: - admin.site.register(model, modeladmin) - else: - admin.site.register(model) - -if PropertyModel not in registered_models and \ - not settings.CHIMERE_HIDE_PROPERTYMODEL: +# register of differents database fields +admin.site.register(Page, PageAdmin) +admin.site.register(News, NewsAdmin) +admin.site.register(Category, CategoryAdmin) +admin.site.register(Icon, IconAdmin) +admin.site.register(Marker, MarkerAdmin) +admin.site.register(Route, RouteAdmin) +if not settings.CHIMERE_HIDE_PROPERTYMODEL: admin.site.register(PropertyModel, PropertyModelAdmin) +admin.site.register(Area, AreaAdmin) +admin.site.register(ColorTheme, ColorThemeAdmin) +admin.site.register(Layer) diff --git a/chimere/locale/fr/LC_MESSAGES/django.po b/chimere/locale/fr/LC_MESSAGES/django.po index 913997d..0c5e884 100644 --- a/chimere/locale/fr/LC_MESSAGES/django.po +++ b/chimere/locale/fr/LC_MESSAGES/django.po @@ -1,5 +1,5 @@ # Chimère -# Copyright (C) 2008-2013 +# Copyright (C) 2008-2015 # This file is distributed under the same license as the Chimère package. # Étienne Loks <etienne.loks@peacefrogs.net>, 2008-2011. # @@ -7,18 +7,18 @@ msgid "" msgstr "" "Project-Id-Version: 0.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-10-27 20:17+0100\n" +"POT-Creation-Date: 2015-04-20 09:15+0200\n" "PO-Revision-Date: 2010-03-20 20:00+0100\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" -#: actions.py:41 +#: actions.py:44 msgid "View" msgstr "Voir" -#: actions.py:42 +#: actions.py:45 msgid "Contribute" msgstr "Participer" @@ -30,106 +30,110 @@ msgstr "Ajout d'un point remarquable" msgid "Add a new route" msgstr "Ajout d'un nouveau trajet" -#: actions.py:53 +#: actions.py:52 +msgid "Directory" +msgstr "Annuaire" + +#: actions.py:56 msgid "RSS feeds" msgstr "Flux RSS" -#: actions.py:57 +#: actions.py:60 msgid "Contact us" msgstr "Nous contacter" -#: admin.py:56 admin.py:57 -msgid "User" -msgstr "Utilisateur" - -#: admin.py:69 +#: admin.py:55 msgid "Disable" msgstr "Désactiver" -#: admin.py:75 templates/admin/chimere/managed_modified.html:44 +#: admin.py:61 templates/admin/chimere/managed_modified.html:44 #: templates/chimere/feeds/rss.html:70 msgid "Validate" msgstr "Valider" -#: admin.py:86 +#: admin.py:72 msgid "Export to KML" msgstr "Exporter en KML" -#: admin.py:100 +#: admin.py:86 msgid "Export to Shapefile" msgstr "Exporter en Shapefile" -#: admin.py:114 +#: admin.py:96 msgid "Export to CSV" msgstr "Exporter en CSV" -#: admin.py:121 +#: admin.py:103 msgid "Only one item can be managed at a time." msgstr "Seul un élément à la fois peut-être géré." -#: admin.py:131 +#: admin.py:113 msgid "No modified item associated to the selected item." msgstr "Pas d'élément modifié associé à l'élément sélectionné." -#: admin.py:177 +#: admin.py:159 msgid "Modified item traited." msgstr "Élément modifié traité." -#: admin.py:182 +#: admin.py:164 msgid "Managed modified items" msgstr "Gérer les éléments modifiés" -#: admin.py:216 admin.py:292 +#: admin.py:181 +msgid "area" +msgstr "zone" + +#: admin.py:221 admin.py:298 msgid "Submitter" msgstr "Demandeur" -#: admin.py:221 admin.py:297 admin.py:357 +#: admin.py:226 admin.py:303 admin.py:355 msgid "Import" msgstr "Import" -#: admin.py:226 admin.py:302 +#: admin.py:231 admin.py:308 msgid "Associated items" msgstr "Éléments associés" -#: admin.py:363 +#: admin.py:361 msgid "Cancel import" msgstr "Annuler l'import" -#: admin.py:369 +#: admin.py:367 msgid "Cancel export" msgstr "Annuler l'export" -#: admin.py:373 +#: admin.py:371 msgid "Can manage only one OSM export at a time." -msgstr "Ne peut gérer qu'un seul export OSM à la fois." +msgstr "Ne peux gérer qu'un seul export OSM à la fois." -#: admin.py:378 +#: admin.py:376 msgid "" "You must treat all item with the status \"imported\" before exporting to OSM." msgstr "" "Vous devez traiter tous les éléments avec le status « importé » avant " "d'exporter vers OSM." -#: admin.py:382 +#: admin.py:380 msgid "Only OSM importer are managed for export." msgstr "Seul les imports de type OSM peuvent être gérés pour les exports." -#: admin.py:389 +#: admin.py:387 msgid "No point of interest are concerned by this export." msgstr "Aucun point d'intérêt n'est concerné par cet export." -#: admin.py:401 +#: admin.py:399 msgid "Export launched." msgstr "Export lancé." -#: admin.py:405 +#: admin.py:403 #, python-format msgid "" "%s point(s) of interest concerned by this export before bounding box filter." msgstr "" "%s point(s) d'intérêt concerné par cet export (avant le filtre sur la zone)" -#: admin.py:410 +#: admin.py:408 msgid "Export to osm" msgstr "Exporter vers osm" @@ -145,50 +149,50 @@ msgstr "Nouveaux points d'intérêt de " msgid "Last points of interest by area" msgstr "Nouveaux points d'intérêt par zone" -#: forms.py:83 +#: forms.py:87 msgid "New submission for" msgstr "Nouvelle proposition pour" -#: forms.py:84 +#: forms.py:88 #, 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:86 +#: forms.py:90 msgid "To valid, precise or unvalid this item: " msgstr "Pour valider, préciser ou rejeter cet élément : " -#: forms.py:96 +#: forms.py:100 msgid "Email (optional)" msgstr "Courriel (optionnel) " -#: forms.py:97 +#: forms.py:101 msgid "Object" msgstr "Objet" -#: forms.py:117 +#: forms.py:121 msgid "OSM user" msgstr "Utilisateur OSM" -#: forms.py:118 models.py:1635 +#: forms.py:122 models.py:1552 msgid "Password" msgstr "Mot de passe" -#: forms.py:122 +#: forms.py:126 msgid "API" msgstr "API" -#: forms.py:125 +#: forms.py:129 #, python-format msgid "Test API - %s" msgstr "API de test - %s" -#: forms.py:127 +#: forms.py:131 #, python-format msgid "Main API - %s" msgstr "API principale - %s" -#: forms.py:158 forms.py:162 +#: forms.py:162 forms.py:166 msgid "" "For OSM import you must be provide a filter. Select an area and node/way " "filter." @@ -196,30 +200,30 @@ msgstr "" "Pour les imports OSM vous devez fournir un filtre. Sélectionnez une zone et " "un filtre sur les nœuds/routes." -#: forms.py:166 +#: forms.py:170 msgid "Shapefiles must be provided in a zipped archive." msgstr "" "Les fichiers Shapefiles doivent être fournis regroupés dans une archive zip." -#: forms.py:170 +#: forms.py:175 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:175 +#: forms.py:180 msgid "You have to set \"source\" or \"source file\"." msgstr "Vous devez spécifier le champ « Source » ou « Fichier source »." -#: forms.py:236 +#: forms.py:241 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:240 +#: forms.py:245 msgid "End date can't be before start date" msgstr "La date de fin ne peut pas être antérieure à la date de début" -#: forms.py:250 +#: forms.py:255 msgid "This field is mandatory for the selected categories" msgstr "Ce champ est obligatoire pour les catégories sélectionnées" @@ -231,16 +235,16 @@ msgstr "Fichier" 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:518 models.py:53 models.py:101 models.py:163 models.py:185 -#: models.py:198 models.py:213 models.py:378 models.py:752 models.py:808 -#: models.py:867 models.py:985 models.py:1343 models.py:1355 models.py:1624 -#: utils.py:487 templates/admin/chimere/managed_modified.html:23 -#: templates/chimere/edit.html:44 templates/chimere/edit_route.html:39 +#: forms.py:518 models.py:54 models.py:102 models.py:164 models.py:185 +#: models.py:198 models.py:213 models.py:424 models.py:773 models.py:829 +#: models.py:888 models.py:1006 models.py:1356 models.py:1368 models.py:1542 +#: utils.py:490 templates/admin/chimere/managed_modified.html:23 +#: templates/chimere/edit.html:40 templates/chimere/edit_route.html:37 #: templates/chimere/blocks/alternate_multimedia.html:39 msgid "Name" msgstr "Nom" -#: forms.py:527 +#: forms.py:527 models.py:1405 msgid "Area" msgstr "Zone" @@ -266,62 +270,62 @@ msgstr "Arrivée" msgid "Speed" msgstr "Vitesse" -#: models.py:54 +#: models.py:55 msgid "Mnemonic" msgstr "Mnémonique" -#: models.py:56 models.py:102 models.py:186 models.py:214 models.py:371 -#: models.py:756 models.py:1356 models.py:1626 models.py:1673 +#: models.py:57 models.py:103 models.py:186 models.py:214 models.py:417 +#: models.py:777 models.py:1374 models.py:1544 models.py:1587 msgid "Available" msgstr "Disponible" -#: models.py:57 models.py:173 models.py:187 models.py:233 models.py:810 -#: models.py:882 models.py:1362 models.py:1613 models.py:1625 +#: models.py:58 models.py:174 models.py:187 models.py:231 models.py:831 +#: models.py:903 models.py:1373 models.py:1531 models.py:1543 msgid "Order" msgstr "Ordre" -#: models.py:58 +#: models.py:59 msgid "Template path" msgstr "Chemin du patron" -#: models.py:65 models.py:66 +#: models.py:66 models.py:67 msgid "Page" msgstr "Page" -#: models.py:103 models.py:474 +#: models.py:104 models.py:520 msgid "Is front page" msgstr "Est en page principale" -#: models.py:105 models.py:1636 +#: models.py:106 models.py:1553 msgid "Date" msgstr "Date" -#: models.py:107 models.py:809 +#: models.py:108 models.py:830 msgid "Url" msgstr "Url" -#: models.py:108 -msgid "Associated maps" -msgstr "Cartes associées" +#: models.py:109 +msgid "Associated areas" +msgstr "Zones associées" -#: models.py:114 models.py:115 templates/chimere/blocks/news.html:3 +#: models.py:115 models.py:116 templates/chimere/blocks/news.html:3 #: templates/chimere/blocks/news.html:5 msgid "News" -msgstr "Nouvelle" +msgstr "Actualités" -#: models.py:124 +#: models.py:125 msgid "Parameters" msgstr "Paramètres" -#: models.py:128 +#: models.py:129 msgid "TinyUrl" msgstr "Mini-url" -#: models.py:167 models.py:174 models.py:228 +#: models.py:168 models.py:175 models.py:226 msgid "Color theme" msgstr "Thème de couleur" -#: models.py:172 +#: models.py:173 msgid "Code" msgstr "Code" @@ -329,24 +333,24 @@ msgstr "Code" msgid "Color" msgstr "Couleur" -#: models.py:193 models.py:211 +#: models.py:193 models.py:211 models.py:410 msgid "Category" msgstr "Catégorie" -#: models.py:199 models.py:748 models.py:868 models.py:1051 +#: models.py:199 models.py:769 models.py:889 models.py:1072 #: templates/chimere/blocks/alternate_multimedia.html:43 msgid "Image" msgstr "Image" -#: models.py:201 models.py:870 models.py:1053 +#: models.py:201 models.py:891 models.py:1074 msgid "Height" msgstr "Hauteur" -#: models.py:202 models.py:871 models.py:1054 +#: models.py:202 models.py:892 models.py:1075 msgid "Width" msgstr "Largeur" -#: models.py:206 models.py:225 +#: models.py:206 models.py:223 msgid "Icon" msgstr "Icône" @@ -355,42 +359,42 @@ msgid "Available for submission" msgstr "Disponible pour soumission" #: models.py:217 -msgid "Has an associated quantity" -msgstr "A une quantité associée" - -#: models.py:219 msgid "Marker" msgstr "Point d'intérêt" -#: models.py:220 models.py:1047 models.py:1064 -#: templates/chimere/edit_route.html:30 +#: models.py:218 models.py:1068 models.py:1085 +#: templates/chimere/edit_route.html:28 msgid "Route" msgstr "Trajet" -#: models.py:221 +#: models.py:219 msgid "Both" msgstr "Mixte" -#: models.py:222 +#: models.py:220 msgid "Item type" msgstr "Type d'élément" -#: models.py:223 +#: models.py:221 msgid "Is dated" msgstr "Est daté" -#: models.py:226 +#: models.py:224 msgid "Hover icon" msgstr "Icône en survol" -#: models.py:230 +#: models.py:228 msgid "Displayed in the layer menu" msgstr "Apparaît dans le menu des couches ?" -#: models.py:232 +#: models.py:230 msgid "Routing warn" msgstr "Avertissement sur les itinéraires" +#: models.py:232 models.py:435 templates/chimere/edit.html:56 +msgid "Keywords" +msgstr "Mots clés" + #: models.py:238 msgid "Sub-category" msgstr "Sous-catégorie" @@ -399,335 +403,351 @@ msgstr "Sous-catégorie" msgid "Sub-categories" msgstr "Sous-catégories" -#: models.py:323 +#: models.py:336 msgid "Importer type" msgstr "Type d'import" -#: models.py:325 +#: models.py:338 msgid "Filter" msgstr "Filtre" -#: models.py:327 templates/chimere/blocks/alternate_multimedia.html:49 +#: models.py:340 templates/chimere/blocks/alternate_multimedia.html:49 msgid "Web address" msgstr "Adresse web" -#: models.py:329 +#: models.py:342 +msgid "Don't forget the trailing slash" +msgstr "N'oubliez pas la barre oblique (« / ») finale" + +#: models.py:343 msgid "Source file" msgstr "Fichier source" -#: models.py:331 +#: models.py:345 +msgid "Alt source file" +msgstr "Fichier source alternatif" + +#: models.py:347 msgid "Name by default" msgstr "Nom par défaut" -#: models.py:333 +#: models.py:349 msgid "SRID" msgstr "SRID" -#: models.py:334 +#: models.py:350 msgid "Zipped file" msgstr "Fichier zippé" -#: models.py:335 +#: models.py:351 msgid "Overwrite existing data" msgstr "Écraser les données existantes" -#: models.py:337 +#: models.py:353 msgid "Get description from source" msgstr "Obtenir une description depuis la source" -#: models.py:339 +#: models.py:355 msgid "Default description" msgstr "Description par défaut" -#: models.py:341 models.py:399 +#: models.py:357 models.py:447 msgid "Origin" msgstr "Origine" -#: models.py:343 models.py:401 +#: models.py:359 models.py:449 msgid "License" msgstr "Licence" -#: models.py:346 +#: models.py:362 msgid "Associated subcategories" msgstr "Sous-catégories associées" -#: models.py:347 utils.py:491 +#: models.py:363 utils.py:494 msgid "State" msgstr "État" -#: models.py:349 +#: models.py:364 msgid "Automatically associate a marker to a way" msgstr "Associer automatiquement un marqueur à une route" -#: models.py:353 +#: models.py:366 +msgid "Automatically updated" +msgstr "Mis à jour automatiquement" + +#: models.py:368 +msgid "Default localisation" +msgstr "Localisation par défaut" + +#: models.py:374 models.py:408 msgid "Importer" msgstr "Import" -#: models.py:370 +#: models.py:411 models.py:437 +msgid "Import key" +msgstr "Clé d'import" + +#: models.py:414 +msgid "Importer - Key categories" +msgstr "Importeur - clés / catégories" + +#: models.py:416 msgid "Submited" msgstr "Soumis" -#: models.py:372 +#: models.py:418 msgid "Modified" msgstr "Modifié" -#: models.py:373 +#: models.py:419 msgid "Disabled" msgstr "Désactivé" -#: models.py:374 +#: models.py:420 msgid "Imported" msgstr "Importé" -#: models.py:380 +#: models.py:426 msgid "Submitter session key" msgstr "Clé de session du demandeur" -#: models.py:382 +#: models.py:428 msgid "Submitter name or nickname" msgstr "Nom ou pseudo du demandeur" -#: models.py:384 +#: models.py:430 msgid "Submitter email" msgstr "Courriel du demandeur" -#: models.py:386 +#: models.py:432 msgid "Submitter comment" msgstr "Commentaire du demandeur" -#: models.py:388 models.py:1234 +#: models.py:434 models.py:1248 msgid "Status" msgstr "État" -#: models.py:389 -msgid "Import key" -msgstr "Clé d'import" - -#: models.py:391 +#: models.py:439 msgid "Import version" msgstr "Version de l'import" -#: models.py:393 +#: models.py:441 msgid "Source" msgstr "Source" -#: models.py:395 +#: models.py:443 msgid "Modified since last import" msgstr "Modifié depuis le dernier import" -#: models.py:397 +#: models.py:445 msgid "Not to be exported to OSM" msgstr "À ne pas exporter vers OSM" -#: models.py:403 templates/chimere/edit.html:61 -#: templates/chimere/edit_route.html:55 +#: models.py:451 templates/chimere/edit.html:63 +#: templates/chimere/edit_route.html:53 msgid "Start date" msgstr "Date de début" -#: models.py:404 +#: models.py:452 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:406 templates/chimere/edit.html:67 -#: templates/chimere/edit_route.html:61 +#: models.py:454 templates/chimere/edit.html:69 +#: templates/chimere/edit_route.html:59 msgid "End date" msgstr "Date de fin" -#: models.py:407 +#: models.py:455 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:464 +#: models.py:512 msgid "Reference marker" msgstr "Point d'intérêt de référence" -#: models.py:465 utils.py:493 +#: models.py:513 utils.py:496 msgid "Localisation" msgstr "Localisation" -#: models.py:467 +#: models.py:515 msgid "Available Date" msgstr "Date de mise en disponibilité" -#: models.py:471 -msgid "Quantity" -msgstr "Quantité" - -#: models.py:473 utils.py:492 templates/admin/chimere/managed_modified.html:31 -#: templates/chimere/edit.html:54 templates/chimere/edit_route.html:49 +#: models.py:519 utils.py:495 templates/admin/chimere/managed_modified.html:31 +#: templates/chimere/edit.html:50 templates/chimere/edit_route.html:47 msgid "Description" msgstr "Description" -#: models.py:548 models.py:1683 +#: models.py:590 models.py:1597 msgid "Point of interest" msgstr "Point d'intérêt" -#: models.py:746 +#: models.py:767 msgid "Audio" msgstr "Audio" -#: models.py:747 +#: models.py:768 msgid "Video" msgstr "Vidéo" -#: models.py:749 +#: models.py:770 msgid "Other" msgstr "Autre" -#: models.py:750 +#: models.py:771 msgid "Media type" msgstr "Type de media" -#: models.py:753 +#: models.py:774 msgid "Mime type" msgstr "Type mime" -#: models.py:755 +#: models.py:776 msgid "Inside an iframe" msgstr "À l'intérieur d'un iframe" -#: models.py:759 +#: models.py:780 msgid "Multimedia type" msgstr "Type de multimedia" -#: models.py:760 +#: models.py:781 msgid "Multimedia types" msgstr "Types de multimedia" -#: models.py:769 +#: models.py:790 msgid "Automatic recognition" msgstr "Reconnaissance automatique" -#: models.py:795 +#: models.py:816 msgid "Extension name" msgstr "Nom de l'extension" -#: models.py:797 +#: models.py:818 msgid "Associated multimedia type" msgstr "Type de multimedia associé" -#: models.py:801 +#: models.py:822 msgid "Multimedia extension" msgstr "Extension multimedia" -#: models.py:802 +#: models.py:823 msgid "Multimedia extensions" msgstr "Extensions multimedia" -#: models.py:812 models.py:872 +#: models.py:833 models.py:893 msgid "Display inside the description?" msgstr "Apparaît dans la description ?" -#: models.py:817 +#: models.py:838 msgid "Multimedia file" msgstr "Fichier multimedia" -#: models.py:818 +#: models.py:839 msgid "Multimedia files" msgstr "Fichiers multimedias" -#: models.py:874 +#: models.py:895 msgid "Thumbnail" msgstr "Miniature" -#: models.py:878 +#: models.py:899 msgid "Thumbnail height" msgstr "Hauteur de la miniature" -#: models.py:880 +#: models.py:901 msgid "Thumbnail width" msgstr "Largeur de la miniature" -#: models.py:889 +#: models.py:910 msgid "Picture file" msgstr "Fichier d'image" -#: models.py:890 +#: models.py:911 msgid "Picture files" msgstr "Fichiers d'image" -#: models.py:986 +#: models.py:1007 msgid "Raw file (gpx or kml)" msgstr "Fichier brut (gpx ou kml)" -#: models.py:988 +#: models.py:1009 msgid "Simplified file" msgstr "Fichier simplifié" -#: models.py:990 +#: models.py:1011 msgid "KML" msgstr "KML" -#: models.py:990 +#: models.py:1011 msgid "GPX" msgstr "GPX" -#: models.py:995 +#: models.py:1016 msgid "Route file" msgstr "Fichier de trajet" -#: models.py:996 +#: models.py:1017 msgid "Route files" msgstr "Fichiers de trajet" -#: models.py:1046 +#: models.py:1067 msgid "Reference route" msgstr "Trajet de référence" -#: models.py:1050 +#: models.py:1071 msgid "Associated file" msgstr "Fichier associé" -#: models.py:1055 +#: models.py:1076 msgid "Has an associated marker" msgstr "Dispose d'un marqueur associé" -#: models.py:1344 +#: models.py:1357 msgid "Layer code" msgstr "Code pour la couche" -#: models.py:1350 +#: models.py:1363 msgid "Layer" msgstr "Couche" -#: models.py:1358 -msgid "Map urn" -msgstr "Urn de la carte" +#: models.py:1369 +msgid "Area urn" +msgstr "Urn de la zone" -#: models.py:1360 templates/chimere/blocks/welcome.html:3 +#: models.py:1371 templates/chimere/blocks/welcome.html:3 msgid "Welcome message" msgstr "Message d'accueil" -#: models.py:1363 +#: models.py:1375 msgid "Upper left corner" msgstr "Coin en haut à gauche" -#: models.py:1365 +#: models.py:1377 msgid "Lower right corner" msgstr "Coin en bas à droite" -#: models.py:1367 -msgid "Default map" -msgstr "Carte par défaut" +#: models.py:1379 +msgid "Default area" +msgstr "Zone par défaut" -#: models.py:1368 -msgid "Only one map is set by default" -msgstr "Seule une carte est définie par défaut" +#: models.py:1380 +msgid "Only one area is set by default" +msgstr "Seule une zone est définie par défaut" -#: models.py:1372 +#: models.py:1384 msgid "Sub-categories checked by default" msgstr "Sous-catégories cochées par défaut" -#: models.py:1374 +#: models.py:1386 msgid "Sub-categories dynamicaly displayed" msgstr "Sous-categories affichées dynamiquement" -#: models.py:1375 +#: models.py:1387 msgid "" "If checked, categories are only displayed in the menu if they are available " "on the current extent." @@ -735,146 +755,106 @@ msgstr "" "Si coché, les catégories sont disponibles sur le menu seulement si elles " "apparaissent sur la zone affichée." -#: models.py:1379 models.py:1630 +#: models.py:1391 models.py:1547 msgid "Restricted to theses sub-categories" msgstr "Restreindre à ces sous-categories" -#: models.py:1380 +#: models.py:1392 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:1382 +#: models.py:1394 msgid "Link to an external CSS" msgstr "Lien vers une feuille de style externe" -#: models.py:1386 -msgid "Public can read the map" -msgstr "Carte lisible publiquement" - -#: models.py:1387 -msgid "Public can propose item to the map" -msgstr "Des propositions de modification peuvent être faites publiquement" - -#: models.py:1388 -msgid "Public can write without moderation to the map" -msgstr "Des modifications peuvent être faites publiquement" - -#: models.py:1389 +#: models.py:1396 msgid "Restrict to the area extent" msgstr "Restreindre à l'étendue de la zone" -#: models.py:1398 templates/chimere/blocks/footer.html:2 -msgid "Map" -msgstr "Carte" - -#: models.py:1593 models.py:1603 -msgid "Can read the map" -msgstr "Peut lire la carte" - -#: models.py:1594 models.py:1604 -msgid "Can propose item to the map" -msgstr "Peut proposer des éléments sur la carte" - -#: models.py:1595 models.py:1605 -msgid "Can write without moderation to the map" -msgstr "Peut écrire sans modération sur la carte" - -#: models.py:1597 -msgid "Map - user" -msgstr "Carte - Utilisateur" - -#: models.py:1598 -msgid "Map - users" -msgstr "Cartes - Utilisateurs" - -#: models.py:1607 -msgid "Map - group" -msgstr "Carte - Groupe" - -#: models.py:1608 -msgid "Map - groups" -msgstr "Carte - Groupes" - -#: models.py:1614 widgets.py:89 +#: models.py:1532 widgets.py:89 msgid "Default layer" msgstr "Couche par défaut" -#: models.py:1618 models.py:1619 +#: models.py:1536 models.py:1537 msgid "Layers" msgstr "Couches" -#: models.py:1627 +#: models.py:1545 msgid "Mandatory" msgstr "Obligatoire" -#: models.py:1631 +#: models.py:1548 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:1633 +#: models.py:1550 msgid "Text" msgstr "Texte" -#: models.py:1634 +#: models.py:1551 msgid "Long text" msgstr "Texte long" -#: models.py:1637 +#: models.py:1554 msgid "Choices" msgstr "Choix" -#: models.py:1645 +#: models.py:1555 +msgid "Boolean" +msgstr "Booléen" + +#: models.py:1564 msgid "Type" msgstr "Type" -#: models.py:1650 models.py:1671 models.py:1685 +#: models.py:1569 models.py:1585 models.py:1599 msgid "Property model" msgstr "Modèle de propriété" -#: models.py:1672 models.py:1686 +#: models.py:1586 models.py:1600 msgid "Value" msgstr "Valeur" -#: models.py:1678 +#: models.py:1592 msgid "Model property choice" msgstr "Choix pour les modèles de propriété" -#: models.py:1701 +#: models.py:1611 msgid "Property" msgstr "Propriété" -#: settings.sample.py:86 +#: settings.sample.py:94 msgid "Foot" -msgstr "À pied" +msgstr "À pieds" -#: settings.sample.py:87 +#: settings.sample.py:95 msgid "Bicycle" msgstr "À vélo" -#: settings.sample.py:88 +#: settings.sample.py:96 msgid "Motorcar" msgstr "En voiture" -#: settings.sample.py:91 +#: settings.sample.py:99 msgid "You are walking slowly" msgstr "Vous marchez lentement" -#: settings.sample.py:92 +#: settings.sample.py:100 msgid "You are walking pretty quickly" -msgstr "Vous marchez assez rapidement" +msgstr "Vous marchez plutôt rapidement" -#: settings.sample.py:93 +#: settings.sample.py:101 msgid "You are riding pretty slowly" -msgstr "Vous roulez plutôt lentement" +msgstr "Vous conduisez plutôt lentement" -#: settings.sample.py:94 +#: settings.sample.py:102 msgid "You are riding pretty quickly" -msgstr "Vous roulez plutôt rapidement" +msgstr "Vous conduisez plutôt rapidement" #: tasks.py:63 msgid "Import pending" @@ -926,28 +906,28 @@ msgstr "Export échoué" msgid "Export canceled" msgstr "Export annulé" -#: utils.py:150 utils.py:199 +#: utils.py:153 utils.py:202 msgid "Bad zip file" msgstr "Mauvais fichier zip" -#: utils.py:202 +#: utils.py:205 msgid "Missing file(s) inside the zip file" msgstr "Fichier(s) manquant(s) dans l'archive zip" -#: utils.py:243 +#: utils.py:246 msgid "Bad XML file" msgstr "Mauvais fichier XML" -#: utils.py:330 +#: utils.py:333 msgid "Error while reading the data source." msgstr "Erreur lors de la lecture de la source." -#: utils.py:348 +#: utils.py:351 #, python-format msgid "SRID cannot be guessed. The default SRID (%s) has been used." msgstr "Le SRID n'a pu être trouvé. Le SRID par défaut (%s) a été utilisé." -#: utils.py:369 +#: utils.py:372 #, python-format msgid "" "Type of geographic item (%s) of this shapefile is not managed by Chimère." @@ -955,44 +935,42 @@ msgstr "" "Les types des éléments géographiques (%s) de ce fichier Shapefile ne sont " "pas gérés par Chimère." -#: utils.py:389 +#: utils.py:392 msgid "Bad Shapefile" msgstr "Mauvais fichier Shapefile" -#: utils.py:431 +#: utils.py:434 msgid "Could not create file!" msgstr "Ne peut pas créer le fichier !" -#: utils.py:442 +#: utils.py:445 msgid "Failed to create field" msgstr "Ne peut pas créer un champ" -#: utils.py:488 templates/admin/chimere/managed_modified.html:25 -#: templates/chimere/edit.html:49 templates/chimere/edit_route.html:44 -#: templates/chimere/main_map.html:26 +#: utils.py:491 templates/admin/chimere/managed_modified.html:25 +#: templates/chimere/edit.html:45 templates/chimere/edit_route.html:42 +#: templates/chimere/main_map.html:16 #: templates/chimere/main_map_simple.html:10 msgid "Categories" msgstr "Catégories" -#: utils.py:529 -msgid "Invalid CSV format - not enough columns check a reference CSV file" -msgstr "" -"Format CSV invalide - pas assez de colonnes - vérifiez sur un fichier CSV de " -"référence" +#: utils.py:524 +msgid "Invalid CSV format" +msgstr "Fichier CSV non valide" -#: utils.py:630 +#: utils.py:603 msgid "RSS feed is not well formed" msgstr "Flux RSS non valide" -#: utils.py:706 +#: utils.py:679 msgid "Nothing to import" msgstr "Rien à importer" -#: utils.py:790 +#: utils.py:763 msgid "New items imported - validate them before exporting" msgstr "Nouveaux éléments importés - valider ceux-ci avant d'exporter" -#: utils.py:792 +#: utils.py:765 msgid "" "There are items from a former import not yet validated - validate them " "before exporting" @@ -1000,19 +978,19 @@ msgstr "" "Il y a des éléments d'un import précédent pas encore validé - Validez les " "avant d'exporter" -#: utils.py:804 +#: utils.py:777 msgid "Bad params - programming error" msgstr "Mauvais paramètres - erreur de programmation" -#: utils.py:814 +#: utils.py:787 msgid "Bad param" msgstr "Mauvais paramètre" -#: utils.py:829 +#: utils.py:802 msgid "No non ambigious tag is defined in the XAPI request" msgstr "Pas de tag non ambigü définis dans la requête XAPI" -#: utils.py:831 +#: utils.py:804 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" @@ -1021,23 +999,40 @@ msgstr "" "vouloir lancer la requête sur la planète entière fixez la « bounding box » " "à -180,-90,180,90" -#: views.py:161 -msgid "Invalid user or password." -msgstr "Nom d'utilisateur ou mot de passe incorrect" +#: utils.py:933 +msgid "Source page is unreachable." +msgstr "La page source est inatteignable" + +#: utils.py:949 +msgid "The source file is not a valid XSLT file." +msgstr "Le fichier source n'est pas un fichier XSLT valide" + +#: utils.py:961 +msgid "The alt source file is not a valid XSLT file." +msgstr "Le fichier source alternatif n'est pas un fichier XSLT valide" -#: views.py:315 +#: utils.py:1005 +#, python-format +msgid "" +"Names \"%s\" doesn't match existing categories. Modify the import to match " +"theses names with categories." +msgstr "" +"Les noms \"%s\" ne correspondent pas à des catégories existantes. Modifiez " +"l'import pour faire correspondre ces noms avec des catégories." + +#: views.py:302 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:405 +#: views.py:387 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:521 +#: views.py:502 msgid "Comments/request on the map" msgstr "Commentaires/requètes sur la carte" -#: views.py:524 +#: views.py:505 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." @@ -1046,52 +1041,60 @@ msgstr "" "laissé votre courriel vous serez peut-être contacté bientôt pour plus de " "détails." -#: views.py:528 +#: views.py:509 msgid "Temporary error. Renew your message later." msgstr "Erreur temporaire. Réenvoyez votre message plus tard." -#: views.py:722 +#: views.py:715 msgid "No category available in this area." msgstr "Pas de catégorie disponible sur cette zone." -#: views.py:822 +#: views.py:842 +msgid "Category does not exist" +msgstr "Cette catégorie n'existe pas" + +#: views.py:900 msgid "Bad geometry" msgstr "Géométrie incorrecte" -#: views.py:911 +#: views.py:985 msgid "Incorrect choice in the list" msgstr "Choix incorrect dans la liste" -#: widgets.py:272 +#: widgets.py:243 +msgid "Street, City, Country" +msgstr "Rue, Commune, Pays" + +#: widgets.py:281 msgid "Latitude" msgstr "Latitude" -#: widgets.py:274 +#: widgets.py:283 msgid "Longitude" msgstr "Longitude" -#: widgets.py:302 +#: widgets.py:326 msgid "Invalid point" msgstr "Point invalide" -#: widgets.py:359 +#: widgets.py:382 msgid "Creation mode" msgstr "Mode création" -#: widgets.py:360 +#: widgets.py:383 msgid "To start drawing the route click on the toggle button: \"Draw\"." msgstr "" "Pour commencer le dessin cliquez sur le bouton : « Tracer »." -#: widgets.py:362 +#: widgets.py:385 msgid "Then click on the map to begin the drawing." msgstr "Puis cliquez sur la carte pour commencer le dessin." -#: widgets.py:363 +#: widgets.py:386 msgid "You can add points by clicking again." msgstr "Vous pouvez ajouter des points en cliquant de nouveau." -#: widgets.py:364 +#: widgets.py:387 msgid "" "To finish the drawing double click. When the drawing is finished you can " "edit it." @@ -1099,7 +1102,7 @@ msgstr "" "Pour finir le tracé double-cliquez. Quand le tracé est fini vous pouvez " "toujours l'éditer." -#: widgets.py:366 +#: widgets.py:389 msgid "" "While creating to undo a drawing click again on the toggle button \"Stop " "drawing\"." @@ -1107,17 +1110,17 @@ msgstr "" "En mode création vous pouvez annuler un tracé en appuyant sur le bouton " "« Arrêter le tracé »." -#: widgets.py:371 +#: widgets.py:394 msgid "Modification mode" msgstr "Mode modification" -#: widgets.py:372 +#: widgets.py:395 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:373 +#: widgets.py:396 msgid "" "To delete a point move the mouse cursor over it and press the \"d\" or \"Del" "\" key." @@ -1125,7 +1128,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:375 +#: widgets.py:398 msgid "" "To add a point click in the middle of a segment and drag the new point to " "the desired position" @@ -1134,51 +1137,51 @@ msgstr "" "maintenez le bouton appuyé et déplacez le nouveau point à la position " "désirée." -#: widgets.py:382 +#: widgets.py:405 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:385 +#: widgets.py:408 msgid "Upload a route file (GPX or KML)" msgstr "Déposer un trajet (fichier GPX ou KML)" -#: widgets.py:386 +#: widgets.py:409 msgid "or" msgstr "ou" -#: widgets.py:391 +#: widgets.py:414 msgid "Start \"hand\" drawing" msgstr "Commencer le tracé manuellement" -#: widgets.py:414 +#: widgets.py:437 msgid "Move on the map" msgstr "Se déplacer" -#: widgets.py:414 +#: widgets.py:437 msgid "Draw" msgstr "Tracer" -#: widgets.py:504 +#: widgets.py:527 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:561 +#: widgets.py:584 msgid "Type:" msgstr "Type :" -#: widgets.py:561 +#: widgets.py:584 msgid "Node" msgstr "Nœud" -#: widgets.py:562 +#: widgets.py:585 msgid "Way" msgstr "Route" -#: widgets.py:573 +#: widgets.py:596 msgid "" "Enter an OSM \"tag=value\" string such as \"amenity=pub\". A list of common " "tag is available <a href='https://wiki.openstreetmap.org/wiki/Map_Features' " @@ -1188,39 +1191,39 @@ msgstr "" "liste des clés est disponible <a href='https://wiki.openstreetmap.org/wiki/" "FR:Map_Features' target='_blank'>ici</a>." -#: widgets.py:580 +#: widgets.py:603 msgid "Tag:" msgstr "Clé/valeur :" -#: widgets.py:584 +#: widgets.py:607 msgid "You have to select an area." msgstr "Vous devez sélectionner une zone." -#: widgets.py:586 +#: widgets.py:609 msgid "You have to select a type." msgstr "Vous devez sélectionner un type." -#: widgets.py:588 +#: widgets.py:611 msgid "You have to insert a filter tag." msgstr "Vous devez saisir une clé=valeur." -#: widgets.py:590 +#: widgets.py:613 msgid "If you change the above form don't forget to refresh before submit!" msgstr "" "Si vous modifiez le formulaire ci-dessus n'oubliez pas de rafraîchir avant " "de valider !" -#: widgets.py:593 +#: widgets.py:616 msgid "You can put a Folder name of the KML file to filter on it." msgstr "" "Vous pouvez saisir le nom d'un « Folder » du fichier KML pour filter sur " "celui-ci." -#: widgets.py:601 +#: widgets.py:624 msgid "Refresh" msgstr "Rafraîchir" -#: widgets.py:667 +#: widgets.py:690 msgid "Select..." msgstr "Sélectionner..." @@ -1315,92 +1318,94 @@ msgstr "" "Après ajout/modification de modèle de propriété vous aurez à recharger le " "serveur web." -#: templates/chimere/base.html:12 +#: templates/chimere/base.html:15 msgid "You must enable JavaScript in your browser to display Chimère." msgstr "" "Vous devez activer le JavaScript dans votre navigateur pour afficher Chimère." -#: templates/chimere/contactus.html:16 -msgid "" -"If you have some requests or remarks about this site you can leave them here." -msgstr "" -"Si vous avez des requètes, des remarques à propos de ce site vous pouvez " -"nous laisser un commentaire ici." - -#: templates/chimere/contactus.html:19 -msgid "Submit" -msgstr "Proposer" +#: templates/chimere/category_directory.html:15 +msgid "No category defined!" +msgstr "Pas de catégorie existante !" -#: templates/chimere/detail.html:16 +#: templates/chimere/category_item_detail.html:17 +#: templates/chimere/detail.html:17 msgid "Date:" msgstr "Date :" -#: templates/chimere/detail.html:25 +#: templates/chimere/category_item_detail.html:26 +#: templates/chimere/detail.html:26 msgid "Source:" msgstr "Source :" -#: templates/chimere/detail.html:26 +#: templates/chimere/category_item_detail.html:27 +#: templates/chimere/detail.html:27 msgid "License:" msgstr "Licence :" -#: templates/chimere/detail.html:28 -msgid "Show multimedia gallery" -msgstr "Montrer la galerie multimedia" - -#: templates/chimere/detail.html:33 -msgid "Edit" -msgstr "Modifier" +#: templates/chimere/category_item_detail.html:29 +msgid "See on the map" +msgstr "Voir sur la carte" +#: templates/chimere/category_item_detail.html:31 #: templates/chimere/detail.html:34 msgid "Submit an amendment" msgstr "Proposer une modification" -#: templates/chimere/detail.html:38 templates/chimere/detail.html.py:39 +#: templates/chimere/category_item_detail.html:34 +#: templates/chimere/category_item_detail.html:35 +#: templates/chimere/detail.html:37 templates/chimere/detail.html.py:38 msgid "Propose amendment" msgstr "Proposer une modification" -#: templates/chimere/detail.html:38 +#: templates/chimere/category_item_detail.html:34 +#: templates/chimere/detail.html:37 msgid "I would like to propose an amendment for this item:" msgstr "Je souhaiterais proposer une modification pour cet élément :" -#: templates/chimere/edit.html:22 +#: templates/chimere/contactus.html:16 +msgid "" +"If you have some requests or remarks about this site you can leave them here." +msgstr "" +"Si vous avez des requètes, des remarques à propos de ce site vous pouvez " +"nous laisser un commentaire ici." + +#: templates/chimere/contactus.html:19 +msgid "Submit" +msgstr "Proposer" + +#: templates/chimere/detail.html:29 +msgid "Show multimedia gallery" +msgstr "Montrer la galerie multimedia" + +#: templates/chimere/edit.html:20 msgid "Error" msgstr "Erreur" -#: templates/chimere/edit.html:25 +#: templates/chimere/edit.html:23 templates/chimere/edit_route.html:20 msgid "" -"You have write rights for this map. Your modifications will be taking into " +"You are logged as an administrator. Your modifications will be taking into " "account immediately." msgstr "" -"Vous avez les droits d'écriture sur cette carte. Vos modifications vont être " -"prises en compte immédiatement." +"Vous êtes connecté comme administrateur. Vos modifications vont être prises " +"en compte immédiatement." -#: templates/chimere/edit.html:27 +#: templates/chimere/edit.html:25 msgid "Modify a point of interest" msgstr "Modifier un point d'intérêt" -#: templates/chimere/edit.html:27 +#: templates/chimere/edit.html:25 msgid "Add a point of interest" msgstr "Ajout d'un point d'intérêt" -#: templates/chimere/edit.html:29 templates/chimere/edit.html.py:180 -msgid "Add/modify" -msgstr "Ajouter - Modifier" - -#: templates/chimere/edit.html:29 templates/chimere/edit.html.py:180 -#: templates/chimere/edit_route.html:103 -msgid "Propose" -msgstr "Proposez" - -#: templates/chimere/edit.html:34 +#: templates/chimere/edit.html:31 msgid "Point" msgstr "Point" -#: templates/chimere/edit.html:35 templates/chimere/edit_route.html:31 +#: templates/chimere/edit.html:32 templates/chimere/edit_route.html:29 msgid "Select a location for this new site" msgstr "Choisissez une localisation pour ce nouveau site" -#: templates/chimere/edit.html:42 templates/chimere/edit_route.html:37 +#: templates/chimere/edit.html:38 templates/chimere/edit_route.html:35 msgid "indicates a mandatory field" msgstr "indique un champ obligatoire" @@ -1433,46 +1438,22 @@ msgstr "Commentaires au sujet de votre proposition" msgid "Upload in progress. Please wait..." msgstr "Dépôt en cours. Veuillez patienter..." -#: templates/chimere/edit_route.html:22 -msgid "" -"You are logged as an administrator. Your modifications will be taking into " -"account immediately." -msgstr "" -"Vous êtes connecté comme administrateur. Vos modifications vont être prises " -"en compte immédiatement." +#: templates/chimere/edit.html:159 templates/chimere/edit_route.html:78 +msgid "Propose" +msgstr "Proposez" -#: templates/chimere/edit_route.html:24 +#: templates/chimere/edit_route.html:22 msgid "Modify a route" msgstr "Modifier un trajet" -#: templates/chimere/edit_route.html:24 +#: templates/chimere/edit_route.html:22 msgid "Add a route" msgstr "Ajout d'un nouveau trajet" -#: templates/chimere/main_map.html:22 templates/chimere/no_map.html:21 -msgid "Identified as: " -msgstr "Identifié en tant que : " - -#: templates/chimere/main_map.html:22 templates/chimere/no_map.html:21 -msgid "Logout" -msgstr "Se déconnecter" - -#: templates/chimere/main_map.html:48 +#: templates/chimere/main_map.html:38 msgid "Simple map" msgstr "Carte simple" -#: templates/chimere/no_map.html:31 -msgid "No map are currently available for your account." -msgstr "Aucune carte n'est disponible actuellement pour votre compte." - -#: templates/chimere/no_map.html:33 -msgid "" -"No map are currently available for public access. If you have an account " -"identify yourself." -msgstr "" -"Aucune carte n'est disponible actuellement en accès public. Si vous avez un " -"compte identifiez vous." - #: templates/chimere/upload_file.html:13 msgid "Thank you for your submission!" msgstr "Merci pour votre proposition !" @@ -1533,13 +1514,17 @@ msgstr "Vous devez renseigner un fichier ou une adresse web." msgid "You must provide a web address." msgstr "Vous devez fournir une adresse web." -#: templates/chimere/blocks/areas.html:5 templates/chimere/blocks/maps.html:5 -msgid "Maps:" -msgstr "Cartes :" +#: templates/chimere/blocks/areas.html:4 +msgid "Maps" +msgstr "Cartes" + +#: templates/chimere/blocks/areas_alternative.html:4 +msgid "Shortcuts" +msgstr "Raccourcis" +#: templates/chimere/blocks/areas_alternative.html:7 #: templates/chimere/blocks/categories.html:8 #: templates/chimere/blocks/categories.html:17 -#: templates/chimere/blocks/maps_alternative.html:7 msgid "Zoom to" msgstr "Zoomer sur" @@ -1556,19 +1541,23 @@ msgstr "" msgid "This site uses Chimère" msgstr "Ce site utilise Chimère" -#: templates/chimere/blocks/map.html:9 +#: templates/chimere/blocks/footer.html:2 +msgid "Map" +msgstr "Carte" + +#: templates/chimere/blocks/map.html:15 msgid "Loading of the map in progress" msgstr "Chargement de la carte en cours" -#: templates/chimere/blocks/map.html:13 +#: templates/chimere/blocks/map.html:19 msgid "Display options" msgstr "Options d'affichage" -#: templates/chimere/blocks/map.html:15 +#: templates/chimere/blocks/map.html:21 msgid "Map type" msgstr "Type de carte" -#: templates/chimere/blocks/map.html:25 +#: templates/chimere/blocks/map.html:32 msgid "Permalink" msgstr "Lien permanent" @@ -1604,10 +1593,6 @@ msgstr "Zoomer en arrière" msgid "Center the map here" msgstr "Centrer la carte ici" -#: templates/chimere/blocks/maps_alternative.html:4 -msgid "Shortcuts" -msgstr "Raccourcis" - #: templates/chimere/blocks/multimedia_file.html:19 msgid "Please use a modern browser or install the non free Flash-Plugin." msgstr "" @@ -1619,14 +1604,6 @@ msgstr "" msgid "See it on the map" msgstr "Voir sur la carte" -#: templates/chimere/blocks/nominatim_widget.html:5 -msgid "Search:" -msgstr "Rechercher :" - -#: templates/chimere/blocks/nominatim_widget.html:10 -msgid "Street, City, Country" -msgstr "Rue, Commune, Pays" - #: templates/chimere/blocks/routing.html:5 msgid "Itinerary" msgstr "Itinéraire" @@ -1635,7 +1612,7 @@ msgstr "Itinéraire" msgid "Add a step" msgstr "Ajouter une étape" -#: templates/chimere/blocks/routing.html:17 +#: templates/chimere/blocks/routing.html:17 templates/search/search.html:33 msgid "Search" msgstr "Rechercher" @@ -1667,43 +1644,27 @@ msgstr "Partager sur" msgid "Share" msgstr "Partager" -#: templates/chimere/blocks/submited.html:6 -msgid "Your modification has been taken into account." -msgstr "Votre modification a été prise en compte." - -#: templates/chimere/blocks/submited.html:8 -msgid "" -"Your modification has been submited. A moderator will treat your submission " -"shortly. Thanks!" -msgstr "" -"Votre proposition a été soumise. Un modérateur va traiter votre " -"proposition sous peu. Merci !" - -#: templates/chimere/blocks/submited.html:12 -msgid "Your new proposition has been added." -msgstr "Votre nouvelle proposition a été ajoutée." - -#: templates/chimere/blocks/submited.html:14 +#: templates/chimere/blocks/submited.html:3 msgid "" -"Your new proposition has been submited. A moderator will treat your " -"submission shortly. Thanks!" +"Your new proposition/modification has been submited. A moderator will treat " +"your submission shortly. Thanks!" msgstr "" -"Votre proposition a été soumise. Un modérateur va traiter votre " +"Votre proposition/modification a été soumise. Un modérateur va traiter votre " "proposition sous peu. Merci !" -#: templates/chimere/blocks/submited.html:21 +#: templates/chimere/blocks/submited.html:8 msgid "Thank you" msgstr "Merci" -#: templates/chimere/blocks/submited.html:25 +#: templates/chimere/blocks/submited.html:12 msgid "Add a new item" msgstr "Ajout d'un nouvel élément" -#: templates/chimere/blocks/submited.html:29 +#: templates/chimere/blocks/submited.html:16 msgid "Continue edition of this item" msgstr "Continuer l'édition de cet élément" -#: templates/chimere/blocks/submited.html:33 +#: templates/chimere/blocks/submited.html:20 msgid "Return to the map" msgstr "Retourner à la carte" @@ -1736,8 +1697,8 @@ msgid "Choose a category" msgstr "Choisir une catégorie" #: templates/chimere/feeds/rss.html:51 -msgid "Choose a pre-defined map" -msgstr "Choisir une carte pré-définie" +msgid "Choose a pre-defined areas" +msgstr "Choisir une zone pré-définie" #: templates/chimere/feeds/rss.html:65 msgid "Or select the area by zooming and panning this map" @@ -1751,17 +1712,35 @@ msgstr "Description :" msgid ":" msgstr " :" -#: templatetags/chimere_tags.py:72 +#: templates/search/search.html:3 +msgid "Do you mean: " +msgstr "Voulez-vous dire :" + +#: templates/search/search.html:4 +msgid "?" +msgstr " ?" + +#: templates/search/search.html:15 +msgid "No results found." +msgstr "Pas de résultats trouvés." + +#: templates/search/search.html:23 +msgid "Previous" +msgstr "Précédent" + +#: templates/search/search.html:24 +msgid "More results..." +msgstr "Plus de résultats..." + +#: templates/search/search.html:38 +msgid "No exact match." +msgstr "Pas de correspondance exacte." + +#: templatetags/chimere_tags.py:93 #, python-format msgid "Welcome to the %s" msgstr "Bienvenue sur %s" -#~ msgid "Invalid CSV format" -#~ msgstr "Fichier CSV non valide" - -#~ msgid "Associated areas" -#~ msgstr "Zones associées" - #~ msgid "Areas:" #~ msgstr "Zones :" @@ -1777,6 +1756,9 @@ msgstr "Bienvenue sur %s" #~ msgid "Administration de Chimère" #~ msgstr "Administration de Chimère" +#~ msgid "Add/modify a site" +#~ msgstr "Ajouter ou modifier un site" + #~ msgid "Categorys" #~ msgstr "Catégories" diff --git a/chimere/migrations/0010_auto__add_field_subcategory_keywords.py b/chimere/migrations/0010_auto__add_field_subcategory_keywords.py new file mode 100644 index 0000000..3a05ac7 --- /dev/null +++ b/chimere/migrations/0010_auto__add_field_subcategory_keywords.py @@ -0,0 +1,291 @@ +# -*- 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 'SubCategory.keywords' + db.add_column('chimere_subcategory', 'keywords', + self.gf('django.db.models.fields.TextField')(max_length=200, null=True, blank=True), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'SubCategory.keywords' + db.delete_column('chimere_subcategory', 'keywords') + + + models = { + 'chimere.aggregatedroute': { + 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}) + }, + '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', [], {'unique': 'True'}), + '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'}, + 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}), + 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}), + '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'}), + 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + 'source_file_alt': ('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.TextField', [], {'null': 'True', 'blank': 'True'}), + 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'chimere.importerkeycategories': { + 'Meta': {'object_name': 'ImporterKeyCategories'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}), + 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + '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'}), + 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', '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': 'True'}), + '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.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'}), + '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']", 'null': 'True', 'blank': 'True'}), + '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', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}), + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'date': ('django.db.models.fields.DateField', [], {}), + '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': { + '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.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'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': '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'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', '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': 'True'}), + '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'}, + 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + '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'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}), + 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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/0011_auto__add_field_importer_default_status.py b/chimere/migrations/0011_auto__add_field_importer_default_status.py new file mode 100644 index 0000000..bb36e42 --- /dev/null +++ b/chimere/migrations/0011_auto__add_field_importer_default_status.py @@ -0,0 +1,292 @@ +# -*- 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.default_status' + db.add_column('chimere_importer', 'default_status', + self.gf('django.db.models.fields.CharField')(default='I', max_length=1), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Importer.default_status' + db.delete_column('chimere_importer', 'default_status') + + + models = { + 'chimere.aggregatedroute': { + 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}) + }, + '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', [], {'unique': 'True'}), + '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'}, + 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}), + 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}), + 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}), + 'filtr': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + 'source_file_alt': ('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.TextField', [], {'null': 'True', 'blank': 'True'}), + 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'chimere.importerkeycategories': { + 'Meta': {'object_name': 'ImporterKeyCategories'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}), + 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + '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'}), + 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', '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': 'True'}), + '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.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'}), + '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']", 'null': 'True', 'blank': 'True'}), + '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', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}), + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'date': ('django.db.models.fields.DateField', [], {}), + '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': { + '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.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'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': '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'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', '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': 'True'}), + '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'}, + 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + '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'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}), + 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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/0012_auto__chg_field_importer_filtr.py b/chimere/migrations/0012_auto__chg_field_importer_filtr.py new file mode 100644 index 0000000..84e4c72 --- /dev/null +++ b/chimere/migrations/0012_auto__chg_field_importer_filtr.py @@ -0,0 +1,290 @@ +# -*- 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): + + # Changing field 'Importer.filtr' + db.alter_column('chimere_importer', 'filtr', self.gf('django.db.models.fields.TextField')(null=True)) + + def backwards(self, orm): + + # Changing field 'Importer.filtr' + db.alter_column('chimere_importer', 'filtr', self.gf('django.db.models.fields.CharField')(max_length=200, null=True)) + + models = { + 'chimere.aggregatedroute': { + 'Meta': {'object_name': 'AggregatedRoute', 'db_table': "'chimere_aggregated_routes'", 'managed': 'False'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'route': ('django.contrib.gis.db.models.fields.MultiLineStringField', [], {}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'subcategory': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}) + }, + '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', [], {'unique': 'True'}), + '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'}, + 'associate_marker_to_way': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'automatic_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'to': "orm['chimere.SubCategory']", 'null': 'True', 'blank': 'True'}), + 'default_description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'default_localisation': ('chimere.widgets.PointField', [], {'null': 'True', 'blank': 'True'}), + 'default_name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'default_status': ('django.db.models.fields.CharField', [], {'default': "'I'", 'max_length': '1'}), + 'filtr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'get_description': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + 'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + 'source_file_alt': ('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.TextField', [], {'null': 'True', 'blank': 'True'}), + 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'chimere.importerkeycategories': { + 'Meta': {'object_name': 'ImporterKeyCategories'}, + 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.SubCategory']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'importer': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'key_categories'", 'to': "orm['chimere.Importer']"}), + 'key': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + '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'}), + 'is_front_page': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', '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': 'True'}), + '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.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'}), + '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']", 'null': 'True', 'blank': 'True'}), + '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', [], {'symmetrical': 'False', 'to': "orm['chimere.Area']", 'null': 'True', 'blank': 'True'}), + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'content': ('django.db.models.fields.TextField', [], {}), + 'date': ('django.db.models.fields.DateField', [], {}), + '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': { + '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.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'}), + 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'has_associated_marker': ('django.db.models.fields.BooleanField', [], {'default': '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'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', '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': 'True'}), + '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'}, + 'as_layer': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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'}), + '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'}), + 'keywords': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '1000'}), + 'routing_warn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + '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/models.py b/chimere/models.py index 15d264b..9a91a74 100644 --- a/chimere/models.py +++ b/chimere/models.py @@ -46,7 +46,8 @@ from chimere.widgets import HiddenPointChooserWidget, PointField, RouteField, \ DatePickerWidget from chimere.managers import BaseGeoManager from chimere.utils import KMLManager, OSMManager, ShapefileManager, \ - GeoRSSManager, CSVManager, HtmlXsltManager, XMLXsltManager + GeoRSSManager, CSVManager, HtmlXsltManager, XMLXsltManager, JsonManager + class Page(models.Model): """Simple extra pages @@ -106,7 +107,7 @@ class News(models.Model): date = models.DateField(_(u"Date")) content = models.TextField() url = models.URLField(_(u"Url"), max_length=200, blank=True, null=True) - maps = SelectMultipleField('Map', verbose_name=_(u"Associated maps"), + areas = SelectMultipleField('Area', verbose_name=_(u"Associated areas"), blank=True, null=True) def __unicode__(self): ordering = ["-date"] @@ -172,8 +173,7 @@ class Color(models.Model): """ code = models.CharField(_(u"Code"), max_length=6) order = models.IntegerField(_(u"Order")) - color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme"), - related_name='colors') + color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme")) def __unicode__(self): return self.code class Meta: @@ -184,7 +184,6 @@ class Category(models.Model): """Category of Point Of Interest (POI) """ name = models.CharField(_(u"Name"), max_length=150) - slug = models.SlugField() available = models.BooleanField(_(u"Available")) order = models.IntegerField(_(u"Order")) description = models.TextField(blank=True, null=True) @@ -213,12 +212,9 @@ class SubCategory(models.Model): category = models.ForeignKey(Category, verbose_name=_(u"Category"), related_name='subcategories') name = models.CharField(_(u"Name"), max_length=150) - slug = models.SlugField() available = models.BooleanField(_(u"Available"), default=True) submission = models.BooleanField(_(u"Available for submission"), default=True) - weighted = models.BooleanField(_(u"Has an associated quantity"), - default=False) TYPE = (('M', _(u'Marker')), ('R', _(u'Route')), ('B', _(u'Both')),) @@ -234,6 +230,8 @@ class SubCategory(models.Model): default=False) routing_warn = models.BooleanField(_(u"Routing warn"), default=False) order = models.IntegerField(_(u"Order"), default=1000) + keywords = models.TextField(_(u"Keywords"), max_length=200, + blank=True, null=True) def __unicode__(self): return u"%s / %s" % (self.category.name, self.name) class Meta: @@ -242,7 +240,7 @@ class SubCategory(models.Model): verbose_name_plural = _(u"Sub-categories") @classmethod - def getAvailable(cls, item_types=None, map_name=None, public=False): + def getAvailable(cls, item_types=None, area_name=None, public=False): '''Get list of tuples with first the category and second the associated subcategories ''' @@ -255,14 +253,14 @@ class SubCategory(models.Model): if public: subcategories = subcategories.filter(submission=True) selected_cats = [] - if map_name: - map = Map.objects.get(urn=map_name) + if area_name: + area = Area.objects.get(urn=area_name) # if there some restrictions with categories limit them - if map.subcategories.count(): - sub_ids = [sub.id for sub in map.subcategories.all()] + if area.subcategories.count(): + sub_ids = [sub.id for sub in area.subcategories.all()] subcategories = subcategories.filter(id__in=sub_ids) selected_cats = [subcat.pk - for subcat in map.default_subcategories.all()] + for subcat in area.default_subcategories.all()] for sub_category in subcategories.order_by('order'): if sub_category.category not in sub_categories: sub_categories[sub_category.category] = [] @@ -278,10 +276,10 @@ class SubCategory(models.Model): return subcategories @classmethod - def getAvailableTuples(cls, item_types=None, map_name=None): + def getAvailableTuples(cls, item_types=None, area_name=None): cats = [] for cat, subcats in cls.getAvailable(item_types=item_types, - map_name=map_name): + area_name=area_name): cats.append((unicode(cat), [(subcat.pk, subcat.name) for subcat in subcats])) return cats @@ -304,13 +302,29 @@ class SubCategory(models.Model): json_string = json.dumps(self.getJSONDict()) return json_string -IMPORTERS = {'KML':KMLManager, - 'OSM':OSMManager, - 'SHP':ShapefileManager, - 'RSS':GeoRSSManager, - 'CSV':CSVManager, - 'XSLT':HtmlXsltManager, - 'XXLT':XMLXsltManager + @property + def slug(self): + return defaultfilters.slugify(self.name) + + @property + def item_nb(self): + return Marker.objects.filter(categories=self).count() + +STATUS = (('S', _(u'Submited')), + ('A', _(u'Available')), + ('M', _(u'Modified')), + ('D', _(u'Disabled')), + ('I', _(u'Imported'))) +STATUS_DCT = dict(STATUS) + +IMPORTERS = {'KML': KMLManager, + 'OSM': OSMManager, + 'SHP': ShapefileManager, + 'RSS': GeoRSSManager, + 'CSV': CSVManager, + 'JSON': JsonManager, + 'XSLT': HtmlXsltManager, + 'XXLT': XMLXsltManager } IMPORTER_CHOICES = (('KML', 'KML'), @@ -318,20 +332,21 @@ IMPORTER_CHOICES = (('KML', 'KML'), ('SHP', 'Shapefile'), ('RSS', 'GeoRSS'), ('CSV', 'CSV'), + ('JSON', 'JSON'), ('XSLT', 'HTML-XSLT'), ('XXLT', 'XML-XSLT'), ) IMPORTER_CHOICES_DICT = dict(IMPORTER_CHOICES) + class Importer(models.Model): ''' Data importer for a specific subcategory ''' importer_type = models.CharField(_(u"Importer type"), max_length=4, choices=IMPORTER_CHOICES) - filtr = models.CharField(_(u"Filter"), max_length=200, - blank=True, null=True) + filtr = models.TextField(_(u"Filter"), blank=True, null=True) source = models.CharField(_(u"Web address"), max_length=200, blank=True, null=True, help_text=_(u"Don't forget the trailing slash")) @@ -360,6 +375,8 @@ class Importer(models.Model): u"a marker to a way"), default=False) automatic_update = models.BooleanField(_(u"Automatically updated"), default=False) + default_status = models.CharField(_(u"Default status"), max_length=1, + choices=STATUS, default='I') default_localisation = PointField(_(u"Default localisation"), srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION, blank=True, null=True, @@ -396,6 +413,7 @@ class Importer(models.Model): dct[key_cat.key] = key_cat.category return dct + class ImporterKeyCategories(models.Model): """ Association between key and categories @@ -408,13 +426,6 @@ class ImporterKeyCategories(models.Model): class Meta: verbose_name = _(u"Importer - Key categories") -STATUS = (('S', _(u'Submited')), - ('A', _(u'Available')), - ('M', _(u'Modified')), - ('D', _(u'Disabled')), - ('I', _(u'Imported'))) -STATUS_DCT = dict(STATUS) - class GeographicItem(models.Model): name = models.CharField(_(u"Name"), max_length=150) categories = SelectMultipleField(SubCategory) @@ -473,7 +484,12 @@ class GeographicItem(models.Model): if not _set: new_keys += '%s:%s;' % (key, value) self.import_key = new_keys + modified_since_import = self.modified_since_import self.save() + # preserve modified_since_import + if modified_since_import != self.modified_since_import: + self.modified_since_import = modified_since_import + self.save() def has_modified(self): if (self.ref_item and self.ref_item != self) \ @@ -511,8 +527,6 @@ class Marker(GeographicItem): null=True) # used by feeds route = models.ForeignKey(u"Route", blank=True, null=True, related_name='associated_marker') - weight = models.IntegerField(_(u"Quantity"), blank=True, null=True, - default=0) description = models.TextField(_(u"Description"), blank=True, null=True) is_front_page = models.NullBooleanField(_(u"Is front page"), blank=True, null=True) @@ -582,10 +596,6 @@ class Marker(GeographicItem): def geom_attr(self): return 'point' - @property - def has_weight(self): - return bool(self.categories.filter(weighted=True).count()) - class Meta: ordering = ('status', 'name') verbose_name = _(u"Point of interest") @@ -667,32 +677,6 @@ class Marker(GeographicItem): val = values[unicode(propertymodel.id)] self.setProperty(propertymodel, val) - PROPERTIES_KEYS = ['point', 'pk', 'name', 'weight'] - @classmethod - def _getJson(cls, values, base_dct={"properties":{}}): - item = base_dct.copy() - item["geometry"] = {"type": "Point", - "coordinates": [values['point'].x, - values['point'].y]} - item["properties"]['pk'] = values['pk'] - item["properties"]['name'] = values['name'] - if values['weight']: - item["properties"]['weight'] = values['weight'] - return item - - def _getItems(self, base_dct={"properties":{}}): - '''Return a dict representation for json - ''' - item = base_dct.copy() - item["geometry"] = {"type": "Point", - "coordinates": [ self.point.x, self.point.y ] - } - item["properties"]['pk'] = self.pk - item["properties"]['name'] = self.name - if self.weight: - item["properties"]['weight'] = self.weight - return item - def getGeoJSON(self, categories_id=[]): '''Return a GeoJSON string ''' @@ -707,31 +691,14 @@ class Marker(GeographicItem): 'pk':self.id, 'name':self.name, 'icon_path':unicode(cat.icon.image), - 'icon_hover_path':cat.hover_icon.image \ + 'icon_hover_path':unicode(cat.hover_icon.image) \ if cat.hover_icon else '', 'category_name':cat.name}) - items['weight'] = '' - if cat.weighted: - if not self.weight: - continue - items['weight'] = self.weight - if cat.color_theme and cat.color_theme.colors.count(): - items['colors'] += ["#%s"] % '", "#'.join( - [color.code for color in cat.color_theme.colors.\ - order_by('order').all()]) try: items['properties'].update({'icon_width':cat.icon.image.width, 'icon_height':cat.icon.image.height,}) except IOError: pass - if cat.weighted: - if not self.weight: - continue - items['weight'] = u', "weight":%d' % self.weight - if cat.color_theme and cat.color_theme.colors.count(): - items['weight'] += u', "colors":["#%s"]' % '", "#'.join( - [color.code for color in cat.color_theme.colors.\ - order_by('order').all()]) jsons.append(items) @@ -745,20 +712,20 @@ class Marker(GeographicItem): if cats.count(): return cats.all()[0] - def get_absolute_url(self, map_name=''): + def get_absolute_url(self, area_name=''): parameters = 'current_feature=%d' % self.id if self.default_category: parameters += '&checked_categories=%s' % self.default_category.pk urn = TinyUrl.getUrnByParameters(parameters) - map_name = map_name + '/' if map_name else '' - url = reverse('chimere:tiny', args=[map_name, urn]) + area_name = area_name + '/' if area_name else '' + url = reverse('chimere:tiny', args=[area_name, urn]) return url - PRE_ATTRS = { - 'Marker':('name', 'geometry', 'import_version', 'modified_since_import'), + 'Marker':('name', 'description', 'start_date', 'geometry', 'import_version', + 'modified_since_import'), 'Route':('name', 'geometry', 'import_version', 'modified_since_import'), - 'Map':('urn', 'name'), + 'Area':('urn', 'name'), } def geometry_pre_save(cls, pre_save_geom_values): def geom_pre_save(sender, **kwargs): @@ -767,8 +734,9 @@ 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] = [getattr(instance, attr) - for attr in PRE_ATTRS[cls.__name__]] + pre_save_geom_values[instance.pk] = dict( + [(attr, getattr(instance, attr)) + for attr in PRE_ATTRS[cls.__name__]]) except ObjectDoesNotExist: pass return geom_pre_save @@ -786,24 +754,25 @@ def geometry_post_save(pre_save_geom_values): or kwargs['instance'].pk not in pre_save_geom_values: return instance = kwargs['instance'] - name, geometry, import_version, modified_since_import = \ - pre_save_geom_values[instance.pk] + pre = pre_save_geom_values[instance.pk] # force the reinit of modified_since_import - if modified_since_import != instance.modified_since_import: + if pre['modified_since_import'] != instance.modified_since_import: return - if (instance.import_version != import_version + if (instance.import_version != pre['import_version'] and instance.modified_since_import): instance.modified_since_import = False instance.save() return if instance.modified_since_import: return - if instance.name != name or instance.geometry != geometry: + if [key for key in pre if pre not in ('import_version', + 'modified_since_import') and + getattr(instance, key) != pre[key]]: instance.modified_since_import = True instance.save() return geom_post_save def marker_post_save(sender, **kwargs): - if not kwargs['instance']: + if not kwargs['instance'] or kwargs['created']: return geometry_post_save(pre_save_marker_values)(sender, **kwargs) post_save.connect(marker_post_save, sender=Marker) @@ -1196,13 +1165,6 @@ class Route(GeographicItem): properties.append(property) return properties - def _getItems(self, dct={'properties':{}}): - dct['geometry'] = { "type": "LineString", - "coordinates": [[point.x, point.y] - for point in self.route]} - dct['properties'].update({'id':self.id, 'name':self.name}) - return dct - def getGeoJSON(self, color="#000"): '''Return a GeoJSON string ''' @@ -1343,14 +1305,14 @@ class SimpleArea: return True return False - def getCategories(self, status='A', filter_available=True, map_name=None): + def getCategories(self, status='A', filter_available=True, area_name=None): """ - Get categories for this map + Get categories for this area """ wheres = [] - if map_name: + if area_name: subcategory_pks = [] - for cat, subcats in SubCategory.getAvailable(map_name=map_name): + for cat, subcats in SubCategory.getAvailable(area_name=area_name): for subcat in subcats: subcategory_pks.append(unicode(subcat.pk)) if filter_available: @@ -1414,43 +1376,37 @@ class Layer(models.Model): class Meta: verbose_name = _("Layer") -class Map(models.Model, SimpleArea): - """A map +class Area(models.Model, SimpleArea): + """Rectangular area of the map """ name = models.CharField(_(u"Name"), max_length=150) - available = models.BooleanField(_(u"Available")) - users = models.ManyToManyField(User, through='MapUsers') - urn = models.SlugField(_(u"Map urn"), max_length=50, blank=True, + urn = models.SlugField(_(u"Area urn"), max_length=50, blank=True, unique=True) welcome_message = models.TextField(_(u"Welcome message"), blank=True, null=True) order = models.IntegerField(_(u"Order"), unique=True) + available = models.BooleanField(_(u"Available")) upper_left_corner = models.PointField(_(u"Upper left corner"), default='POINT(0 0)', srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION) lower_right_corner = models.PointField(_(u"Lower right corner"), default='POINT(0 0)', srid=settings.CHIMERE_EPSG_DISPLAY_PROJECTION) - default = models.BooleanField(_(u"Default map"), default=False, - help_text=_(u"Only one map is set by default")) - layers = SelectMultipleField(Layer, related_name='maps', - through='MapLayers', blank=True) + default = models.NullBooleanField(_(u"Default area"), + help_text=_(u"Only one area is set by default")) + layers = SelectMultipleField(Layer, related_name='areas', + through='AreaLayers', blank=True) default_subcategories = SelectMultipleField(SubCategory, blank=True, verbose_name=_(u"Sub-categories checked by default")) dynamic_categories = models.NullBooleanField( _(u"Sub-categories dynamicaly displayed"), help_text=_(u"If checked, categories are only displayed in the menu if " u"they are available on the current extent.")) - subcategories = SelectMultipleField(SubCategory, related_name='maps', - blank=True, db_table='chimere_subcategory_maps', + subcategories = SelectMultipleField(SubCategory, related_name='areas', + blank=True, db_table='chimere_subcategory_areas', verbose_name=_(u"Restricted to theses sub-categories"), help_text=_(u"If no sub-category is set all sub-categories are " u"available")) external_css = models.URLField(_(u"Link to an external CSS"), blank=True, null=True) - cluster = models.BooleanField(u"Clustering map (weight of items are added)", - default=False) - public_read = models.BooleanField(_(u"Public can read the map")) - public_propose = models.BooleanField(_(u"Public can propose item to the map")) - public_write = models.BooleanField(_(u"Public can write without moderation to the map")) restrict_to_extent = models.BooleanField(_(u"Restrict to the area extent"), default=False) objects = models.GeoManager() @@ -1460,72 +1416,13 @@ class Map(models.Model, SimpleArea): class Meta: ordering = ('order', 'name') - verbose_name = _("Map") - - def can_write(self, user=None): - return bool(self.getAvailable(user=user, urn=self.urn, single=True, - edit=True)) - - def can_propose(self, user=None): - return bool(self.getAvailable(user=user, urn=self.urn, single=True, - propose=True)) + verbose_name = _("Area") @classmethod - def getAvailable(cls, user=None, urn=None, single=False, edit=False, - propose=False): - '''Get available maps + def getAvailable(cls): + '''Get available areas ''' - map_filter = {'available':True} - if urn: - map_filter['urn'] = urn - elif single: - map_filter['default'] = True - filters = [] - if not propose and not edit: - filters = [{'public_write':True}, - {'public_propose':True}, - {'public_read':True}] - elif propose: - filters = [{'public_write':True}, - {'public_propose':True}] - elif edit: - filters = [{'public_write':True}] - if user and user.is_authenticated(): - if not propose and not edit: - filters += [ - {'mapusers__user':user, 'mapusers__read':True}, - {'mapusers__user':user, 'mapusers__write':True}, - {'mapusers__user':user, 'mapusers__propose':True}, - {'mapgroups__group__user':user, 'mapgroups__read':True}, - {'mapgroups__group__user':user, 'mapgroups__write':True}, - {'mapgroups__group__user':user, 'mapgroups__propose':True} - ] - elif propose: - filters += [ - {'mapusers__user':user, 'mapusers__write':True}, - {'mapusers__user':user, 'mapusers__propose':True}, - {'mapgroups__group__user':user, 'mapgroups__write':True}, - {'mapgroups__group__user':user, 'mapgroups__propose':True} - ] - elif edit: - filters += [ - {'mapusers__user':user, 'mapusers__write':True}, - {'mapgroups__group__user':user, 'mapgroups__write':True}, - ] - query = None - for fltr in filters: - fltr.update(map_filter) - if not query: - query = Q(**fltr) - else: - query = query | Q(**fltr) - maps = cls.objects.filter(query).distinct() - if single: - if not maps.count(): - return - return maps.all()[0] - else: - return maps.all() + return cls.objects.filter(available=True) def getWkt(self): return "SRID=%d;POLYGON((%f %f,%f %f,%f %f,%f %f, %f %f))" % ( @@ -1549,66 +1446,54 @@ class Map(models.Model, SimpleArea): """ return Q(route__contained=self.getWkt()) -pre_save_map_values = {} -def map_pre_save(sender, **kwargs): +pre_save_area_values = {} +def area_pre_save(sender, **kwargs): if not kwargs['instance']: return - geometry_pre_save(Map, pre_save_map_values)(sender, **kwargs) -pre_save.connect(map_pre_save, sender=Map) + geometry_pre_save(Area, pre_save_area_values)(sender, **kwargs) +pre_save.connect(area_pre_save, sender=Area) -def map_post_save(sender, **kwargs): +def area_post_save(sender, **kwargs): if not kwargs['instance']: return - map = kwargs['instance'] - if map.default: - defaults = Map.objects.filter(default=True).exclude(pk=map.pk) + area = kwargs['instance'] + if area.default: + defaults = Area.objects.filter(default=True).exclude(pk=area.pk) for default in defaults: default.default = False default.save() # manage permissions - old_urn, old_name = map.urn, map.name - if map.pk in pre_save_map_values: - old_urn, old_name = pre_save_map_values[map.pk] + 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 map.urn != old_urn: - oldmnemo = 'change_map_' + old_urn + 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] - codename = 'change_map_' + map.urn - if not Permission.objects.filter(codename=codename).count(): - perm.codename = codename - perm.save() - if not map.urn: - map.urn = defaultfilters.slugify(map.name) - map.save() - - # fix old mnemo - oldmnemo = 'change_area_' + old_urn - old_perm = Permission.objects.filter(codename=oldmnemo) - if old_perm.count(): - perm = old_perm.all()[0] - perm.codename = 'change_map_' + map.urn - perm.save() - - mnemo = 'change_map_' + map.urn + 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 " + map.name + lbl = "Can change " + area.name if not perm.count(): content_type, created = ContentType.objects.get_or_create( - app_label="chimere", model="map") + 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 != map.name: + if old_name != area.name: perm.name = lbl perm.save() # manage moderation group - groupname = map.name + " moderation" - if old_name != map.name: + 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(): @@ -1629,56 +1514,36 @@ def map_post_save(sender, **kwargs): for p in Permission.objects.filter(content_type=ct).all(): group.permissions.add(p) -post_save.connect(map_post_save, sender=Map) +post_save.connect(area_post_save, sender=Area) -def get_maps_for_user(user): +def get_areas_for_user(user): """ - Getting maps for a specific user + Getting subcats for a specific user """ perms = user.get_all_permissions() - maps = set() - prefix = 'chimere.change_map_' + areas = set() + prefix = 'chimere.change_area_' for perm in perms: if perm.startswith(prefix): try: - map = Map.objects.get(urn=perm[len(prefix):]) - maps.add(map) + area = Area.objects.get(urn=perm[len(prefix):]) + areas.add(area) except ObjectDoesNotExist: pass - return maps + return areas -def get_users_by_map(map): - if not map: +def get_users_by_area(area): + if not area: return [] - perm = 'change_map_'+map.urn + perm = 'change_area_'+area.urn return User.objects.filter(Q(groups__permissions__codename=perm)| Q(user_permissions__codename=perm)).all() -class MapUsers(models.Model): - map = models.ForeignKey(Map, related_name='mapusers') - user = models.ForeignKey(User, related_name='mapusers') - read = models.BooleanField(_(u"Can read the map")) - propose = models.BooleanField(_(u"Can propose item to the map")) - write = models.BooleanField(_(u"Can write without moderation to the map")) - class Meta: - verbose_name = _("Map - user") - verbose_name_plural = _("Map - users") - -class MapGroups(models.Model): - map = models.ForeignKey(Map, related_name='mapgroups') - group = models.ForeignKey(Group, related_name='mapgroups') - read = models.BooleanField(_(u"Can read the map")) - propose = models.BooleanField(_(u"Can propose item to the map")) - write = models.BooleanField(_(u"Can write without moderation to the map")) - class Meta: - verbose_name = _("Map - group") - verbose_name_plural = _("Map - groups") - -class MapLayers(models.Model): - map = models.ForeignKey(Map) +class AreaLayers(models.Model): + area = models.ForeignKey(Area) layer = models.ForeignKey(Layer) order = models.IntegerField(_(u"Order")) - default = models.BooleanField(_(u"Default layer"), default=False) + default = models.NullBooleanField(_(u"Default layer")) class Meta: ordering = ('order',) @@ -1692,7 +1557,6 @@ class PropertyModel(models.Model): order = models.IntegerField(_(u"Order")) available = models.BooleanField(_(u"Available")) mandatory = models.BooleanField(_(u"Mandatory")) - slug = models.SlugField() subcategories = SelectMultipleField(SubCategory, related_name='properties', blank=True, verbose_name=_(u"Restricted to theses sub-categories"), help_text=_(u"If no sub-category is set all the property applies to all " @@ -1701,7 +1565,6 @@ class PropertyModel(models.Model): ('L', _('Long text')), ('P', _('Password')), ('D', _("Date")), - ('B', _("Boolean")), ('C', _("Choices")), ('B', _("Boolean")), ) @@ -1720,7 +1583,8 @@ class PropertyModel(models.Model): verbose_name = _("Property model") def getAttrName(self): - attr_name = self.slug.replace('-', '_') + attr_name = defaultfilters.slugify(self.name) + attr_name = re.sub(r'-','_', attr_name) return attr_name def getNamedId(self): @@ -1728,11 +1592,6 @@ class PropertyModel(models.Model): ''' return 'property_%d_%d' % (self.order, self.id) - def save(self, *args, **kwargs): - if not self.slug: - self.slug = defaultfilters.slugify(self.name) - super(PropertyModel, self).save(*args, **kwargs) - class PropertyModelChoice(models.Model): '''Choices for property model ''' @@ -1753,9 +1612,10 @@ class Property(models.Model): propertymodel = models.ForeignKey(PropertyModel, verbose_name=_(u"Property model")) value = models.TextField(_(u"Value")) - def __unicode__(self): - if self.value and self.propertymodel.type == 'C': + if self.propertymodel.type == 'C': + if not self.value: + return '' try: return unicode(PropertyModelChoice.objects.get( pk=self.value).value) @@ -1763,9 +1623,6 @@ class Property(models.Model): return "" return unicode(self.value) - def label(self): - return unicode(self) - class Meta: verbose_name = _(u"Property") @@ -1779,7 +1636,7 @@ class Property(models.Model): if self.propertymodel.type == 'C' and self.value: try: return PropertyModelChoice.objects.get(pk=self.value) - except self.DoesNotExist: + except (self.DoesNotExist, ValueError): return None else: return self.value diff --git a/chimere/settings.sample.py b/chimere/settings.sample.py index 1ddeca6..357ccef 100644 --- a/chimere/settings.sample.py +++ b/chimere/settings.sample.py @@ -57,6 +57,8 @@ CHIMERE_DAYS_BEFORE_EVENT = 30 CHIMERE_ALL_DATED_ARE_FRONT = False # allow feeds CHIMERE_FEEDS = True +# display a directory of items +CHIMERE_DIRECTORY = False CHIMERE_ICON_WIDTH = 21 CHIMERE_ICON_HEIGHT = 25 @@ -132,6 +134,8 @@ HAYSTACK_CONNECTIONS = { 'URL': 'http://127.0.0.1:8080/solr' }, } +HAYSTACK_SEARCH_RESULTS_PER_PAGE = 12 +HAYSTACK_AUTOCOMPLETE = False CHIMERE_CSV_ENCODING = 'ISO-8859-1' diff --git a/chimere/static/chimere/css/styles.css b/chimere/static/chimere/css/styles.css index dd27d95..52832b0 100644 --- a/chimere/static/chimere/css/styles.css +++ b/chimere/static/chimere/css/styles.css @@ -501,6 +501,11 @@ ul.share li{ margin:0; } +span.icon{ + display:inline-block; + width:70px; +} + #frm_categories{ padding:0; margin:0; @@ -837,6 +842,7 @@ table.inline-table td input[type=file]{ list-style-type:none; margin:0; padding:4px; + padding-bottom: 70px; } #search-listing ul li{ @@ -1138,11 +1144,25 @@ div.pp_default .pp_expand{ padding:0 6px; } +#category-directory ul{ + padding:0; +} + +.category-directory-category{ + font-variant: small-caps; + font-weight: bold; +} + .olControlSimplePanZoom { top: 20px; right: 10px; } +.olControlSimplePanZoom #zoombar, +.olControlSimplePanZoom #slider{ + display: none; +} + .olControlSimplePanZoom .button { background-image: url('../img/map_sprite.png'); position:absolute; @@ -1189,11 +1209,12 @@ div.pp_default .pp_expand{ } .olControlSimplePanZoom #zoomout { - top:210px; + top:70px; width:25px; height:20px; left:10px; background-position: -15px -220px; + border-top:1px solid #ccc; } .olControlSimplePanZoom #slider { diff --git a/chimere/static/chimere/js/importer_interface.js b/chimere/static/chimere/js/importer_interface.js index 65bcf8c..1b95fb0 100644 --- a/chimere/static/chimere/js/importer_interface.js +++ b/chimere/static/chimere/js/importer_interface.js @@ -2,35 +2,42 @@ django.jQuery(function($) { var importer_form_filter = { OSM:new Array('field-filtr', 'field-default_name', 'field-categories', 'field-source', 'field-overwrite', - 'field-automatic_update'), + 'field-automatic_update', 'field-default_status'), KML:new Array('field-source', 'field-source_file', 'field-default_name', 'field-filtr', 'field-zipped', 'field-origin', 'field-license', 'field-categories', 'field-overwrite', - 'field-get_description', 'field-automatic_update'), + 'field-get_description', 'field-automatic_update', + 'field-default_status'), SHP:new Array('field-source', 'field-source_file', 'field-default_name', 'field-zipped', 'field-origin', 'field-srid', 'field-license', 'field-categories', 'field-overwrite', - 'field-automatic_update'), + 'field-automatic_update', 'field-default_status'), RSS:new Array('field-source', 'field-default_name', 'field-origin', 'field-srid', 'field-license', 'field-categories', 'field-overwrite', 'field-get_description', - 'field-automatic_update'), + 'field-automatic_update', 'field-default_status'), CSV:new Array('field-source', 'field-source_file', 'field-default_name', 'field-origin', 'field-srid', 'field-license', 'field-categories', 'field-overwrite', - 'field-get_description', 'field-automatic_update'), + 'field-get_description', 'field-automatic_update', + 'field-default_status'), XSLT:new Array('field-source', 'field-source_file', 'field-source_file_alt', 'field-default_name', 'field-origin', 'field-srid', 'field-license', 'field-categories', 'field-overwrite', 'field-get_description', 'field-default_localisation', - 'field-automatic_update'), + 'field-automatic_update', 'field-default_status'), XXLT:new Array('field-source', 'field-source_file', 'field-source_file_alt', 'field-default_name', 'field-origin', 'field-srid', 'field-license', 'field-categories', 'field-overwrite', 'field-get_description', 'field-default_localisation', - 'field-automatic_update') + 'field-automatic_update', 'field-default_status'), + JSON:new Array('field-source', 'field-source_file', 'field-default_name', + 'field-filtr', 'field-zipped', 'field-origin', + 'field-license', 'field-categories', 'field-overwrite', + 'field-get_description', 'field-automatic_update', + 'field-default_status', 'field-default_localisation') } var osm_map_initialized; var edit_map_initialized; @@ -63,13 +70,17 @@ django.jQuery(function($) { osm_map_initialized = true; } } - else if (importer_val == 'XSLT' || importer_val == 'XXLT'){ + else if (importer_val == 'XSLT' || importer_val == 'XXLT' + || importer_val == 'JSON'){ $('#importerkeycategories_set-group').show(); $('#key_categories-group').show(); $('#importerkeycategories_set-group .form-row').show(); $('#key_categories-group .form-row').show(); $('.form-row.field-filtr').addClass('field-map'); $('#map_edit').show(); + $('#map_edit_area').hide(); + $('.help-osm').hide(); + $('.input-osm').hide(); if (!edit_map_initialized){ init_map_edit(); edit_map_initialized = true; @@ -118,10 +129,10 @@ django.jQuery(function($) { value = $('input[name=id_filtr_type]:checked').val(); value += '[' + $("#id_filtr_tag").val() + ']'; value += '[bbox='; - value += $('#upper_left_lon').val() + ','; - value += $('#lower_right_lat').val() + ','; - value += $('#lower_right_lon').val() + ','; - value += $('#upper_left_lat').val(); + value += Number($('#upper_left_lon').val()).toFixed(6) + ','; + value += Number($('#lower_right_lat').val()).toFixed(6) + ','; + value += Number($('#lower_right_lon').val()).toFixed(6) + ','; + value += Number($('#upper_left_lat').val()).toFixed(6); value += ']'; $('#id_filtr').val(value); return false; diff --git a/chimere/static/chimere/js/jquery.chimere-ol.js b/chimere/static/chimere/js/jquery.chimere-ol.js index 9346964..1599e1d 100644 --- a/chimere/static/chimere/js/jquery.chimere-ol.js +++ b/chimere/static/chimere/js/jquery.chimere-ol.js @@ -45,7 +45,6 @@ if (typeof(OpenLayers) != 'undefined'){ else return v; }; })( jQuery ); - (function ($) { /* * Chimere jQuery plugin @@ -84,6 +83,7 @@ if (typeof(OpenLayers) != 'undefined'){ // Provide this function for overriding the getSubcategories default get_subcategories_fx: null, hide_popup_fx: null, + open_dialog_fx: null, // if leave to false every click on the map hide the pop-up explicit_popup_hide: false, controls:null, @@ -594,6 +594,7 @@ if (typeof(OpenLayers) != 'undefined'){ content += "</ul></div>"; $('#cluster_list').html(content); $('#cluster_list').dialog('open'); + $("#cluster_list").on("dialogclose", methods.cleanCluster); settings.map.setCenter( feature.geometry.getBounds().getCenterLonLat()); // register after the display @@ -687,8 +688,16 @@ if (typeof(OpenLayers) != 'undefined'){ }); }, razMap: function() { + methods.hidePopup(); + methods.uncheckCategories(); settings.layerMarkers.clearMarkers(); settings.layerVectors.removeAllFeatures(); + if (settings.enable_clustering){ + settings.layerCluster.removeAllFeatures(); + settings.cluster_array = []; + settings.layerCluster.addFeatures(settings.cluster_array); + methods.cleanCluster(); + } }, /* * Update the categories div in ajax @@ -714,7 +723,7 @@ if (typeof(OpenLayers) != 'undefined'){ _init_categories(); _reCheckCategories(); if (settings.current_category) { - // TODO : add a force mode + // TODO : add a force mode // (in case the category is yet visible in HTML...) methods.toggle_category(); } @@ -774,7 +783,6 @@ if (typeof(OpenLayers) != 'undefined'){ } else { par.removeClass('selected'); } - methods.hidePopup(e); methods.loadGeoObjects(); _toggle_categories($(this)); settings.permalink.updateLink(); @@ -782,6 +790,7 @@ if (typeof(OpenLayers) != 'undefined'){ $('#layer_cat_'+c_name).prop("checked", this.checked); } + methods.hidePopup(e); }); $('#display_submited_check').bind("click", function () { methods.loadGeoObjects(); @@ -796,8 +805,8 @@ if (typeof(OpenLayers) != 'undefined'){ var id = this.id.substr(this.id.lastIndexOf("_")+1); helpers.zoom_to_subcategories([id]); }); - $(".toggle_category").bind("click", function (e) { - var item = $(this); + $(".toggle_category").parent().bind("click", function (e) { + var item = $(this).children('.toggle_category'); var id = item.attr('id').substr(item.attr('id').lastIndexOf("_")+1); methods.toggle_category(id); }); @@ -823,6 +832,18 @@ if (typeof(OpenLayers) != 'undefined'){ } }, /* + * + */ + uncheckCategories: function (){ + $('#frm_categories .subcategories input:checkbox').each(function(index){ + $(this).attr("checked", false); + $(this).removeAttr("checked", false); + }); + $('#frm_categories .selected').each(function(index){ + $(this).removeClass("selected"); + }); + }, + /* * Hide clusterized markers */ cleanCluster: function (){ @@ -1046,6 +1067,28 @@ if (typeof(OpenLayers) != 'undefined'){ cleanRoute: function(){ settings.layerVectors.removeAllFeatures(); }, + // add json layer + addJSON: function(json_url){ + var jsonStyle = new OpenLayers.Style({ + 'strokeWidth':1, + 'fillColor':'#BBBBBB', + 'strokeColor':'#AAAAAA' + }); + + var jsonStyleMap = new OpenLayers.StyleMap({'default': jsonStyle}); + settings.layerJson = new OpenLayers.Layer.Vector("GeoJSON", { + projection: EPSG_DISPLAY_PROJECTION, + strategies: [new OpenLayers.Strategy.Fixed()], + protocol: new OpenLayers.Protocol.HTTP({ + url: json_url, + format: new OpenLayers.Format.GeoJSON() + }), + styleMap: jsonStyleMap + }); + settings.map.addLayer(settings.layerJson); + settings.map.setLayerIndex(settings.layerJson, 0); + settings.layerJson.setOpacity(0.4); + }, // Put a route on the map addRoute: function(route) { var polyline = route.geometry; @@ -1441,16 +1484,23 @@ if (typeof(OpenLayers) != 'undefined'){ helpers.zoom_to_area(options["area"]); } }, + open_dialog: function(title, content){ + if(settings.open_dialog_fx){ + settings.open_dialog_fx(title, content); + } else { + $("#category_description").html(content).dialog(); + $("#category_description").dialog("option", "title", title); + $('#category_description').dialog('open'); + } + }, category_detail: function (category_id) { /* show the detail of a category */ var uri = extra_url + "getDescriptionDetail/" + category_id; $.ajax({url:uri, - success: function (data) { - $("#category_description").html(data).dialog(); - $("#category_description").dialog( "option", "title", - $("#category_title").html()); - } - }); + success: function (data) { + methods.open_dialog($("#category_title").html(), data); + } + }); }, /* * Load the subcategory description if available @@ -1462,10 +1512,7 @@ if (typeof(OpenLayers) != 'undefined'){ dataType: "json", success: function (data) { if (!data.description){return} - $('#category_description').html(data.description); - $("#category_description").dialog("option", "title", - data.name); - $('#category_description').dialog('open'); + methods.open_dialog(data.name, data.description); }, error: function (data) { // fail silently diff --git a/chimere/tasks.py b/chimere/tasks.py index 9c94f43..9eff7f5 100644 --- a/chimere/tasks.py +++ b/chimere/tasks.py @@ -60,19 +60,20 @@ else: return task_exc IMPORT_MESSAGES = { - 'import_pending':[_(u"Import pending")], - 'import_process':[_(u"Import processing")], - 'import_done':[_(u"Import successfuly done"), + 'import_pending': [_(u"Import pending")], + 'import_process': [_(u"Import processing")], + 'import_done': [_(u"Import successfuly done"), _(u" %(new)d new item(s), %(updated)d updated item(s)")], - 'import_failed':[_(u"Import failed"), "%s"], - 'import_cancel':[_(u"Import canceled")], - 'export_pending':[_(u"Export pending")], - 'export_process':[_(u"Export processing")], - 'export_done':[_(u"Export successfuly done"), + 'import_failed': [_(u"Import failed"), "%s"], + 'import_cancel': [_(u"Import canceled")], + 'export_pending': [_(u"Export pending")], + 'export_process': [_(u"Export processing")], + 'export_done': [_(u"Export successfuly done"), _(u" %(updated)d updated item(s)")], - 'export_failed':[_(u"Export failed"), "%s"], - 'export_cancel':[_(u"Export canceled")] - } + 'export_failed': [_(u"Export failed"), "%s"], + 'export_cancel': [_(u"Export canceled")] +} + @task() def importing(importer_pk): @@ -89,15 +90,16 @@ def importing(importer_pk): new_item, updated_item, error = importer.manager.get() importer.state = error + '\n' if error else '' importer.state += unicode(IMPORT_MESSAGES['import_done'][0]) - importer.state += u" - " \ - + unicode(IMPORT_MESSAGES['import_done'][1]) % {'new':new_item, - 'updated':updated_item} + importer.state += \ + u" - " + unicode(IMPORT_MESSAGES['import_done'][1]) % { + 'new': new_item, 'updated': updated_item} importer.state = importer.state importer.save() return True + @task() -@single_instance_task(60*10) +@single_instance_task(60 * 10) def exporting(importer_pk, extra_args=[]): try: importer = Importer.objects.get(pk=importer_pk) @@ -116,10 +118,11 @@ def exporting(importer_pk, extra_args=[]): pass if error: importer.state = unicode(IMPORT_MESSAGES['export_failed'][0]) \ - + u" - " + unicode(IMPORT_MESSAGES['export_failed'][1]) % error + + u" - " + unicode(IMPORT_MESSAGES['export_failed'][1]) % error importer.save() return importer.state = unicode(IMPORT_MESSAGES['export_done'][0]) + u" - " \ - + unicode(IMPORT_MESSAGES['export_done'][1]) % {'updated':updated_item} + + unicode(IMPORT_MESSAGES['export_done'][1]) % { + 'updated': updated_item} importer.save() return True diff --git a/chimere/templates/chimere/blocks/map_menu.html b/chimere/templates/chimere/blocks/map_menu.html index 38fb4a8..02f415a 100644 --- a/chimere/templates/chimere/blocks/map_menu.html +++ b/chimere/templates/chimere/blocks/map_menu.html @@ -1,7 +1,7 @@ {% load i18n %} <div id='chimere_map_menu'> <ul> - {% if routing %} + {% if routing and not simple %} <li id='map_menu_from' class='routing_item'>{% trans "From" context "routing" %}</li> <li id='map_menu_step' class='routing_item'>{% trans "Add a step" context "routing" %}</li> <li id='map_menu_to' class='routing_item'>{% trans "To" context "routing" %}</li> diff --git a/chimere/templates/chimere/blocks/news.html b/chimere/templates/chimere/blocks/news.html index 07c2bbb..0514081 100644 --- a/chimere/templates/chimere/blocks/news.html +++ b/chimere/templates/chimere/blocks/news.html @@ -22,7 +22,7 @@ $(function(){ <h3>{{news.title}} – {{ news.date }}</h3> <p>{{news.content|safe}}</p> {% else %} - <h3>{{news.name}} – {{ news.start_date }}{% if news.end_date %} - {{ news.end_date }}{% endif %}</h3> + <h3>{{news.name}} – {{ news.start_date }}{% if news.end_date and news.end_date != news.start_date %} – {{ news.end_date }}{% endif %}</h3> {% if news.default_pictures or news.default_pictures or news.default_multimedia_items%} <div class='small-gallery'> {% for picture in news.default_pictures %} diff --git a/chimere/templates/chimere/category_directory.html b/chimere/templates/chimere/category_directory.html new file mode 100644 index 0000000..7031c83 --- /dev/null +++ b/chimere/templates/chimere/category_directory.html @@ -0,0 +1,35 @@ +{% extends "chimere/base.html" %} +{% load i18n chimere_tags %} +{% load url from future %} +{% block extra_head %} + {{ block.super }} + {{ form.media }} + {% head_jquery %} +{% endblock %} +{% block message_map %}{% endblock %} +{% block message_edit%}{% endblock %} +{% block content %} + {{ block.super }} + <div id="category-directory-content"> + {% if not object_list.count %} + <p>{% trans "No category defined!" %}</p> + {% else %} + <ul id="category-directory" class="list-group">{% for object in object_list %} + {% ifchanged object.category %} + {% if forloop.counter0 %} + </ul> + </li> + {% endif %} + <li class='list-group-item' id='{{object.category|slugify}}'><p class='category-directory-category'>{{object.category}}</p> + <ul> + {% endifchanged %} + <li class='list-group-item'><span class='icon'><img src='{{MEDIA_URL}}{{object.icon.image}}'/></span><a href="{% url 'chimere:category-directory-detail' area_name object.slug %}">{{object.name}}</a></li> + {% endfor %} + </ul> + </li> + </ul> + {% endif %} + </div> +{% endblock %} + + diff --git a/chimere/templates/chimere/category_directory_detail.html b/chimere/templates/chimere/category_directory_detail.html new file mode 100644 index 0000000..1b23b7e --- /dev/null +++ b/chimere/templates/chimere/category_directory_detail.html @@ -0,0 +1,25 @@ +{% extends "chimere/base.html" %} +{% load i18n chimere_tags %} +{% load url from future %} +{% block extra_head %} + {{ block.super }} + {{ form.media }} + {% head_jquery %} +{% endblock %} +{% block message_map %}{% endblock %} +{% block message_edit%}{% endblock %} +{% block content %} + {{ block.super }} + <ol class="breadcrumb"> + <li><a href="{% url 'chimere:category-directory' area_name %}#{{category.category.name|slugify}}">{{category.category.name}}</a></li> + <li class="active">{{category.name}}</li> + </ol> + <ul id="category-directory" class="list-group">{% for marker in items %} + <li class='list-group-item' id='{{item.name|slugify}}'> + {% include "chimere/category_item_detail.html" %} + </li> + {% endfor %} + </ul> +{% endblock %} + + diff --git a/chimere/templates/chimere/category_item_detail.html b/chimere/templates/chimere/category_item_detail.html new file mode 100644 index 0000000..3f90c6c --- /dev/null +++ b/chimere/templates/chimere/category_item_detail.html @@ -0,0 +1,38 @@ +{% load i18n sanitize chimere_tags %} + +<h2>{{ marker.name }}</h2> +<div class='detail_content'> + {% if marker.default_pictures or marker.default_pictures or marker.default_multimedia_items%} + <div class='small-gallery'> + {% for picture in marker.default_pictures %} + {% multimedia_render picture %} + {%endfor%} + {% for multimedia_item in marker.default_multimedia_items %} + {% multimedia_render multimedia_item %} + {%endfor%} + </div> + {%endif%} + <div> + {% if dated %} + <p class='detail_start_date'><label>{% trans "Date:" %}</label> <span>{{marker.start_date|date:"D d M Y"}} + {% if marker.end_date %} - {{marker.end_date|date:"D d M Y"}}</p>{% endif %}</span> + {% endif %} + {% if marker.description %} + <p class='description'>{{ marker.description|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> + {% endif %} + {% for property in marker.getProperties %} + <p class='{{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 %} + {% share_bar marker.name %} + <a href="{% get_tinyfied_url marker area_name %}">{% trans "See on the map" %}</a> + <p class='detail_amendment'><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 an amendment" %} + </a> + {% 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%} + </div> +</div> diff --git a/chimere/templates/search/indexes/chimere/marker_text.txt b/chimere/templates/search/indexes/chimere/marker_text.txt index 7c7929d..d089654 100644 --- a/chimere/templates/search/indexes/chimere/marker_text.txt +++ b/chimere/templates/search/indexes/chimere/marker_text.txt @@ -2,3 +2,5 @@ {{object.name}} {{object.description|safe|striptags|unescape}} {{object.keywords}} +{% for category in object.categories.all %}{{category.keywords}} +{% endfor %} diff --git a/chimere/templates/search/indexes/chimere/route_text.txt b/chimere/templates/search/indexes/chimere/route_text.txt index 5e612cd..d67c88b 100644 --- a/chimere/templates/search/indexes/chimere/route_text.txt +++ b/chimere/templates/search/indexes/chimere/route_text.txt @@ -1,2 +1,4 @@ {{object.name}} {{object.keywords}} +{% for category in object.categories.all %}{{category.keywords}} +{% endfor %} diff --git a/chimere/templates/search/search.html b/chimere/templates/search/search.html index 95d3937..ab3e61e 100644 --- a/chimere/templates/search/search.html +++ b/chimere/templates/search/search.html @@ -30,7 +30,7 @@ var end_do_you_mean = "{% trans '?' %}"; {% else %} <form id='search-form' class='autocomplete-me'> <input type="text" id="id_q" name="q" autocomplete="off"/> - <button name='haystack-search' id='haystack-search' type='button' disabled='disabled' class="btn btn-default"><span class='action-label'>{% trans "Search" %} </span><span class="glyphicon glyphicon-search"></span></button> + <button name='haystack-search' id='haystack-search' type='button' class="btn btn-default"><span class='action-label'>{% trans "Search" %} </span><span class="glyphicon glyphicon-search"></span></button> </form> <div id='spelling'></div> <div id='search-result'></div> @@ -42,10 +42,11 @@ $(function(){ $("#main-map").chimere("razMap"); haystack_search(evt); }); + {% if autocomplete %} window.autocomplete = new Autocomplete({ form_selector: '.autocomplete-me' }); - window.autocomplete.setup(); + window.autocomplete.setup();{% endif %} }); </script> {% endif %} diff --git a/chimere/templatetags/chimere_tags.py b/chimere/templatetags/chimere_tags.py index e3b439f..34cb4b2 100644 --- a/chimere/templatetags/chimere_tags.py +++ b/chimere/templatetags/chimere_tags.py @@ -57,13 +57,13 @@ def get_news(map=None): Q(end_date__gte=today)| (Q(end_date__isnull=True) & Q(start_date__gte=today))) - if not'CHIMERE_ALL_DATED_ARE_FRONT' in dir(settings)\ + if not 'CHIMERE_ALL_DATED_ARE_FRONT' in dir(settings)\ or not settings.CHIMERE_ALL_DATED_ARE_FRONT: q = q.filter(is_front_page=True) if map: q = q.filter(map.getIncludeMarker()) news += list(q) - news.sort(key=lambda x:x.date, reverse=True) + news.sort(key=lambda x:x.date) return news @register.inclusion_tag('chimere/blocks/welcome.html', takes_context=True) @@ -182,7 +182,8 @@ def head_form(): @register.inclusion_tag('chimere/blocks/map_menu.html', takes_context=True) def map_menu(context): context_data = {'routing': settings.CHIMERE_ENABLE_ROUTING \ - if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') else False} + if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') else False, + 'simple':context.get('simple')} return context_data @register.inclusion_tag('chimere/blocks/routing.html', takes_context=True) @@ -330,9 +331,10 @@ def get_tinyfied_url(marker, map_name=''): @register.inclusion_tag('chimere/blocks/share_bar.html', takes_context=True) -def share_bar(context, name='', email_only=False): +def share_bar(context, name='', email_only=False, rss=True): context['STATIC_URL'] = settings.STATIC_URL context['name'] = name + context['rss'] = rss context['email_only'] = email_only context['share_networks'] = [(defaultfilters.slugify(name), url, icon) for name, url, icon in settings.CHIMERE_SHARE_NETWORKS] diff --git a/chimere/tests.py b/chimere/tests.py index e06b073..0e500f1 100644 --- a/chimere/tests.py +++ b/chimere/tests.py @@ -365,6 +365,22 @@ class XmlXsltImporterTest(TestCase, ImporterTest): importer1.categories.add(subcategories[0]) self.marker_importers = [(importer1, 10),] + +class JsonImporterTest(TestCase, ImporterTest): + def setUp(self): + subcategories = subcategory_setup() + jsonfile = File(open(test_dir_path + 'tests/test.json')) + importer1 = Importer.objects.create( + importer_type='JSON', + source_file=jsonfile, + filtr='{"title":"name", "id_agenda":"id", ' + '"content":"description", "date_start_evt":"start_date", ' + '"date_end_evt":"end_date"}', + default_localisation='SRID=4326;POINT(-4.5 48.4)',) + importer1.categories.add(subcategories[0]) + self.marker_importers = [(importer1, 5), ] + + class FeedsTest(TestCase): def setUp(self): self.areas = areas_setup() diff --git a/chimere/tests/test.json b/chimere/tests/test.json new file mode 100644 index 0000000..6c9fa0c --- /dev/null +++ b/chimere/tests/test.json @@ -0,0 +1,57 @@ + +[ +{"id_agenda":"1759", +"title":"Exposition municipale d'Orsay : inscription en ligne", +"content":"TEST +TESTST", +"date_start_evt":"2015-08-20", +"date_end_evt":"2015-12-14", +"date_start_display":"2015-10-20", +"date_end_display":"2015-12-14", +"date_add":"2015-10-20 10:37:52", +"date_update":"2015-10-27 14:56:18" +}, +{"id_agenda":"179", +"title":"Exposition municipale d'Orsay : inscription en ligne", +"content":"TEST +TESTST", +"date_start_evt":"2015-08-20", +"date_end_evt":"2015-12-14", +"date_start_display":"2015-10-20", +"date_end_display":"2015-12-14", +"date_add":"2015-10-20 10:37:52", +"date_update":"2015-10-27 14:56:18" +}, +{"id_agenda":"19", +"title":"Exposition municipale d'Orsay : inscription en ligne", +"content":"TEST +TESTST", +"date_start_evt":"2015-08-20", +"date_end_evt":"2015-12-14", +"date_start_display":"2015-10-20", +"date_end_display":"2015-12-14", +"date_add":"2015-10-20 10:37:52", +"date_update":"2015-10-27 14:56:18" +}, +{"id_agenda":"17", +"title":"Exposition municipale d'Orsay : inscription en ligne", +"content":"TEST +TESTST", +"date_start_evt":"2015-08-20", +"date_end_evt":"2015-12-14", +"date_start_display":"2015-10-20", +"date_end_display":"2015-12-14", +"date_add":"2015-10-20 10:37:52", +"date_update":"2015-10-27 14:56:18" +}, +{"id_agenda":"59", +"title":"Exposition municipale d'Orsay : inscription en ligne", +"content":"TEST +TESTST", +"date_start_evt":"2015-08-20", +"date_end_evt":"2015-12-14", +"date_start_display":"2015-10-20", +"date_end_display":"2015-12-14", +"date_add":"2015-10-20 10:37:52", +"date_update":"2015-10-27 14:56:18" +}] diff --git a/chimere/urls.py b/chimere/urls.py index 256c08f..b9ec380 100644 --- a/chimere/urls.py +++ b/chimere/urls.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2008-2015 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2008-2014 É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 @@ -23,33 +23,34 @@ from django.contrib import admin from django.core.exceptions import ImproperlyConfigured admin.autodiscover() -from chimere.models import Map +from chimere.views import CategoryDirectoryView, CategoryView from chimere.feeds import LatestPOIsByCategory, LatestPOIsBySubCategory, \ LatestPOIs, LatestPOIsByZone, LatestPOIsByZoneID + def i18n_javascript(request): return admin.site.i18n_javascript(request) urlpatterns = patterns('chimere.views', - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?simple$', 'index', {'simple':True}, + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?simple$', 'index', {'simple':True}, name="simple_index") ) if settings.CHIMERE_FEEDS: urlpatterns += patterns('', - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?feeds$', 'chimere.views.rss', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds$', 'chimere.views.rss', name='feeds-form'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?feeds/category/(?P<category_id>\d+)$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/category/(?P<category_id>\d+)$', LatestPOIsByCategory(), name='feeds-cat'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?feeds/subcategory/(?P<category_id>\d+)$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/subcategory/(?P<category_id>\d+)$', LatestPOIsBySubCategory(), name='feeds-subcat'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?feeds/global/$', LatestPOIs(), + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/global/$', LatestPOIs(), name='feeds-global'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?feeds/area/(?P<area>[0-9-_.]+)$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/area/(?P<area>[0-9-_.]+)$', LatestPOIsByZone(), name='feeds-area'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?feeds/mapid/(?P<map_id>\d+)$', - LatestPOIsByZoneID(), name='feeds-mapid'), + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?feeds/areaid/(?P<area_id>\d+)$', + LatestPOIsByZoneID(), name='feeds-areaid'), ) if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') \ @@ -59,7 +60,7 @@ if hasattr(settings, 'CHIMERE_ENABLE_ROUTING') \ raise ImproperlyConfigured(u"CHIMERE_ROUTING_TRANSPORT must be set in"\ u" settings if you enable routing") urlpatterns += patterns('chimere.views', - url(r'^(?P<map_name>[a-zA-Z0-9_-]*/)?route/'\ + url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?route/'\ r'(?P<transport>(%s))/((?P<speed>[0-9][0-9]*)/)?' r'(?P<lon1>[-]?[0-9]+[.]?[0-9]*)_(?P<lat1>[-]?[0-9]+[.]?[0-9]*)_'\ r'(?P<lonlat_steps>([-]?[0-9]+[.]?[0-9]*_[-]?[0-9]+[.]?[0-9]*_)*)'\ @@ -85,45 +86,46 @@ if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \ #urlpatterns += [url(r'^search/', include('haystack.urls')),] urlpatterns += patterns('chimere.views', - url(r'^logout/?$', 'logout_view', name="logout"), url(r'^charte/?$', 'charte', name="charte"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?contact/?$', 'contactus', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?contact/?$', 'contactus', name="contact"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?edit/$', 'edit', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit/$', 'edit', name="edit"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?edit/(?P<item_id>\w+)/(?P<submited>\w+)?$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit/(?P<item_id>\w+)/(?P<submited>\w+)?$', 'edit', name="edit-item"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?edit-route/$', 'editRoute', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-route/$', 'editRoute', name="editroute"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?edit-route/(?P<item_id>\w+)/(?P<submited>\w+)?$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?edit-route/(?P<item_id>\w+)/(?P<submited>\w+)?$', 'editRoute', name="editroute-item"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getDetail/(?P<marker_id>\d+)/?$', 'getDetail', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getDetail/(?P<marker_id>\d+)/?$', 'getDetail', name="get_detail"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getDescriptionDetail/?(?P<category_id>\d+)/?$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getDescriptionDetail/?(?P<category_id>\d+)/?$', 'getDescriptionDetail', name="get_description_detail"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getGeoObjects/'\ + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getGeoObjects/'\ r'(?P<category_ids>[a-zA-Z0-9_-]+)(/(?P<status>\w+))?$', 'getGeoObjects', name="getgeoobjects"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getAvailableCategories/$', - 'get_available_categories', name="get_categories"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?get-marker/'\ + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?get-marker/'\ r'(?P<pk>[0-9]+)$', 'getMarker', name="get-marker"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getAllCategories/$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getAvailableCategories/$', + 'get_available_categories', name="get_categories"), + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getAllCategories/$', 'get_all_categories', name="get_all_categories"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?getCategory/(?P<category_id>\d+)/?$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?getCategory/(?P<category_id>\d+)/?$', 'getCategory', name="get_category"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]*/)?get-share-url/(?P<network>\w+)?$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?get-share-url/(?P<network>\w+)?$', 'getShareUrl', name="get-share-url"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]*/)?ty/(?P<tiny_urn>\w+)$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?ty/(?P<tiny_urn>\w+)$', 'redirectFromTinyURN', name="tiny"), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?upload_file/((?P<category_id>\w+)/)?$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?upload_file/((?P<category_id>\w+)/)?$', 'uploadFile', name='upload_file'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?process_route_file/(?P<file_id>\d+)/$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?process_route_file/(?P<file_id>\d+)/$', 'processRouteFile', name='process_route_file'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?dyn/(?P<page_id>\w+)/$', + url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?dyn/(?P<page_id>\w+)/$', 'extraPage', name='extra_page'), - url(r'^(?P<map_name>[a-zA-Z0-9_-]+/)?json/(?P<app_name>[a-zA-Z0-9_-]+)/(?P<filename>[a-zA-Z0-9_-]+).json$', 'get_json', - name='get-json'), + url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?categories/$', + CategoryDirectoryView.as_view(), name='category-directory'), + url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?categories/(?P<category_slug>[a-zA-Z0-9_-]+)$', + CategoryView.as_view(), name='category-directory-detail'), # At the end, because it catches large - url(r'^(?P<map_name>[a-zA-Z0-9_-]+)?', 'index', name="index"), + url(r'^(?P<area_name>[a-zA-Z0-9_-]+)?', 'index', name="index"), ) diff --git a/chimere/utils.py b/chimere/utils.py index 790fd56..8066255 100644 --- a/chimere/utils.py +++ b/chimere/utils.py @@ -22,14 +22,14 @@ Utilitaries """ import csv +import collections import datetime import feedparser -import simplejson as json +import json import os import re import StringIO import tempfile -from urllib import urlencode import urllib2 import unicodedata import zipfile @@ -47,26 +47,30 @@ from django.utils.translation import ugettext_lazy as _ from chimere import get_version from external_utils import OsmApi + def unicode_normalize(string): if type(string) == str: string = unicode(string.decode('utf-8')) return ''.join( (c for c in unicodedata.normalize('NFD', string) - if unicodedata.category(c) != 'Mn')) + if unicodedata.category(c) != 'Mn')) + class ImportManager(object): u""" Generic class for specific importers """ default_source = None + def __init__(self, importer_instance): self.importer_instance = importer_instance if self.importer_instance.default_name: self.default_name = self.importer_instance.default_name else: - self.default_name = " - ".join([cat.name + self.default_name = " - ".join([ + cat.name for cat in self.importer_instance.categories.order_by( - 'name').all()]) + 'name').all()]) def get(self): raise NotImplementedError @@ -85,8 +89,8 @@ class ImportManager(object): item = None if import_key or pk: dct_import = { - 'import_key__icontains':'%s:%s;' % (key, import_key), - 'import_source':self.importer_instance.source} + 'import_key__icontains': '%s:%s;' % (key, import_key), + 'import_source': self.importer_instance.source} ref_item = cls.objects.filter(**dct_import) try: item = None @@ -102,7 +106,7 @@ class ImportManager(object): return ref_item, None, None if not self.importer_instance.overwrite \ and ref_item.modified_since_import: - dct_import['ref_item'] = ref_item + return ref_item, None, None else: item = ref_item for k in values: @@ -123,16 +127,17 @@ class ImportManager(object): if not self.importer_instance.get_description and \ self.importer_instance.default_description: values['description'] = \ - self.importer_instance.default_description + self.importer_instance.default_description values.update({ - 'import_source':self.importer_instance.source}) - values['status'] = 'I' \ - if not self.importer_instance.automatic_update else 'A' + 'import_source': self.importer_instance.source}) + values['status'] = self.importer_instance.default_status if not self.importer_instance.associate_marker_to_way\ - and cls.__name__ == 'Route': + and cls.__name__ == 'Route': values['has_associated_marker'] = False try: item = cls.objects.create(**values) + item.modified_since_import = False + item.save() except TypeError: # error on data source return None, False, False @@ -159,8 +164,8 @@ class ImportManager(object): current_file_name = None for name in namelist: if name.endswith(suffix) \ - or name.endswith(suffix.lower()) \ - or name.endswith(suffix.upper()): + or name.endswith(suffix.lower()) \ + or name.endswith(suffix.upper()): current_file_name = name filenames.append(current_file_name) files = [] @@ -181,7 +186,7 @@ class ImportManager(object): if not hasattr(source, 'read'): if not source: source = self.importer_instance.source \ - if self.importer_instance.source else self.default_source + if self.importer_instance.source else self.default_source try: url = source if extra_url: @@ -208,6 +213,7 @@ class ImportManager(object): source = files[0] if len(suffixes) == 1 else files return (source, None) + class KMLManager(ImportManager): u""" KML importer @@ -216,6 +222,7 @@ class KMLManager(ImportManager): """ XPATH = '//kml:Folder/kml:name[text()="%s"]/../kml:Placemark' DEFAULT_XPATH = '//kml:Placemark' + def __init__(self, importer_instance, ns=''): super(KMLManager, self).__init__(importer_instance) self.ns = ns @@ -250,9 +257,9 @@ class KMLManager(ImportManager): if not self.ns: self.ns = tree.getroot().nsmap[None] xpath = self.XPATH % self.importer_instance.filtr \ - if self.importer_instance.filtr else self.DEFAULT_XPATH + if self.importer_instance.filtr else self.DEFAULT_XPATH for placemark in tree.xpath(xpath, - namespaces={'kml':self.ns}): + namespaces={'kml': self.ns}): name, point, line = None, None, None pl_id = placemark.attrib.get('id') pl_key = 'kml-%d' % self.importer_instance.pk @@ -280,10 +287,10 @@ class KMLManager(ImportManager): 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} + dct = {'description': description, + 'name': name, + 'origin': self.importer_instance.origin, + 'license': self.importer_instance.license} if point: dct['point'] = point cls = Marker @@ -293,7 +300,7 @@ class KMLManager(ImportManager): cls = Route if cls: item, updated, created = self.create_or_update_item( - cls, dct, pl_id, key=pl_key) + cls, dct, pl_id, key=pl_key) if updated: updated_item += 1 if created: @@ -302,15 +309,17 @@ class KMLManager(ImportManager): @classmethod def export(cls, queryset): - dct = {'name':settings.PROJECT_NAME, - 'description':unicode(datetime.date.today()), - 'locations':queryset.all() + dct = { + 'name': settings.PROJECT_NAME, + 'description': unicode(datetime.date.today()), + 'locations': queryset.all() } - filename = unicode_normalize(settings.PROJECT_NAME + dct['description']\ + filename = unicode_normalize(settings.PROJECT_NAME + dct['description'] + '.kml') result = render_to_response('chimere/export.kml', dct) return filename, result + class ShapefileManager(ImportManager): u""" Shapefile importer @@ -352,7 +361,7 @@ class ShapefileManager(ImportManager): srid = settings.CHIMERE_EPSG_DISPLAY_PROJECTION msg = _(u"SRID cannot be guessed. The default SRID (%s) has " u"been used.") % srid - #If imported items are not well located " + # If imported items are not well located " # u"ask your data provider for the SRID to use.") % srid shapefilename = tmpdir + os.sep + sources[0] ds = DataSource(shapefilename) @@ -375,7 +384,7 @@ class ShapefileManager(ImportManager): u"is not managed by Chimère.") % lyr.geom_type) geom_key = 'point' if lyr.geom_type == 'Point' else 'route' geom_cls = Marker if lyr.geom_type == 'Point' else Route - indexes = [] + # indexes = [] for idx, feat in enumerate(lyr): name = unicode(idx) if lbl_name: @@ -385,7 +394,7 @@ class ShapefileManager(ImportManager): except UnicodeDecodeError: try: name = unicode( - name.decode(settings.CHIMERE_SHAPEFILE_ENCODING)) + name.decode(settings.CHIMERE_SHAPEFILE_ENCODING)) except: continue try: @@ -394,15 +403,17 @@ class ShapefileManager(ImportManager): 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 '' + 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, - 'origin':self.importer_instance.origin, - 'license':self.importer_instance.license - } + dct = { + geom_key: 'SRID=%s;%s' % (srid, geom), + '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) + geom_cls, dct, import_key) if updated: updated_item += 1 if created: @@ -427,8 +438,9 @@ class ShapefileManager(ImportManager): tmp_name = tmp.name field_names = [field.name for field in queryset.model._meta.fields] - geo_field = getattr(queryset.model, - 'point' if 'point' in field_names else 'route')._field + geo_field = getattr( + queryset.model, + 'point' if 'point' in field_names else 'route')._field dr = ogr.GetDriverByName('ESRI Shapefile') ds = dr.CreateDataSource(tmp_name) @@ -454,7 +466,7 @@ class ShapefileManager(ImportManager): feat = ogr.Feature(feature_def) feat.SetField('name', str(unicode_normalize(item.name)[:80])) feat.SetField('category', - str(unicode_normalize(category.name)[:80])) + str(unicode_normalize(category.name)[:80])) geom = getattr(item, geo_field.name) if not geom: @@ -480,6 +492,7 @@ class ShapefileManager(ImportManager): buff.close() return filename, zip_stream + class CSVManager(ImportManager): u""" CSV importer @@ -490,9 +503,8 @@ class CSVManager(ImportManager): # (label, getter, setter) COLS = [("Id", 'pk', 'pk'), (_(u"Name"), 'name', 'name'), - (_(u"Categories"), lambda obj:", ".join( - [c.name for c in obj.categories.all()]), - set_categories), + (_(u"Categories"), lambda obj: ", ".join( + [c.name for c in obj.categories.all()]), set_categories), (_(u"State"), 'status', lambda x: x), (_(u"Description"), 'description', 'description'), (_(u"Localisation"), 'geometry', 'geometry')] @@ -512,40 +524,32 @@ class CSVManager(ImportManager): if msg: return (0, 0, msg) reader = csv.reader(source, delimiter=';', quotechar='"') - prop_cols, nominatim_fields = [], {} - reverse_nominatim_dct = dict((v, k) - for k, v in settings.CHIMERE_NOMINATIM_FIELDS.iteritems()) - nominatim_default_query = settings.CHIMERE_NOMINATIM_FIELDS - for idx, pm in enumerate(Marker.all_properties()): + prop_cols = [] + for pm in Marker.all_properties(): prop_cols.append((pm.name, pm.getAttrName(), - pm.getAttrName()+'_set')) - if settings.CHIMERE_NOMINATIM_FIELDS and \ - pm.slug in reverse_nominatim_dct: - nominatim_fields[idx+len(self.COLS)] = \ - reverse_nominatim_dct[pm.slug] - nominatim_default_query.pop(reverse_nominatim_dct[pm.slug]) + pm.getAttrName() + '_set')) cols = list(self.COLS) + prop_cols - datas = [] + # datas = [] for idx, row in enumerate(reader): - if not idx: # first row + if not idx: # first row try: assert(len(row) >= len(cols)) except AssertionError: - return (0, 0, _(u"Invalid CSV format - not enough columns " - u"check a reference CSV file")) + 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] + # pk, name, cats, state = row[0], row[1], row[2], row[3] + pk, name = row[0], row[1] geom = row[5] description = '' if self.importer_instance.get_description: description = row[4] COL_INDEX = 6 - dct = {'description':description, - 'name':name, - 'origin':self.importer_instance.origin, - 'license':self.importer_instance.license} + dct = {'description': description, + 'name': name, + 'origin': self.importer_instance.origin, + 'license': self.importer_instance.license} cls = None if 'POINT' in geom: cls = Marker @@ -553,27 +557,11 @@ class CSVManager(ImportManager): elif 'LINE' in geom: cls = Route dct['route'] = geom - elif settings.CHIMERE_NOMINATIM_FIELDS: - nominatim_query = settings.NOMINATIM_URL + "?" - nominatim_keys = nominatim_default_query.copy() - nominatim_keys['format'] = 'json' - for idx in nominatim_fields: - nominatim_keys[nominatim_fields[idx]] = row[idx] - nominatim_query += urlencode(nominatim_keys) - remotehandle = urllib2.urlopen(nominatim_query) - result = StringIO.StringIO(remotehandle.read()) - remotehandle.close() - result = json.load(result) - if not result: - continue - result = result[0] - cls = Marker - dct['point'] = "POINT(%s %s)" % (result['lon'], result['lat']) else: continue import_key = pk if pk else name.decode('utf-8') - item, updated, created = self.create_or_update_item(cls, dct, - import_key, pk=pk) + item, updated, created = self.create_or_update_item( + cls, dct, import_key, pk=pk) if updated: updated_item += 1 if created: @@ -581,19 +569,17 @@ class CSVManager(ImportManager): for idx, col in enumerate(cols[COL_INDEX:]): name, getter, setter_val = col setter = getattr(item, setter_val) - val = row[idx+COL_INDEX] + val = row[idx + COL_INDEX] setter(item, val) return (new_item, updated_item, msg) @classmethod - def export(cls, queryset, cols=[]): - dct = {'description':unicode(datetime.date.today()), 'data':[]} - cls_name = queryset.model.__name__.lower() - if not cols: - cols = list(cls.COLS) - if hasattr(queryset.model, 'all_properties'): - for pm in queryset.model.all_properties(): - cols.append((pm.name, pm.getAttrName(), pm.getAttrName()+'_set')) + def export(cls, queryset): + dct = {'description': unicode(datetime.date.today()), 'data': []} + # cls_name = queryset.model.__name__.lower() + cols = list(cls.COLS) + for pm in queryset.model.all_properties(): + 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(): @@ -602,16 +588,14 @@ class CSVManager(ImportManager): if callable(attr): data.append(attr(item)) else: - v = getattr(item, attr) - if v == None: - v = '' - data.append(v) + data.append(getattr(item, attr)) dct['data'].append(data) - filename = unicode_normalize(settings.PROJECT_NAME + dct['description']\ + filename = unicode_normalize(settings.PROJECT_NAME + dct['description'] + '.csv') result = render_to_response('chimere/export.csv', dct) return filename, result + class GeoRSSManager(ImportManager): u""" RSS importer. @@ -627,19 +611,19 @@ class GeoRSSManager(ImportManager): - number of item updated ; - error detail on error """ - from models import Marker + from models import Marker, Route new_item, updated_item, msg = 0, 0, '' feed = feedparser.parse(self.importer_instance.source) - if feed['bozo'] and not isinstance(feed['bozo_exception'], - feedparser.CharacterEncodingOverride): + if feed['bozo'] and not isinstance( + feed['bozo_exception'], feedparser.CharacterEncodingOverride): 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 \ and not ("geo_lat" in item and "geo_long" in item): continue cls = None - dct = {'origin':self.importer_instance.origin, - 'license':self.importer_instance.license} + dct = {'origin': self.importer_instance.origin, + 'license': self.importer_instance.license} if 'georss_point' in item or "geo_lat" in item: cls = Marker if 'georss_point' in item: @@ -661,11 +645,11 @@ class GeoRSSManager(ImportManager): 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])) + 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) + ",".join(reordered_points) dct['name'] = item['title'] pl_id = item['id'] if 'id' in item else item['title'] @@ -676,10 +660,101 @@ class GeoRSSManager(ImportManager): new_item += 1 return (new_item, updated_item, msg) + +class JsonManager(ImportManager): + u""" + Json importer. + This manager only gets and do not produce Json feed + """ + + def get(self): + u""" + Get data from a json 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, '' + source, msg = self.get_source_file(['.json']) + if msg: + return (0, 0, msg) + + vals = source.read().replace('\n', ' ') + try: + values = json.JSONDecoder( + object_pairs_hook=collections.OrderedDict).decode(vals) + except ValueError as e: + return (new_item, updated_item, + _(u"JSON file is not well formed: " + e.message)) + # configuration in filtr + try: + filtr = json.JSONDecoder().decode(self.importer_instance.filtr) + except ValueError: + return ( + new_item, updated_item, + _(u"Bad configuration: filter field must be a valid " + u"JSON string")) + + vls = filtr.values() + for k in ('name', 'id', 'description'): + if k not in vls: + return ( + new_item, updated_item, + _(u"A key must be associated to \"%s\" in the " + u"filter.") % k) + + default_dct = {'origin': self.importer_instance.origin, + 'license': self.importer_instance.license} + if 'prefix_name' in filtr: + default_dct['name'] = filtr.pop('prefix_name') + if 'prefix_description' in filtr: + default_dct['description'] = filtr.pop('prefix_description') + if self.importer_instance.default_localisation: + default_dct['point'] = self.importer_instance.default_localisation + + for item in values: + dct = default_dct.copy() + for k in filtr: + if k in item and item[k]: + if filtr[k] not in dct: + dct[filtr[k]] = "" + else: + if filtr[k] == 'description': + dct[filtr[k]] += "<br/>" + else: + dct[filtr[k]] += " " + dct[filtr[k]] += item[k] + if 'point' in item: + x, y = item['point'].split(",") + dct['point'] = 'SRID=4326;POINT(%s %s)' % (x, y) + elif 'lat' in item and item['lat'] \ + and 'lon' in item and item['lon']: + dct['point'] = 'SRID=4326;POINT(%s %s)' % (item['lon'], + item['lat']) + elif 'x' in item and item['x'] \ + and 'y' in item and item['y']: + dct['point'] = 'SRID=4326;POINT(%s %s)' % (item['x'], + item['y']) + if not dct['point']: + continue + cls = Marker + pl_id = (dct.pop('id') if 'id' in dct else dct['name']) \ + + "-" + unicode(self.importer_instance.pk) + 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 + class OSMManager(ImportManager): u""" OSM importer/exporter @@ -697,8 +772,8 @@ class OSMManager(ImportManager): - updated items; - error detail on error. """ - source, msg = self.get_source_file(['.osm'], - extra_url=self.importer_instance.filtr) + source, msg = self.get_source_file( + ['.osm'], extra_url=self.importer_instance.filtr) if not source: return (0, 0, msg) @@ -711,8 +786,8 @@ class OSMManager(ImportManager): return 0, 0, _(u"Nothing to import") def import_ways(self, tree): - from chimere.models import Marker, Route - msg, items, new_item, updated_item = "", [], 0 , 0 + from chimere.models import Route + msg, items, new_item, updated_item = "", [], 0, 0 nodes = {} for node in tree.xpath('//node'): node_id = node.attrib.get('id') @@ -734,17 +809,17 @@ class OSMManager(ImportManager): points.append(item.get('ref')) if not points: continue - wkt = 'SRID=4326;LINESTRING(%s)' % ",".join([nodes[point_id] - 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} + wkt = 'SRID=4326;LINESTRING(%s)' % ",".join( + [nodes[point_id] 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) + Route, dct, node_id, version) if updated: updated_item += 1 if created: @@ -754,7 +829,7 @@ class OSMManager(ImportManager): def import_nodes(self, tree): from chimere.models import Marker - msg, items, new_item, updated_item = "", [], 0 , 0 + msg, items, new_item, updated_item = "", [], 0, 0 for node in tree.xpath('//node'): name = None node_id = node.attrib.get('id') @@ -767,15 +842,15 @@ class OSMManager(ImportManager): name = item.attrib.get('v') point = 'SRID=4326;POINT(%s %s)' % (node.get('lon'), 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} + 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) + Marker, dct, node_id, version) if updated: updated_item += 1 if created: @@ -810,8 +885,8 @@ class OSMManager(ImportManager): username = username.encode('latin1') password = password.encode('latin1') api = OsmApi.OsmApi(api=api, username=username, password=password) - api.ChangesetCreate({u"comment": u"Import from Chimère %s" % \ - get_version()}) + api.ChangesetCreate({u"comment": u"Import from Chimère %s" % + get_version()}) hooks = RE_HOOK.findall(self.importer_instance.filtr) if not hooks: hooks = RE_HOOK.findall(self.importer_instance.source) @@ -825,28 +900,31 @@ class OSMManager(ImportManager): continue if key == 'bbox': x1, y1, x2, y2 = [float(val) for val in value.split(',')] - bbox = GEOSGeometry( + bbox = GEOSGeometry( 'POLYGON((%f %f,%f %f,%f %f,%f %f,%f %f))' % ( - x1, y1, x2, y1, x2, y2, x1, y2, x1, y1), srid=4326) + x1, y1, x2, y1, x2, y2, x1, y2, x1, y1), srid=4326) continue tags[key] = value if not tags: return 0, _(u"No non ambigious tag is defined in the XAPI request") if not bbox: - return 0, _(u"No bounding box is defined in the XAPI request."\ - u"If you are sure to manage the entire planet set the bounding box"\ - u" to -180,-90,180,90") - default_dct = {'tag':tags, - 'import_source':self.importer_instance.source} + return 0, _( + u"No bounding box is defined in the XAPI request." + u"If you are sure to manage the entire planet set the " + u"bounding box to -180,-90,180,90") + default_dct = {'tag': tags, + 'import_source': self.importer_instance.source} idx = -1 - for idx, item in enumerate(Marker.objects.filter(status='A', - point__contained=bbox, - categories=self.importer_instance.categories.all(), - not_for_osm=False, modified_since_import=True, - route=None).all()): + for idx, item in enumerate( + Marker.objects.filter( + status='A', + point__contained=bbox, + categories=self.importer_instance.categories.all(), + not_for_osm=False, modified_since_import=True, + route=None).all()): dct = default_dct.copy() - dct.update({'lon':item.point.x, - 'lat':item.point.y}) + dct.update({'lon': item.point.x, + 'lat': item.point.y}) dct['tag']['name'] = item.name node = None import_key = item.get_key('OSM') @@ -861,7 +939,7 @@ class OSMManager(ImportManager): if error.status == 404: dct.pop('id') dct.pop('version') - pass # if the node doesn't exist it is created + pass # if the node doesn't exist it is created else: raise if not updated: @@ -870,20 +948,23 @@ class OSMManager(ImportManager): item.import_version = node['version'] item.save() api.ChangesetClose() - return idx+1, None + return idx + 1, None + -import urllib2, chardet, HTMLParser +import chardet +import HTMLParser from BeautifulSoup import BeautifulSoup -from lxml import etree + RE_CLEANS = ((re.compile('(\n)*|^( )*(\n)*( )*|( )*(\n)*( )*$'), ''), (re.compile(' ( )*'), ' '), (re.compile(r"""<a href=["'](?!https?)(.*)["']"""), - '<a href="%(base_url)s\\1"'), + '<a href="%(base_url)s\\1"'), ) from calendar import TimeEncoding, month_name + def get_month_name(month_no, locale): with TimeEncoding(locale) as encoding: s = month_name[month_no] @@ -891,62 +972,62 @@ def get_month_name(month_no, locale): s = s.decode(encoding) return s -MONTH_NAMES = {locale:[get_month_name(no_month, locale+'.UTF-8') - for no_month in xrange(1, 13)] for locale in ['fr_FR']} +MONTH_NAMES = {locale: [get_month_name(no_month, locale + '.UTF-8') + for no_month in xrange(1, 13)] for locale in ['fr_FR']} try: - UNI_MONTH_NAMES = {locale:[m.decode('utf-8') for m in MONTH_NAMES[locale]] - for locale in MONTH_NAMES} + UNI_MONTH_NAMES = {locale: [m.decode('utf-8') for m in MONTH_NAMES[locale]] + for locale in MONTH_NAMES} except UnicodeEncodeError: - UNI_MONTH_NAMES = {locale:[m for m in MONTH_NAMES[locale]] - for locale in MONTH_NAMES} - -DATE_PARSINGS = {'fr_FR':[ - re.compile(r'(?P<day1>\d{1,2}) '\ - r'(?P<month1>'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') '\ - r'(?P<year1>\d{4})?[^\d]*'\ - r'(?P<day2>\d{1,2}) '\ - r'(?P<month2>'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') *'\ - r'(?P<year2>\d{4})?.*'), - re.compile(r'(?P<day1>\d{1,2}) '\ - r'(?P<month1>'+ '|'.join(UNI_MONTH_NAMES['fr_FR']) +') *'\ - r'(?P<year1>\d{4})?') - ], - 'en':[ - re.compile(r'(?P<year1>\d{4})-'\ - r'(?P<month1>\d{2})-'\ - r'(?P<day1>\d{2})'\ - r'(?:T'\ - r'(?P<hour1>\d{2})?:'\ - r'(?P<minut1>\d{2})?:'\ - r'(?P<second1>\d{2})'\ - r')?.*'\ - r'(?P<year2>\d{4})-'\ - r'(?P<month2>\d{2})-'\ - r'(?P<day2>\d{2})'\ - r'(?:T'\ - r'(?P<hour2>\d{2})?:'\ - r'(?P<minut2>\d{2})?:'\ - r'(?P<second2>\d{2})'\ - r')?.*' - ), - re.compile(r'(?P<year1>\d{4})-'\ - r'(?P<month1>\d{2})-'\ - r'(?P<day1>\d{2})'\ - r'(?:T'\ - r'(?P<hour1>\d{2})?:'\ - r'(?P<minut1>\d{2})?:'\ - r'(?P<second1>\d{2})'\ - r')?' - ) - ], - } + UNI_MONTH_NAMES = {locale: [m for m in MONTH_NAMES[locale]] + for locale in MONTH_NAMES} + +DATE_PARSINGS = { + 'fr_FR': [ + re.compile(r'(?P<day1>\d{1,2}) ' + r'(?P<month1>' + '|'.join(UNI_MONTH_NAMES['fr_FR']) + ') ' + r'(?P<year1>\d{4})?[^\d]*' + r'(?P<day2>\d{1,2}) ' + r'(?P<month2>' + '|'.join(UNI_MONTH_NAMES['fr_FR']) + ') *' + r'(?P<year2>\d{4})?.*'), + re.compile(r'(?P<day1>\d{1,2}) ' + r'(?P<month1>' + '|'.join(UNI_MONTH_NAMES['fr_FR']) + ') * ' + r'(?P<year1>\d{4})?')], + 'en': [ + re.compile(r'(?P<year1>\d{4})-' + r'(?P<month1>\d{2})-' + r'(?P<day1>\d{2})' + r'(?:T' + r'(?P<hour1>\d{2})?:' + r'(?P<minut1>\d{2})?:' + r'(?P<second1>\d{2})' + r')?.*' + r'(?P<year2>\d{4})-' + r'(?P<month2>\d{2})-' + r'(?P<day2>\d{2})' + r'(?:T' + r'(?P<hour2>\d{2})?:' + r'(?P<minut2>\d{2})?:' + r'(?P<second2>\d{2})' + r')?.*'), + re.compile(r'(?P<year1>\d{4})-' + r'(?P<month1>\d{2})-' + r'(?P<day1>\d{2})' + r'(?:T' + r'(?P<hour1>\d{2})?:' + r'(?P<minut1>\d{2})?:' + r'(?P<second1>\d{2})' + r')?')], +} + def clean_field(value): return value.strip() + class HtmlXsltManager(ImportManager): PARSER = 'HTMLParser' + def get(self): u""" Get data from the source @@ -970,7 +1051,7 @@ class HtmlXsltManager(ImportManager): soup = BeautifulSoup(data) main_page = soup.prettify() # convert it to valid XHTML - #doc, errors = tidy_document(main_page) + # doc, errors = tidy_document(main_page) doc = main_page dom = etree.HTML(doc, getattr(etree, self.PARSER)()) try: @@ -994,8 +1075,8 @@ class HtmlXsltManager(ImportManager): base_url = u"/".join(self.importer_instance.source.split(u'/')[:-1]) base_url += u"/" for item in newdom.getroot(): - c_item = {child.tag:clean_field(child.text) - for child in item.getchildren() if child.text} + c_item = {child.tag: clean_field(child.text) + for child in item.getchildren() if child.text} # try to have more information on the linked page if transform_child and 'link' in c_item: # not an absolute address @@ -1016,8 +1097,8 @@ class HtmlXsltManager(ImportManager): child_dom = etree.HTML(child_page, etree.HTMLParser()) extra_keys = transform_child(child_dom).getroot() if len(extra_keys): - c_item.update({extra.tag:etree.tostring(extra) - for extra in extra_keys[0].getchildren()}) + c_item.update({extra.tag: etree.tostring(extra) + for extra in extra_keys[0].getchildren()}) items.append(c_item) # change relative link to full link, simplify, unescape HTML entities html_unescape = HTMLParser.HTMLParser().unescape @@ -1025,7 +1106,7 @@ class HtmlXsltManager(ImportManager): for k in item: val = item[k] for r, replaced in RE_CLEANS: - val = re.sub(r, replaced % {'base_url':base_url}, val) + val = re.sub(r, replaced % {'base_url': base_url}, val) item[k] = html_unescape(val) self.key_categories = self.importer_instance.get_key_category_dict() self.missing_cats = set() @@ -1034,9 +1115,10 @@ class HtmlXsltManager(ImportManager): self.add_dct_item(item) msg = '' if self.missing_cats: - msg = _(u"Names \"%s\" doesn't match existing categories. " - u"Modify the import to match theses names with categories.") % ( - u'", "'.join(self.missing_cats)) + msg = _( + u"Names \"%s\" doesn't match existing categories. " + u"Modify the import to match theses names with categories.") %\ + (u'", "'.join(self.missing_cats)) return (self.new_item, self.updated_item, msg) @classmethod @@ -1073,18 +1155,18 @@ class HtmlXsltManager(ImportManager): if not m: continue values = m.groupdict() - date = self._internal_parse_date(locale, - 'year1' in values and values['year1'], - values['month1'], values['day1']) + date = self._internal_parse_date( + locale, 'year1' in values and values['year1'], + values['month1'], values['day1']) if not date: continue dct['start_date'] = date has_dates = True if 'day2' not in values: break - date = self._internal_parse_date(locale, - 'year2' in values and values['year2'], - values['month2'], values['day2']) + date = self._internal_parse_date( + locale, 'year2' in values and values['year2'], + values['month2'], values['day2']) if date: dct['end_date'] = date break @@ -1092,13 +1174,14 @@ class HtmlXsltManager(ImportManager): def add_dct_item(self, item): if not self.importer_instance.default_localisation and \ - not "point" in item and not ("lat" in item and item['lat']): + "point" not in item and not ("lat" in item and item['lat']): return cls = None - dct = {'origin':"<a href='%s'>%s</a>" % (item['link'], - self.importer_instance.origin), - 'license':self.importer_instance.license, - 'name':item['name']} + dct = { + 'origin': "<a href='%s' target='_blank'>%s</a>" % ( + item.get('link') or '#', self.importer_instance.origin), + 'license': self.importer_instance.license, + 'name': item['name']} category = None if 'category' in item and item['category']: if item['category'] in self.key_categories: @@ -1114,7 +1197,7 @@ class HtmlXsltManager(ImportManager): item['lat']) else: dct['point'] = self.importer_instance.default_localisation - dct['description'] = item['description'] + dct['description'] = item.get('description', '') if 'date' in item: dct.update(self.parse_date(item['date'])) key = item['key'] @@ -1125,5 +1208,6 @@ class HtmlXsltManager(ImportManager): if created: self.new_item += 1 + class XMLXsltManager(HtmlXsltManager): PARSER = 'XMLParser' diff --git a/chimere/views.py b/chimere/views.py index be9d816..88619ce 100644 --- a/chimere/views.py +++ b/chimere/views.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2008-2014 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2008-2015 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # # RSS : Copyright (C) 2010 Pierre Clarenc <pierre.crc_AT_gmailDOTcom>, # Samuel Renard <renard.samuel_AT_gmailDOTcom>, @@ -24,15 +24,12 @@ Views of the project """ -import copy import datetime from itertools import groupby import re import simplejson as json from django.conf import settings -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.forms import AuthenticationForm from django.contrib.gis.geos import GEOSGeometry from django.contrib.gis.gdal.error import OGRException from django.contrib.gis.measure import D @@ -41,23 +38,24 @@ from django.core import serializers from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.db.models import Q -from django.http import HttpResponseRedirect, HttpResponse -from django.shortcuts import redirect, render_to_response +from django.http import HttpResponseRedirect, HttpResponse, Http404 +from django.shortcuts import get_object_or_404, redirect, render_to_response from django.template import loader, RequestContext, defaultfilters from django.utils import simplejson as json from django.utils.http import urlquote from django.utils.translation import ugettext as _ +from django.views.generic import TemplateView, ListView -from chimere.actions import actions as default_actions +from chimere.actions import actions from chimere.models import Category, SubCategory, PropertyModel, Page,\ - Marker, Route, News, SimpleArea, Map, Color, TinyUrl, RouteFile,\ + Marker, Route, News, SimpleArea, Area, Color, TinyUrl, RouteFile,\ AggregatedRoute -from chimere.widgets import getMapJS, PointChooserWidget, NominatimWidget,\ +from chimere.widgets import getMapJS, PointChooserWidget, \ RouteChooserWidget, AreaWidget from chimere.forms import MarkerForm, RouteForm, ContactForm, FileForm, \ FullFileForm, MultimediaFileFormSet, PictureFileFormSet, notifySubmission,\ - notifyStaff, MapForm, RoutingForm, getStaffEmails + notifyStaff, AreaForm, RoutingForm, getStaffEmails from chimere.route import router @@ -74,41 +72,43 @@ def get_base_uri(request): return base_uri #TODO: convert to requestcontext -def get_base_response(request, map_name="", propose=False): +def get_base_response(request, area_name=""): """ Get the base url """ - base_response_dct = {'media_path':settings.MEDIA_URL, - 'is_authenticated':request.user.is_authenticated()} + base_response_dct = {'media_path':settings.MEDIA_URL,} base_response_dct['MOBILE'] = settings.MOBILE_TEST or \ get_current_site(request).domain in settings.MOBILE_DOMAINS base_url = reverse("chimere:index") if not base_url.startswith('/'): base_url = '/' + base_url - if map_name and map_name.endswith('/'): - map_name = map_name[:-1] - if map_name: - base_response_dct['map_name_slash'] = map_name + "/" + if area_name and area_name.endswith('/'): + area_name = area_name[:-1] + if area_name: + base_response_dct['area_name_slash'] = area_name + "/" if base_url[-1] != '/': base_url += '/' - base_url += map_name + '/' + base_url += area_name + '/' base_response_dct['extra_url'] = base_url - map = Map.getAvailable(user=request.user, urn=map_name, propose=propose, - single=True) - if map: - map_name = map.urn - elif map_name: - return None, redirect(reverse('chimere:index')) - if map: - base_response_dct['can_write'] = map.can_write(user=request.user) - base_response_dct['can_propose'] = map.can_propose(user=request.user) - - base_response_dct['map'] = map - base_response_dct['map_name'] = map_name - if map and map.external_css: - base_response_dct['css_map'] = map.external_css + area = None + if area_name: + try: + area = Area.objects.get(urn=area_name, available=True) + except ObjectDoesNotExist: + return None, redirect(reverse('chimere:index')) + else: + try: + area = Area.objects.get(default=True) + area_name = area.urn + except ObjectDoesNotExist: + pass + + base_response_dct['area'] = area + base_response_dct['area_name'] = area_name + if area and area.external_css: + base_response_dct['css_area'] = area.external_css base_response_dct['dynamic_categories'] = True \ - if map and map.dynamic_categories else False + if area and area.dynamic_categories else False base_response_dct['JQUERY_JS_URLS'] = settings.JQUERY_JS_URLS base_response_dct['JQUERY_CSS_URLS'] = settings.JQUERY_CSS_URLS base_response_dct['PROJECT_NAME'] = settings.PROJECT_NAME @@ -116,17 +116,17 @@ def get_base_response(request, map_name="", propose=False): base_response_dct['EXTRA_CSS'] = settings.EXTRA_CSS return base_response_dct, None -def getShareUrl(request, map_name='', network=''): +def getShareUrl(request, area_name='', network=''): """ Get a share url """ - data = getTinyfiedUrl(request, request.GET.urlencode(), map_name) + data = getTinyfiedUrl(request, request.GET.urlencode(), area_name) for name, url, img in settings.CHIMERE_SHARE_NETWORKS: if defaultfilters.slugify(name) == network: return HttpResponse(url % {'text':data['text'], 'url':data['url']}) return HttpResponse('') -def getShareNetwork(request, map_name='', marker=None): +def getShareNetwork(request, area_name='', marker=None): """ Get URLs to share items """ @@ -135,19 +135,14 @@ def getShareNetwork(request, map_name='', marker=None): parameters = u'current_feature=%d' % marker.pk parameters += u"&checked_categories=%s" % "_".join([str(m.id) \ for m in marker.categories.all()]) - net_dct = getTinyfiedUrl(request, parameters, map_name) + net_dct = getTinyfiedUrl(request, parameters, area_name) share_networks = [] for network in settings.CHIMERE_SHARE_NETWORKS: share_networks.append((network[0], network[1] % net_dct, network[2])) return share_networks, net_dct - -def logout_view(request): - logout(request) - return redirect(reverse('chimere:index')) - -def index(request, map_name=None, default_map=None, simple=False, - get_response=False, actions=default_actions): +def index(request, area_name=None, default_area=None, simple=False, + get_response=False): """ Main page """ @@ -159,28 +154,9 @@ def index(request, map_name=None, default_map=None, simple=False, request.session['last_visit'] != today: request.session['last_visit'] = today news_visible = True - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir - - if request.POST: - auth_form = AuthenticationForm(None, request.POST) - invalid_msg = _(u"Invalid user or password.") - if auth_form.is_valid(): - user = authenticate( - username=auth_form.cleaned_data['username'], - password=auth_form.cleaned_data['password']) - if user is not None and user.is_active: - login(request, user) - return redirect(reverse('chimere:index')) - else: - response_dct['auth_form'] = auth_form - else: - response_dct['auth_form'] = AuthenticationForm() - - if not response_dct['map']: - return render_to_response('chimere/no_map.html', response_dct, - context_instance=RequestContext(request)) # don't mess with permalink zoomout = True if request.GET and 'lat' in request.GET \ @@ -198,24 +174,24 @@ def index(request, map_name=None, default_map=None, simple=False, except: pass response_dct.update({ - 'actions':actions(request.user, response_dct['map_name']), + 'actions':actions(response_dct['area_name']), 'action_selected':('view',), 'error_message':'', 'is_map':True, 'news_visible': news_visible, - 'maps_visible': settings.CHIMERE_DISPLAY_MAPS, + 'areas_visible': settings.CHIMERE_DISPLAY_AREAS, 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER, 'dynamic_categories':response_dct['dynamic_categories'], 'zoomout':zoomout, - 'has_default_map':Map.objects.filter(default=True).count(), - 'zoomout':zoomout, - 'has_search':settings.CHIMERE_SEARCH_ENGINE, + 'has_default_area':Area.objects.filter(default=True).count(), 'zoomout':zoomout, + 'has_search':hasattr(settings, 'CHIMERE_SEARCH_ENGINE') and \ + settings.CHIMERE_SEARCH_ENGINE }) if hasattr(settings, 'CONTACT_EMAIL') and settings.CONTACT_EMAIL: response_dct['contact_email'] = settings.CONTACT_EMAIL response_dct['share_networks'], net_dct = \ - getShareNetwork(request, response_dct['map_name']) + getShareNetwork(request, response_dct['area_name']) tpl = 'chimere/main_map.html' response_dct['simple'] = simple if simple: @@ -231,13 +207,13 @@ def get_edit_page(redirect_url, item_cls, item_form, """ Edition page """ - def func(request, map_name="", item_id=None, cat_type=['M']): - response_dct, redir = get_base_response(request, map_name, propose=True) + def func(request, area_name="", item_id=None, cat_type=['M']): + response_dct, redir = get_base_response(request, area_name) if redir: return redir, None, None - if 'map_name' in response_dct: - map_name = response_dct['map_name'] - subcategories = SubCategory.getAvailable(cat_type, map_name, + if 'area_name' in response_dct: + area_name = response_dct['area_name'] + subcategories = SubCategory.getAvailable(cat_type, area_name, public=True) listed_subcats = [] if subcategories: @@ -250,7 +226,7 @@ def get_edit_page(redirect_url, item_cls, item_form, try: init_item = item_cls.objects.get(pk=item_id) except: - return redirect(redirect_url, map_name + '/' if map_name \ + return redirect(redirect_url, area_name + '/' if area_name \ else ''), None, None ref_item = init_item modified_item = item_cls.objects.filter(ref_item=init_item, @@ -261,17 +237,18 @@ def get_edit_page(redirect_url, item_cls, item_form, init_multi = init_item.get_init_multi() if init_item else None init_picture = init_item.get_init_picture() if init_item else None - if init_item and not response_dct['can_write'] and \ + if init_item and not request.user.is_superuser and \ not init_item.submiter_session_key == \ request.session.session_key: # hide personal information for k in ('submiter_name', 'submiter_email', 'submiter_comment'): setattr(init_item, k, '') + response_dct['is_superuser'] = request.user.is_superuser # If the form has been submited if request.method == 'POST': inst = None - # allow to directly modify only if owner or has can_write permission - if init_item and (response_dct['can_write'] or \ + # allow to directly modify only if owner or superuser + if init_item and (request.user.is_superuser or \ init_item.submiter_session_key == \ request.session.session_key): inst = init_item @@ -284,7 +261,7 @@ def get_edit_page(redirect_url, item_cls, item_form, # All validation rules pass if form.is_valid() and formset_multi.is_valid() and \ formset_picture.is_valid(): - item = form.save(can_write=response_dct.get('can_write')) + item = form.save() # set the session key (to permit modifications) item.submiter_session_key = request.session.session_key @@ -302,7 +279,7 @@ def get_edit_page(redirect_url, item_cls, item_form, # just submited if not item.status: - item.status = 'A' if response_dct.get('can_write') else 'S' + item.status = 'S' item.save() marker = item @@ -318,9 +295,9 @@ def get_edit_page(redirect_url, item_cls, item_form, f.save(marker) base_uri = get_base_uri(request) notifySubmission(base_uri, item) - response_dct = get_base_response(request, map_name) + response_dct = get_base_response(request, area_name) return redirect(redirect_url + '-item', - map_name + '/' if map_name else '', + area_name + '/' if area_name else '', item.ref_item.pk, 'submited'), None, subcategories else: response_dct['error_message'] = _(u"There are missing field(s)" @@ -337,12 +314,11 @@ def get_edit_page(redirect_url, item_cls, item_form, get_edit_marker = get_edit_page('chimere:edit', Marker, MarkerForm) -def edit(request, map_name="", item_id=None, submited=False, - actions=default_actions): +def edit(request, area_name="", item_id=None, submited=False): """ Edition page """ - response, values, sub_categories = get_edit_marker(request, map_name, + response, values, sub_categories = get_edit_marker(request, area_name, item_id, ['M', 'B']) if response: return response @@ -356,24 +332,20 @@ def edit(request, map_name="", item_id=None, submited=False, point_value = init_item.point if init_item else None if request.POST and request.POST.get('point'): point_value = request.POST.get('point') - has_dated_items = settings.CHIMERE_DAYS_BEFORE_EVENT and [ - True for cat, subcats in sub_categories - if [True for subcat in subcats if subcat.dated]] response_dct.update({ - 'actions':actions(request.user, response_dct['map_name']), + 'actions':actions(response_dct['area_name']), 'action_selected':('contribute', 'edit'), 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER, 'form':form, 'formset_multi':formset_multi, 'formset_picture':formset_picture, - 'dated':has_dated_items, - 'extra_head':form.media + NominatimWidget().media, + 'dated':settings.CHIMERE_DAYS_BEFORE_EVENT, + 'extra_head':form.media, 'marker_id':item_id, 'sub_categories':sub_categories, 'point_widget':PointChooserWidget().render('point', point_value, - map_name=response_dct['map_name']), - 'nominatim_widget':NominatimWidget().render('point'), + area_name=response_dct['area_name']), 'properties':declared_fields, 'filtered_properties':filtered_properties, 'submited':submited @@ -384,8 +356,8 @@ def edit(request, map_name="", item_id=None, submited=False, return render_to_response('chimere/edit.html', response_dct, context_instance=RequestContext(request)) -def uploadFile(request, category_id='', map_name=''): - response_dct, redir = get_base_response(request, map_name) +def uploadFile(request, category_id='', area_name=''): + response_dct, redir = get_base_response(request, area_name) if redir: return redir Form = FileForm if not category_id else FullFileForm @@ -432,7 +404,7 @@ def uploadFile(request, category_id='', map_name=''): return render_to_response('chimere/upload_file.html', response_dct, context_instance=RequestContext(request)) -def processRouteFile(request, map_name='', file_id=None): +def processRouteFile(request, area_name='', file_id=None): if file_id: try: route_file = RouteFile.objects.get(pk=file_id) @@ -450,12 +422,11 @@ def processRouteFile(request, map_name='', file_id=None): get_edit_route = get_edit_page('chimere:editroute', Route, RouteForm) -def editRoute(request, map_name="", item_id=None, submited=False, - actions=default_actions): +def editRoute(request, area_name="", item_id=None, submited=False): """ Route edition page """ - response, values, sub_categories = get_edit_route(request, map_name, + response, values, sub_categories = get_edit_route(request, area_name, item_id, ['R', 'B']) if response: return response @@ -469,22 +440,19 @@ def editRoute(request, map_name="", item_id=None, submited=False, route_value = init_item.route if init_item else None if request.POST and request.POST.get('route'): route_value = request.POST.get('route') - has_dated_items = settings.CHIMERE_DAYS_BEFORE_EVENT and [ - True for cat, subcats in sub_categories - if [True for subcat in subcats if subcat.dated]] response_dct.update({ - 'actions':actions(request.user, response_dct['map_name']), + 'actions':actions(response_dct['area_name']), 'action_selected':('contribute', 'edit-route'), 'error_message':'', 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER, 'form':form, 'formset_multi':formset_multi, 'formset_picture':formset_picture, - 'dated':has_dated_items, + 'dated':settings.CHIMERE_DAYS_BEFORE_EVENT, 'extra_head':form.media, 'sub_categories':sub_categories, 'route_widget':RouteChooserWidget().render('route', route_value, - map_name=response_dct['map_name'], routefile_id='',), + area_name=response_dct['area_name'], routefile_id='',), 'properties':declared_fields, 'submited':submited }) @@ -494,33 +462,34 @@ def editRoute(request, map_name="", item_id=None, submited=False, return render_to_response('chimere/edit_route.html', response_dct, context_instance=RequestContext(request)) -def submited(request, map_name="", action="", actions=default_actions): +def submited(request, area_name="", action=""): """ Successful submission page """ - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir - response_dct.update({'actions':actions(request.user, response_dct['map_name']), - 'action_selected':action,}) + dct = {'actions':actions(response_dct['area_name']), + 'action_selected':action,} if hasattr(settings, 'CONTACT_EMAIL') and settings.CONTACT_EMAIL: response_dct['contact_email'] = settings.CONTACT_EMAIL + response_dct.update(dct) return render_to_response('chimere/submited.html', response_dct, context_instance=RequestContext(request)) -def charte(request, map_name="", actions=default_actions): +def charte(request, area_name=""): """ Affichage de la charte """ - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir - response_dct.update({'actions':actions(request.user, response_dct['map_name']), + response_dct.update({'actions':actions(response_dct['area_name']), 'action_selected':('charte',)}) return render_to_response('chimere/charte.html', response_dct, context_instance=RequestContext(request)) -def contactus(request, map_name="", actions=default_actions): +def contactus(request, area_name=""): """ Contact page """ @@ -541,16 +510,16 @@ def contactus(request, map_name="", actions=default_actions): msg = _(u"Temporary error. Renew your message later.") else: form = ContactForm() - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir - response_dct.update({'actions':actions(request.user, response_dct['map_name']), + response_dct.update({'actions':actions(response_dct['area_name']), 'action_selected':('contact',), 'contact_form':form, 'message':msg}) return render_to_response('chimere/contactus.html', response_dct, context_instance=RequestContext(request)) -def extraPage(request, map_name="", page_id="", actions=default_actions): +def extraPage(request, area_name="", page_id=""): """ Extra dynamic pages """ @@ -558,10 +527,10 @@ def extraPage(request, map_name="", page_id="", actions=default_actions): page = Page.objects.get(available=True, mnemonic=page_id) except ObjectDoesNotExist: return redirect(reverse('chimere:index')) - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir - response_dct.update({'actions':actions(request.user, response_dct['map_name']), + response_dct.update({'actions':actions(response_dct['area_name']), 'action_selected':(page_id,), 'content':page.content, 'title':page.title}) @@ -570,7 +539,7 @@ def extraPage(request, map_name="", page_id="", actions=default_actions): return render_to_response(tpl, response_dct, context_instance=RequestContext(request)) -def getDetail(request, map_name, marker_id): +def getDetail(request, area_name, marker_id): ''' Get the detail for a marker ''' @@ -579,7 +548,7 @@ def getDetail(request, map_name, marker_id): status__in=['A', 'S'])[0] except (ValueError, IndexError): return HttpResponse('no results') - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir response_dct['marker'] = marker @@ -587,7 +556,7 @@ def getDetail(request, map_name, marker_id): if 'simple' in request.GET and request.GET['simple']: response_dct['simple'] = True response_dct['share_networks'], net_dct = \ - getShareNetwork(request, response_dct['map_name'], marker) + getShareNetwork(request, response_dct['area_name'], marker) response_dct['share_url'] = net_dct['url'] net_dct['to'] = settings.CONTACT_EMAIL if net_dct['to']: @@ -602,7 +571,7 @@ def getDetail(request, map_name, marker_id): return render_to_response('chimere/detail.html', response_dct, context_instance=RequestContext(request)) -def getDescriptionDetail(request, map_name, category_id): +def getDescriptionDetail(request, area_name, category_id): ''' Get the description for a category ''' @@ -610,7 +579,7 @@ def getDescriptionDetail(request, map_name, category_id): category = Category.objects.filter(id=int(category_id))[0] except (ValueError, IndexError): return HttpResponse('no results') - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir response_dct['category'] = category @@ -632,82 +601,87 @@ def checkDate(q): ) return q -def getGeoObjects(request, map_name, category_ids, status): +def _getGeoObjects(area_name, category_ids, status='A', getjson=True, + item_types=('Marker', 'Route')): + ''' + Get markers and routes + ''' + items = [] + current_cat, colors, idx = None, None, 0 + empty = [] if not getjson else {} + + # marker + if 'Marker' in item_types: + try: + q = checkDate(Q(status__in=status, categories__in=category_ids)) + query = Marker.objects.filter(q).distinct('pk').order_by('-pk') + except: + return empty + + category_ids = [int(cat_id) for cat_id in category_ids] + if getjson: + for geo_object in list(query): + items += json.loads(geo_object.getGeoJSON(category_ids)) + else: + items += list(query) + + # routes + if 'Route' in item_types: + query = AggregatedRoute.objects.filter(status__in=status, + subcategory__in=category_ids).order_by('subcategory', '-pk') + if getjson: + for route in query.all(): + c_cat = route.subcategory + if not current_cat or current_cat != c_cat: + idx = 0 + current_cat = c_cat + colors = list(Color.objects.filter( + color_theme=c_cat.color_theme)) + if colors: + items.append(json.loads( + route.getGeoJSON(color=colors[idx % len(colors)].code))) + else: + items.append(json.loads(route.getGeoJSON(color='000'))) + idx += 1 + else: + items += list(query) + + if not items: + return empty + return items + +def getGeoObjects(request, area_name, category_ids, status): ''' Get the JSON for markers and routes ''' if not status: status = 'A' status = status.split('_') - category_ids = category_ids.split('_') - query = AggregatedRoute.objects.filter(status__in=status, - subcategory__in=category_ids).order_by('subcategory') - jsons = [] - current_cat, colors, idx = None, None, 0 - for route in query.all(): - c_cat = route.subcategory - if not current_cat or current_cat != c_cat: - idx = 0 - current_cat = c_cat - colors = list(Color.objects.filter(color_theme = c_cat.color_theme)) - color = '000' - if colors: - color = colors[idx % len(colors)].code - if '#' not in color: - color = '#' + color - base_dct = {"type":"Feature", - "properties":{ - "color":color - } - } - jsons.append(route._getItems(base_dct)) - idx += 1 - try: - q = checkDate(Q(status__in=status, categories__in=category_ids)) - query = Marker.objects.filter(q).distinct('pk').order_by('pk') - except: - return HttpResponse('no results') - category_ids = [int(cat_id) for cat_id in category_ids] - for category_id in category_ids: - if not category_id: - continue - cat = SubCategory.objects.get(pk=category_id) - base_dct = {"type":"Feature", - "properties":{ - "icon_path":unicode(cat.icon.image), - "icon_hover_path":cat.hover_icon.image \ - if cat.hover_icon else '', - "icon_width":cat.icon.image.width, - 'icon_height':cat.icon.image.height, - 'category_name':cat.name} - } - for values in query.filter(categories__pk=category_id).values( - 'point', 'pk', 'name', 'weight'): - jsons.append(Marker._getJson(values, copy.deepcopy(base_dct))) + category_ids = unicode(category_ids).split('_') + + jsons = _getGeoObjects(area_name, category_ids, status) if not jsons: return HttpResponse('no results') - data = {"type": "FeatureCollection", "features":jsons} - data = json.dumps(data) - + data = json.dumps({"type": "FeatureCollection", "features":jsons}) return HttpResponse(data, content_type="application/json") -def getMarker(request, map_name, pk): +def getMarker(request, area_name, pk): q = Marker.objects.filter(pk=pk, status='A') if not q.count(): return HttpResponse('{}') data = q.all()[0].getGeoJSON() return HttpResponse(data, content_type="application/json") -def get_all_categories(request, map_name=None): +def get_all_categories(request, area_name=None): ''' Get all available categories in JSON ''' - context_data, redir = get_base_response(request, map_name) - map = context_data["map"] + context_data, redir = get_base_response(request, area_name) + area = context_data["area"] subcategories = [] - if map: - subcategories = list(map.getCategories('A', - map_name=context_data['map_name'])) + if area: + subcategories = list(area.getCategories('A', + area_name=context_data['area_name'])) else: categories = SubCategory.getAvailable() for cat, subcats in categories: @@ -716,25 +690,25 @@ def get_all_categories(request, map_name=None): jsons = json.dumps({'categories':subcats}) return HttpResponse(jsons) -def get_available_categories(request, map_name=None, map=None, status='A', +def get_available_categories(request, area_name=None, area=None, status='A', force=None): ''' - Get category menu for a designed map + Get category menu for a designed area ''' - context_data, redir = get_base_response(request, map_name) - map = context_data["map"] + context_data, redir = get_base_response(request, area_name) + area = context_data["area"] if redir: return redir - if map and map.dynamic_categories and \ + if area and area.dynamic_categories and \ not "current_extent" in request.GET: context_data['sub_categories'] = [] return render_to_response('chimere/blocks/categories.html', context_data, context_instance=RequestContext(request)) - if not map or not map.dynamic_categories: + if not area or not area.dynamic_categories: # Categories are not updated dynamicaly when the user move the map # so we return ALL the categories subcategories = SubCategory.getAvailable( - map_name=context_data['map_name']) + area_name=context_data['area_name']) context_data['sub_categories'] = subcategories return render_to_response('chimere/blocks/categories.html', context_data, context_instance=RequestContext(request)) @@ -746,12 +720,12 @@ def get_available_categories(request, map_name=None, map=None, status='A', status = status.split('_') current_extent = request.GET["current_extent"].replace('M', '-')\ .replace('D', '.') - map = SimpleArea([float(pt) for pt in current_extent.split('_')]) + area = SimpleArea([float(pt) for pt in current_extent.split('_')]) except: # bad extent format return HttpResponse(default_message) - # if not force and map.isIn(SimpleArea(cookie.AREA):return - categories = map.getCategories(status, map_name=context_data['map_name']) + # if not force and area.isIn(SimpleArea(cookie.AREA):return + categories = area.getCategories(status, area_name=context_data['area_name']) if not categories: return HttpResponse(default_message) get_cat = lambda subcat: subcat.category @@ -764,7 +738,7 @@ def get_available_categories(request, map_name=None, map=None, status='A', return render_to_response('chimere/blocks/categories.html', context_data, context_instance=RequestContext(request)) -def getCategory(request, map_name='', category_id=0): +def getCategory(request, area_name='', category_id=0): ''' Get the JSON for a category (mainly in order to get the description) ''' @@ -774,7 +748,7 @@ def getCategory(request, map_name='', category_id=0): return HttpResponse('no results') return HttpResponse(category.getJSON()) -def getTinyfiedUrl(request, parameters, map_name=''): +def getTinyfiedUrl(request, parameters, area_name=''): ''' Get the tinyfied version of parameters ''' @@ -783,11 +757,11 @@ def getTinyfiedUrl(request, parameters, map_name=''): urn = TinyUrl.getUrnByParameters(parameters) except: return {} - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir - url = reverse('chimere:tiny', args=[(response_dct['map_name'] \ - if response_dct['map_name'] else '') + '/', urn]) + url = reverse('chimere:tiny', args=[(response_dct['area_name'] \ + if response_dct['area_name'] else '') + '/', urn]) if not url.startswith('http'): url = get_base_uri(request) + url url = re.sub("([^:])\/\/", "\g<1>/", url) @@ -804,17 +778,89 @@ def getTinyfiedUrl(request, parameters, map_name=''): data["text"] = urlquote(text) return data -def redirectFromTinyURN(request, map_name='', tiny_urn=''): +def redirectFromTinyURN(request, area_name='', tiny_urn=''): """ Redirect from a tiny Urn """ parameters = '?' + TinyUrl.getParametersByUrn(tiny_urn) - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir return HttpResponseRedirect(response_dct['extra_url'] + parameters) -def route(request, map_name, lon1, lat1, lonlat_steps, lon2, lat2, +class CategoryDirectoryView(ListView): + template_name = "chimere/category_directory.html" + + def get_queryset(self): + self.area_name = self.kwargs.get('area_name', None) + if self.area_name: + self.area_name = self.area_name.split('/')[0] + area = get_object_or_404(Area, urn=self.area_name, available=True) + q = area.subcategories.filter(available=True, + category__available=True + ).order_by('category__order', 'category__id', 'order') + if q.count(): + return q + return SubCategory.objects.filter(available=True, + category__available=True + ).order_by('category__order', 'category__id', 'order') + + def get_context_data(self, *args, **kwargs): + context = super(CategoryDirectoryView, self).get_context_data( + *args, **kwargs) + new_context, redirect = get_base_response(self.request, self.area_name) + context.update(new_context) + context.update({ + 'actions':actions(self.area_name), + 'action_selected':('categories',), + }) + return context + +class CategoryView(TemplateView): + template_name = "chimere/category_directory_detail.html" + + def get_geo_items(self): + # TODO: simplify on v2.3 when slug are available + category_slug = self.kwargs.get('category_slug') + self.area_name = self.kwargs.get('area_name', None) + q = None + if self.area_name: + self.area_name = self.area_name.split('/')[0] + area = get_object_or_404(Area, urn=self.area_name, available=True) + q = area.subcategories.filter(available=True, + category__available=True) + if not q.count(): + q = None + if not q: + q = SubCategory.objects.filter(available=True, + category__available=True) + self.category = None + for subcat in q: + if defaultfilters.slugify(subcat.name) == category_slug: + self.category = subcat + break + if not self.category: + raise Http404(_("Category does not exist")) + + items = _getGeoObjects(self.area_name, [unicode(self.category.pk)], + getjson=False, item_types=('Marker',)) + return items + + def get_context_data(self, *args, **kwargs): + context = super(CategoryView, self).get_context_data( + *args, **kwargs) + self.items = self.get_geo_items() + new_context, redirect = get_base_response(self.request, self.area_name) + context.update(new_context) + context.update({ + 'actions':actions(self.area_name), + 'action_selected':('categories',), + 'category':self.category, + 'items':self.items + }) + return context + +def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2, transport='foot', speed=''): ''' Get the JSON for a route @@ -893,18 +939,14 @@ def route(request, map_name, lon1, lat1, lonlat_steps, lon2, lat2, message) return HttpResponse(data) -def get_json(request, map_name='', app_name='', filename=''): - return HttpResponse(open(settings.STATIC_ROOT+app_name+'/json/'+filename+'.json'), - 'application/javascript', status=200) - -def rss(request, map_name='', actions=default_actions): +def rss(request, area_name=''): ''' Redirect to RSS subscription page ''' - response_dct, redir = get_base_response(request, map_name) + response_dct, redir = get_base_response(request, area_name) if redir: return redir - response_dct.update({'actions':actions(request.user, response_dct['map_name']), + response_dct.update({'actions':actions(response_dct['area_name']), 'action_selected':('rss',), 'category_rss_feed':'',}) # If the form has been submited @@ -926,14 +968,14 @@ def rss(request, map_name='', actions=default_actions): # User wants to follow all the new POI situated in a defined area elif request.POST['rss_category'] == 'area': # An unbound form - form = MapForm() + form = AreaForm() area_widget = AreaWidget().render('area', None) response_dct.update({ 'map_layer':settings.CHIMERE_DEFAULT_MAP_LAYER, 'extra_head':form.media, 'form':form, 'category_rss_feed':'area', - 'map_id':Map.getAvailable(), + 'area_id':Area.getAvailable(), 'area_widget':area_widget }) return render_to_response('chimere/feeds/rss.html', @@ -964,10 +1006,10 @@ def rss(request, map_name='', actions=default_actions): kwargs={'category_id':cat_id}) return redirect(feeds_link) - # User has specified the ID of the map he wants to follow - if 'id_map' in request.POST and request.POST['id_map'] != '': - feeds_link = reverse('chimere:feeds-mapid', - kwargs={'map_id':request.POST['id_map']}) + # User has specified the ID of the area he wants to follow + if 'id_area' in request.POST and request.POST['id_area'] != '': + feeds_link = reverse('chimere:feeds-areaid', + kwargs={'area_id':request.POST['id_area']}) return redirect(feeds_link) # User has specified the area he wants to follow => we redirect him @@ -1002,12 +1044,12 @@ def rss(request, map_name='', actions=default_actions): context_instance=RequestContext(request)) if request.GET['rss_category'] == 'area': # An unbound form - form = MapForm() + form = AreaForm() response_dct.update({'map_layer':settings.MAP_LAYER, 'extra_head':form.media, 'form':form, 'category_rss_feed':'area', - 'map_id':Map.getAvailable(), + 'area_id':Area.getAvailable(), 'area_widget':AreaWidget().render('area', None)}) return render_to_response('chimere/feeds/rss.html', response_dct, context_instance=RequestContext(request)) @@ -1026,7 +1068,11 @@ if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \ from haystack.views import SearchView as HaystackSearchView from haystack.query import SearchQuerySet class SearchView(HaystackSearchView): - pass + def extra_context(self, *args, **kwargs): + context = super(SearchView, self).extra_context(*args, **kwargs) + context["autocomplete"] = settings.HAYSTACK_AUTOCOMPLETE \ + if hasattr(settings, 'HAYSTACK_AUTOCOMPLETE') else False + return context def autocomplete(request): sqs = SearchQuerySet().autocomplete( content_auto=request.GET.get('q', ''))[:5] |