diff options
Diffstat (limited to 'chimere/models.py')
| -rw-r--r-- | chimere/models.py | 204 | 
1 files changed, 187 insertions, 17 deletions
| diff --git a/chimere/models.py b/chimere/models.py index 25bc708..545d7e0 100644 --- a/chimere/models.py +++ b/chimere/models.py @@ -25,6 +25,8 @@ import simplejson as json  from lxml import etree  from PIL import Image  from subprocess import Popen, PIPE +from BeautifulSoup import BeautifulSoup +  from django import forms  from django.conf import settings  from django.contrib import admin @@ -45,13 +47,64 @@ from chimere.managers import BaseGeoManager  from chimere.utils import KMLManager, OSMManager, ShapefileManager, \                            GeoRSSManager, CSVManager +class Page(models.Model): +    """Simple extra pages +    """ +    title = models.CharField(_(u"Name"), max_length=150) +    mnemonic = models.CharField(_(u"Mnemonic"), max_length=10, blank=True, +                                null=True) +    available = models.BooleanField(_(u"Available"), default=True) +    order = models.IntegerField(_(u"Order"), default=10, blank=True, null=True) +    template_path = models.CharField(_(u"Template path"), max_length=150, +                                     blank=True, null=True) +    content = models.TextField(blank=True, null=True) +    def __unicode__(self): +        ordering = ["order"] +        return self.title +    class Meta: +        verbose_name = _(u"Page") +        verbose_name_plural = _(u"Page") + +def page_post_save(sender, **kwargs): +    if not kwargs['instance']: +        return +    page = kwargs['instance'] +    if not page.mnemonic: +        page.mnemonic = defaultfilters.slugify(page.title) +        page.save() +post_save.connect(page_post_save, sender=Page) + +def shortify(text): +    if not text: +        return '' +    if len(text) <= settings.CHIMERE_SHORT_DESC_LENGTH: +        return text +    desc = text[:settings.CHIMERE_SHORT_DESC_LENGTH] +    short_desc = "" +    # find a correct opportunity to cut +    for idx, c in enumerate(reversed(desc)): +        if c == '>': +            break +        if c == '<': +            short_desc = desc[:-(idx+1)] +            break +    if not short_desc: +        for idx, c in enumerate(reversed(desc)): +            if c == ' ' or c == '\n': +                short_desc = desc[:-(idx+1)] +                break +    return BeautifulSoup(short_desc).prettify() +  class News(models.Model):      """News of the site      """      title = models.CharField(_(u"Name"), max_length=150)      available = models.BooleanField(_(u"Available")) +    is_front_page = models.NullBooleanField(_(u"Is front page"), blank=True, +                                            null=True)      date = models.DateField(_(u"Date"), auto_now_add=True)      content = models.TextField() +    url = models.URLField(_(u"Url"), max_length=200, blank=True, null=True)      areas = SelectMultipleField('Area', verbose_name=_(u"Associated areas"),                                  blank=True, null=True)      def __unicode__(self): @@ -61,6 +114,10 @@ class News(models.Model):          verbose_name = _(u"News")          verbose_name_plural = _(u"News") +    @property +    def short_desc(self): +        return shortify(self.content) +  class TinyUrl(models.Model):      """Tinyfied version of permalink parameters      """ @@ -156,14 +213,21 @@ class SubCategory(models.Model):      available = models.BooleanField(_(u"Available"), default=True)      submission = models.BooleanField(_(u"Available for submission"),                                       default=True) -    icon = models.ForeignKey(Icon, verbose_name=_(u"Icon")) -    color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme"), -                                    blank=True, null=True) -    order = models.IntegerField(_(u"Order"), default=1000)      TYPE = (('M', _(u'Marker')),              ('R', _(u'Route')),              ('B', _(u'Both')),)      item_type = models.CharField(_(u"Item type"), max_length=1, choices=TYPE) +    dated = models.BooleanField(_(u"Is dated"), default=False) +    description = models.TextField(blank=True, null=True) +    icon = models.ForeignKey(Icon, verbose_name=_(u"Icon")) +    hover_icon = models.ForeignKey(Icon, verbose_name=_(u"Hover icon"), +                          blank=True, null=True, related_name='subcat_hovered') +    color_theme = models.ForeignKey(ColorTheme, verbose_name=_(u"Color theme"), +                                    blank=True, null=True) +    as_layer = models.BooleanField(_(u"Displayed in the layer menu"), +                                   default=False) +    routing_warn = models.BooleanField(_(u"Routing warn"), default=False) +    order = models.IntegerField(_(u"Order"), default=1000)      def __unicode__(self):          return u"%s / %s" % (self.category.name, self.name)      class Meta: @@ -207,6 +271,32 @@ class SubCategory(models.Model):          subcategories = sorted(subcategories, key=get_cat_order)          return subcategories +    @classmethod +    def getAvailableTuples(cls, area_name=None): +        cats = [] +        for cat, subcats in cls.getAvailable(area_name=area_name): +            cats.append((unicode(cat), +                        [(subcat.pk, subcat.name) for subcat in subcats])) +        return cats + +    def getJSONDict(self): +        items = {'id':self.pk, 'name':self.name, +                 'description':self.description if self.description\ +                               else '', +                 'icon':{'url':self.icon.image.url, +                         'width':self.icon.image.width, +                         'height':self.icon.image.height} +                } +        if self.hover_icon: +            items['icon_hover'] = {'url':self.hover_icon.image.url} +        return items + +    def getJSON(self, categories_id=[]): +        '''Return a JSON string - mainly used to get description +        ''' +        json_string = json.dumps(self.getJSONDict()) +        return json_string +  IMPORTERS = {'KML':KMLManager,               'OSM':OSMManager,               'SHP':ShapefileManager, @@ -274,6 +364,13 @@ class Importer(models.Model):      def display_categories(self):          return u"\n".join([cat.name for cat in self.categories.all()]) +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) @@ -285,12 +382,6 @@ class GeographicItem(models.Model):                                         null=True)      submiter_comment = models.TextField(_(u"Submitter comment"), max_length=200,                                          blank=True, null=True) -    STATUS = (('S', _(u'Submited')), -              ('A', _(u'Available')), -              ('M', _(u'Modified')), -              ('D', _(u'Disabled')), -              ('I', _(u'Imported'))) -    STATUS_DCT = dict(STATUS)      status = models.CharField(_(u"Status"), max_length=1, choices=STATUS)      import_key = models.CharField(_(u"Import key"), max_length=200,                                    blank=True, null=True) @@ -349,6 +440,10 @@ class GeographicItem(models.Model):      def properties(cls):          return [pm for pm in PropertyModel.objects.filter(available=True)] +    @classmethod +    def all_properties(cls): +        return [pm for pm in PropertyModel.objects.all()] +  def property_setter(cls, propertymodel):      def setter(self, value):          marker = self @@ -371,6 +466,8 @@ class Marker(GeographicItem):      route = models.ForeignKey(u"Route", blank=True, null=True,                                related_name='associated_marker')      description = models.TextField(_(u"Description"), blank=True, null=True) +    is_front_page = models.NullBooleanField(_(u"Is front page"), blank=True, +                                            null=True)      objects = models.GeoManager()      def __unicode__(self): @@ -379,7 +476,7 @@ class Marker(GeographicItem):      def __init__(self, *args, **kwargs):          super(Marker, self).__init__(*args, **kwargs)          # add read attributes for properties -        for pm in self.properties(): +        for pm in self.all_properties():              attr_name = pm.getAttrName()              if not hasattr(self, attr_name):                  val = '' @@ -426,6 +523,10 @@ class Marker(GeographicItem):              return self.start_date      @property +    def short_desc(self): +        return shortify(self.description) + +    @property      def geometry(self):          return self.point.wkt @@ -481,6 +582,18 @@ class Marker(GeographicItem):          if len(properties) > 1:              for property in properties[1:]:                  property.delete() +        if pm.type == 'C' and value: +            try: +                value = str(int(value)) +            except ValueError: +                choice = PropertyModelChoice.objects.filter(propertymodel=pm, +                                                            value=value) +                if choice.count(): +                    value = choice.all()[0].pk +                else: +                    choice = PropertyModelChoice.objects.create(value=value, +                                                            propertymodel=pm) +                    value = choice.pk          # new property          if not properties:              new_property = Property.objects.create(marker=self, @@ -512,12 +625,18 @@ class Marker(GeographicItem):              items = {'id':self.id, 'name':json.dumps(self.name),                       'geometry':self.point.geojson,                       'icon_path':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,} +                     'icon_height':cat.icon.image.height, +                     'category_name':json.dumps(cat.name)}              jsons.append(u'{"type":"Feature", "geometry":%(geometry)s, '\                  u'"properties":{"pk": %(id)d, "name": %(name)s, '\ -                u'"icon_path":"%(icon_path)s", "icon_width":%(icon_width)d, '\ -                u'"icon_height":%(icon_height)d}}' % items) +                u'"icon_path":"%(icon_path)s", '\ +                u'"icon_hover_path":"%(icon_hover_path)s", '\ +                u'"icon_width":%(icon_width)d, '\ +                u'"icon_height":%(icon_height)d, '\ +                u'"category_name":%(category_name)s}}' % items)          return ",".join(jsons)      @property @@ -1067,6 +1186,28 @@ def getDateCondition():      date_condition += "%(alias)s.end_date >='" + now + "')) "      return date_condition +class AggregatedRoute(models.Model): +    ''' +    Database view for aggregated routes +    ''' +    route = models.MultiLineStringField() +    subcategory = models.ForeignKey(SubCategory) +    status = models.CharField(_(u"Status"), max_length=1, choices=STATUS) +    class Meta: +        managed = False +        db_table = 'chimere_aggregated_routes' + +    def getGeoJSON(self, color="#000"): +        '''Return a GeoJSON string +        ''' +        if '#' not in color: +            color = '#' + color +        attributes = {'id':self.id, 'name':json.dumps(u'Aggregated route'), +                      'color':color, 'geometry':self.route.geojson,} +        return u'{"type":"Feature", "geometry":%(geometry)s, '\ +               u'"properties":{"pk": %(id)d, "name": %(name)s, '\ +               u'"color":"%(color)s"}}' % attributes +  class SimplePoint:      """      Point in the map (not in the database) @@ -1357,11 +1498,15 @@ class PropertyModel(models.Model):      TYPE = (('T', _('Text')),              ('L', _('Long text')),              ('P', _('Password')), -            ('D', _("Date"))) +            ('D', _("Date")), +            ('C', _("Choices")), +            )      TYPE_WIDGET = {'T':forms.TextInput,                     'L':TextareaWidget,                     'P':forms.PasswordInput, -                   'D':DatePickerWidget} +                   'D':DatePickerWidget, +                   'C':forms.Select +                   }      type = models.CharField(_(u"Type"), max_length=1, choices=TYPE)      def __unicode__(self):          return self.name @@ -1379,6 +1524,19 @@ class PropertyModel(models.Model):          '''          return 'property_%d_%d' % (self.order, self.id) +class PropertyModelChoice(models.Model): +    '''Choices for property model +    ''' +    propertymodel = models.ForeignKey(PropertyModel, related_name='choices', +                                      verbose_name=_(u"Property model")) +    value = models.CharField(_(u"Value"), max_length=150) +    available = models.BooleanField(_(u"Available"), default=True) +    def __unicode__(self): +        return unicode(self.value) + +    class Meta: +        verbose_name = _(u"Model property choice") +  class Property(models.Model):      '''Property for a POI      ''' @@ -1387,7 +1545,14 @@ class Property(models.Model):                                        verbose_name=_(u"Property model"))      value = models.TextField(_(u"Value"))      def __unicode__(self): -        return "%s : %s" % (str(self.propertymodel), self.value) +        if self.propertymodel.type == 'C': +            try: +                return unicode(PropertyModelChoice.objects.get( +                                                    pk=self.value).value) +            except self.DoesNotExist: +                return "" +        return unicode(self.value) +      class Meta:          verbose_name = _(u"Property") @@ -1398,6 +1563,11 @@ class Property(models.Model):                  return datetime.date(*[int(val) for val in self.value.split('-')])              except:                  return "" +        if self.propertymodel.type == 'C' and self.value: +            try: +                return PropertyModelChoice.objects.get(pk=self.value) +            except self.DoesNotExist: +                return None          else:              return self.value | 
