diff options
| author | Étienne Loks <etienne.loks@proxience.com> | 2016-01-05 22:17:44 +0100 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@proxience.com> | 2016-01-05 22:17:44 +0100 | 
| commit | 9ce61bc6de5e98397e84c24a00d30002d4e04de5 (patch) | |
| tree | 8ab9d19530ca3026fb21aff1993982f487dc7a28 | |
| parent | 2ca084384e6bf0596822938a607a189b507f60ed (diff) | |
| parent | 89c4baf537a590dbe80c5f6a4c20f202c63ebb15 (diff) | |
| download | Chimère-9ce61bc6de5e98397e84c24a00d30002d4e04de5.tar.bz2 Chimère-9ce61bc6de5e98397e84c24a00d30002d4e04de5.zip  | |
Merge branch 'v2.2'
Conflicts:
	chimere/actions.py
	chimere/admin.py
	chimere/locale/fr/LC_MESSAGES/django.po
	chimere/models.py
	chimere/urls.py
	chimere/utils.py
	chimere/views.py
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]  | 
