Esempio n. 1
0
 def test_longitude_field(self):
     field = LongitudeField()
     name, path, args, kwargs = field.deconstruct()
     self.assertIsNone(name)
     self.assertEqual(path, 'osm_field.fields.LongitudeField')
     self.assertEqual(args, [])
     self.assertEqual(kwargs, {'validators': [validate_longitude]})
Esempio n. 2
0
 def test_longitude_field_with_validator(self):
     field = LongitudeField(validators=[foo_validator])
     name, path, args, kwargs = field.deconstruct()
     self.assertIsNone(name)
     self.assertEqual(path, 'osm_field.fields.LongitudeField')
     self.assertEqual(args, [])
     self.assertEqual(kwargs, {'validators': [foo_validator, validate_longitude]})
Esempio n. 3
0
 def test_longitude_field_with_validator(self):
     field = LongitudeField(validators=[foo_validator])
     name, path, args, kwargs = field.deconstruct()
     self.assertIsNone(name)
     self.assertEqual(path, "osm_field.fields.LongitudeField")
     self.assertEqual(args, [])
     self.assertEqual(kwargs, {"validators": [foo_validator, validate_longitude]})
Esempio n. 4
0
class MultipleNamingModel(models.Model):
    default_location = OSMField()
    default_location_lat = LatitudeField()
    default_location_lon = LongitudeField()

    custom_location = OSMField(lat_field='custom_latitude',
                               lon_field='custom_longitude')
    custom_latitude = LatitudeField()
    custom_longitude = LongitudeField()
Esempio n. 5
0
class ExampleModel(models.Model):
    location = OSMField()
    location_lat = LatitudeField()
    location_lon = LongitudeField()
    another = OSMField(lat_field='some_lat_field', lon_field='other_lon_field')
    some_lat_field = LatitudeField()
    other_lon_field = LongitudeField()

    def __str__(self):
        return str(self.get_location_info())

    def get_absolute_url(self):
        return reverse('detail', kwargs={'pk': self.pk})
Esempio n. 6
0
class ChildModel(models.Model):
    parent = models.ForeignKey(ParentModel,
                               related_name="children",
                               on_delete=models.CASCADE)
    location = OSMField()
    location_lat = LatitudeField()
    location_lon = LongitudeField()
Esempio n. 7
0
class LocationWithDataModel(models.Model):
    location = OSMField(lat_field='latitude',
                        lon_field='longitude',
                        data_field='location_data')
    latitude = LatitudeField()
    longitude = LongitudeField()
    location_data = models.TextField()
Esempio n. 8
0
class MyOsm(models.Model):
    location = OSMField()
    email = models.EmailField(blank=True)
    phone = models.IntegerField(null=True, blank=True)
    location_lat = LatitudeField()
    location_lon = LongitudeField()

    def __str__(self):
        return self.location
Esempio n. 9
0
class Location(models.Model):
    # location=models.CharField(max_length=255)
    # location_lat = models.CharField(max_length=22)
    # location_lon =  models.CharField(max_length=22)
    location = OSMField()
    location_lat = LatitudeField()
    location_lon = LongitudeField()

    def __str__(self):
        return self.location
Esempio n. 10
0
class Listing(models.Model):
  user = models.ForeignKey(User,on_delete=models.DO_NOTHING,default=2)
  realtor = models.ForeignKey(Realtor, on_delete=models.DO_NOTHING)
  title = models.CharField(max_length=200)
  address = models.CharField(max_length=200)
  city = models.CharField(max_length=100)
  state = models.CharField(max_length=100)
  zipcode = models.CharField(max_length=20)
  description = models.TextField(blank=True)
  price = models.IntegerField()
  bedrooms = models.IntegerField()
  bathrooms = models.DecimalField(max_digits=2, decimal_places=1)
  garage = models.IntegerField()
  sqft = models.IntegerField()
  sqft_living = models.IntegerField()
  lot_size = models.DecimalField(max_digits=5, decimal_places=1)
  floors = models.IntegerField()
  waterfront = models.IntegerField(choices=Waterfront_Choices)
  view = models.IntegerField(choices=View_Choices)
  condition = models.IntegerField(choices=Condition_Choices)
  grade = models.IntegerField(choices=Grade_Choices)
  sqft_above = models.IntegerField()
  sqft_basement = models.IntegerField()
  yr_built = models.IntegerField()
  yr_renovated = models.IntegerField()
  sqft_living15 = models.IntegerField()
  sqft_lot15 = models.IntegerField()
  photo_main = models.ImageField(upload_to='photos/%Y/%m/%d/')
  photo_1 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
  photo_2 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
  photo_3 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
  photo_4 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
  photo_5 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
  photo_6 = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
  is_published = models.BooleanField(default=True)
  is_verified = models.BooleanField(default=False)
  list_date = models.DateTimeField(default=datetime.now, blank=True)
  likes = models.ManyToManyField(User,related_name='adz_posts')
  location = OSMField()
  location_lat = LatitudeField()
  location_lon = LongitudeField()

  def total_likes(self):
      return self.likes.count()

  def __str__(self):
    return self.title
Esempio n. 11
0
class CosinnusOrganizationLocation(models.Model):
    location = OSMField(_('Location'), blank=True, null=True)
    location_lat = LatitudeField(_('Latitude'), blank=True, null=True)
    location_lon = LongitudeField(_('Longitude'), blank=True, null=True)

    organization = models.ForeignKey(
        CosinnusOrganization,
        verbose_name=_('Organization'),
        on_delete=models.CASCADE,
        related_name='locations',
    )

    class Meta(object):
        verbose_name = _('CosinnusOrganizationLocation')
        verbose_name_plural = _('CosinnusOrganizationLocations')

    @property
    def location_url(self):
        if not self.location_lat or not self.location_lon:
            return None
        return 'http://www.openstreetmap.org/?mlat=%s&mlon=%s&zoom=15&layers=M' % (
            self.location_lat, self.location_lon)
class Event(models.Model):
    start_time = models.DateTimeField(db_index=True,
                                      verbose_name="Start wydarzenia")
    end_time = models.DateTimeField(db_index=True,
                                    verbose_name="Koniec wydarzenia")
    title = models.CharField(max_length=120, verbose_name="Tytuł")
    description = RichTextField(verbose_name="Opis wydarzenia")
    image = models.ImageField(upload_to='event/%Y/%m/%d/',
                              blank=True,
                              null=True,
                              verbose_name="Plakat")
    place = models.CharField(max_length=120, verbose_name="Miejsce")
    #point = models.PointField(blank=True, null=True, verbose_name="Miejsce na mapie")
    orgs = models.ManyToManyField('Organizer',
                                  blank=True,
                                  related_name='events',
                                  verbose_name="Organizator")
    user = models.ForeignKey(User,
                             blank=True,
                             null=True,
                             related_name='event',
                             verbose_name='Użytkownik',
                             on_delete=models.SET_NULL)
    categories = models.ManyToManyField('Category',
                                        blank=True,
                                        verbose_name="Kategoria")
    url = models.URLField(blank=True, null=True, verbose_name="Adres www")

    location = OSMField(default='Oświęcim',
                        verbose_name="Położenie na mapie",
                        lat_field='latitude',
                        lon_field='longitude')
    latitude = LatitudeField(default=50.038,
                             verbose_name="Długość geograficzna")
    longitude = LongitudeField(default=19.221,
                               verbose_name="Szerokość geograficzna")

    def __str__(self):
        return self.title
Esempio n. 13
0
 class Model(models.Model):
     location = OSMField(lat_field="latitude", lon_field="longitude")
     latitude = LatitudeField()
     longitude = LongitudeField()
Esempio n. 14
0
 class Model(models.Model):
     location = OSMField()
     location_lat = LatitudeField()
     location_lon = LongitudeField()
Esempio n. 15
0
class OpenStreetMaps(models.Model):
    location = OSMField(lat_field='latitude', lon_field='longitude')
    latitude = LatitudeField()
    longitude = LongitudeField()
Esempio n. 16
0
class ChildModel(models.Model):
    parent = models.ForeignKey(ParentModel, related_name='children')
    location = OSMField()
    location_lat = LatitudeField()
    location_lon = LongitudeField()
Esempio n. 17
0
class CustomNamingModel(models.Model):
    location = OSMField(lat_field='latitude', lon_field='longitude')
    latitude = LatitudeField()
    longitude = LongitudeField()
Esempio n. 18
0
class Event(models.Model):
    name = models.CharField(max_length=300)
    organizer = models.ForeignKey(User, on_delete=models.CASCADE)
    events_or_task = models.BooleanField(default=True)
    events_type = models.ForeignKey(EventsType, on_delete=models.CASCADE)
    date_event = models.DateField (null=True, blank=True, verbose_name='Дата')
    time_event = models.TimeField(null=True, blank=True, verbose_name='Час')
    city = models.ForeignKey(City, on_delete=models.CASCADE, null=True, blank=True)
    address = models.CharField(max_length=300, null=True, blank=True)
    status = models.ForeignKey(Status, on_delete=models.CASCADE, verbose_name='Статус', default=Status.DEFAULT_STATUS) # null=True, blank=True
    max_part = models.IntegerField(null=True, blank=True)
    min_part = models.IntegerField(null=True, blank=True)
    recommended_points = models.IntegerField()
    contact = models.EmailField(null=True, blank=True)
    publication_date = models.DateField(auto_now_add=True)
    description = models.TextField(null=True, blank=True)
    geom = PointField(null=True, blank=True)
    calendar_event = models.ForeignKey(CalendarEvent, on_delete=models.SET_NULL, null=True, blank=True)
    location = OSMField(lat_field='latitude', lon_field='longitude',null=True, blank=True)
    latitude = LatitudeField(null=True, blank=True)
    longitude = LongitudeField(null=True, blank=True)
    fb_page = models.URLField(null=True, blank=True)


    @property
    def get_events_type_url(self):
        return self.events_type.image.url

    @property
    def get_events_type_marker_url(self):
        return self.events_type.marker_image.url

    @property
    def get_event_url(self):
        return reverse('volunteer_event', args=(self.id,))


    def save(self, *args, **kwargs):
        # if self.city:
        #     if self.city.city == "Вінницька":
        #         view_box = [(49.3921, 28.3079), (49.072, 28.6219)]
        #     elif self.city.city == "Житомирська":
        #         view_box = [(52.276012, 25.605223), (50.23924, 28.715773)]
        # else:  # khmel
        #     view_box = [(49.4770, 26.9048), (49.3631, 27.0995)]
        # nom = Nominatim(user_agent="changer.in.ua", view_box=view_box, bounded=True)

        if self.longitude and self.latitude:
            self.geom = {'coordinates': [self.longitude, self.latitude], 'type': 'Point'}


        # if self.address:
        #     point = nom.geocode(self.address)
        #     if point:
        #         self.geom = {'coordinates':[point.longitude, point.latitude], 'type':'Point'}
        #     else:
        #         print('coordinates for address not found')
        # elif self.location:
        #     point = nom.geocode(self.location)
        #     if point:
        #         self.geom = {'coordinates':[point.longitude, point.latitude], 'type':'Point'}
        #     else:
        #         print('coordinates for address not found')
        # elif self.longitude and self.latitude:
        #     self.geom = {'coordinates': [self.longitude, self.latitude], 'type': 'Point'}
        # else:
        #     print('coordinates for address not found')

        # calendar part
        if self.calendar_event:
            self.calendar_event.delete()

        if self.date_event:
            calendar_name = 'volunteer_calendar'
            calendar_slug = 'volunteer_calendar_slug'
            if Calendar.objects.filter(name=calendar_name, slug='volunteer_calendar_slug').exists():
                calendar = Calendar.objects.filter(name=calendar_name, slug='volunteer_calendar_slug')[0]
            else:
                calendar = Calendar.objects.create(name=calendar_name, slug=calendar_slug)

            if self.time_event:
                start = datetime.datetime.combine(self.date_event, self.time_event)
            else:
                start = self.date_event
            data = {
                'title': self.name,
                'start': start ,
                'end': datetime.datetime(self.date_event.year, self.date_event.month, self.date_event.day, 23,
                                         59),
                # 'end_recurring_period': datetime.datetime(today.year + 30, 6, 1, 0, 0),
                # 'rule': rule,
                'calendar': calendar,
                'color_event': self.events_type.color_event,
            }

            new_calendar_event = CalendarEvent.objects.create(**data)
            self.calendar_event = new_calendar_event
        # end calendar_part


        is_new_event = False
        if self.pk is None:
            is_new_event = True
        else:
            old_instance = Event.objects.get(pk = self.pk)
            old_status = old_instance.status.id
            old_type = old_instance.events_type.id
            currency = Currency.objects.get(type_event__id=old_type)


        super(Event, self).save(*args, **kwargs)


        if not is_new_event and self.status.id == 3 and old_status!=self.status.id:
            part = list(EventsParticipant.objects.filter(event = Event.objects.get(pk = self.pk)).values_list('user__id', flat = True))
            part_user = User.objects.filter(id__in = part)

            if self.events_or_task == True:
                for user in part_user:
                    points_list = PointsList.objects.create(user = user, currency = currency, points_quantity = self.recommended_points)
                    IncreasePointsInfo.objects.create(increase = points_list, increase_type_id = 1,  event_id = self.id)
                    user_points = UserPoint.objects.get(user = user, currency = currency)
                    user_points.quantity +=  self.recommended_points
                    user_points.save()

                    notify_good_job(sender=self.organizer.django_user_id,
                                    recipient=user.django_user_id,
                                    event_instance=self,
                                    currency_quantity=self.recommended_points,
                                    currency_type=currency.currency)
            else:
                user = TaskApplication.objects.get(event__id = self.id, executor = True).user
                points_list = PointsList.objects.create(user=user, currency=currency, points_quantity=self.recommended_points)
                IncreasePointsInfo.objects.create(increase=points_list, increase_type_id=1, event_id=self.id)
                user_points = UserPoint.objects.get(user=user, currency=currency)
                user_points.quantity += self.recommended_points
                user_points.save()

                notify_good_job(sender=self.organizer.django_user_id,
                                recipient=user.django_user_id,
                                event_instance=self,
                                currency_quantity=self.recommended_points,
                                currency_type=currency.currency)


            if len(part_user)>=3 and self.events_or_task == True:
                organizer_points = 30
                points_list = PointsList.objects.create(user = self.organizer, currency = currency, points_quantity = self.recommended_points)
                IncreasePointsInfo.objects.create(increase=points_list, increase_type_id=2, event_id=self.id)
                user_points = UserPoint.objects.get(user=self.organizer, currency=currency)
                user_points.quantity += organizer_points
                user_points.save()

                notify_good_job(sender=self.organizer.django_user_id,
                                recipient=self.organizer.django_user_id,
                                event_instance=self,
                                currency_quantity=organizer_points,
                                currency_type=currency.currency)

            elif self.events_or_task == False:
                organizer_points = 30
                points_list = PointsList.objects.create(user=self.organizer, currency=currency,points_quantity=self.recommended_points)
                IncreasePointsInfo.objects.create(increase=points_list, increase_type_id=2, event_id=self.id)
                user_points = UserPoint.objects.get(user=self.organizer, currency=currency)
                user_points.quantity += organizer_points
                user_points.save()

                notify_good_job(sender=self.organizer.django_user_id,
                                recipient=self.organizer.django_user_id,
                                event_instance=self,
                                currency_quantity=organizer_points,
                                currency_type=currency.currency)

            print('It is victory!')


        if is_new_event and self.status.id == 1: # потребує допомоги в підготовці
            notify_event_needs_help(self)


    def __str__(self):
        return '%s %s %s' % (self.name, '|', self.date_event)

    def as_dict(self):
        return model_to_dict(self)
Esempio n. 19
0
class EcobasaCommunityProfile(models.Model):
    group = models.OneToOneField(CosinnusGroup,
                                 editable=False,
                                 related_name='profile')
    # mandatory name!
    network = models.BooleanField(_('Is this a regional network?'),
                                  default=False,
                                  blank=True)
    COMMUNITY_STATUS_STARTING = 's'
    COMMUNITY_STATUS_ESTABLISHED = 'e'
    COMMUNITY_STATUS_LAND = 'l'
    COMMUNITY_STATUS_CHOICES = (
        (COMMUNITY_STATUS_STARTING, _('Starting Project (first years)')),
        (COMMUNITY_STATUS_ESTABLISHED, _('Established (+4 years)')),
        (COMMUNITY_STATUS_LAND, _('Land Offer')),
    )
    community_status = models.CharField(_('Project status'),
                                        max_length=2,
                                        blank=True,
                                        choices=COMMUNITY_STATUS_CHOICES,
                                        default=COMMUNITY_STATUS_ESTABLISHED)

    COMMUNITY_TYPE_ECOVILLAGE = 'e'
    COMMUNITY_TYPE_COMUNE = 'c'
    COMMUNITY_TYPE_HOUSEPROJECT = 'h'
    COMMUNITY_TYPE_FARM = 'f'
    COMMUNITY_TYPE_CHOICES = (
        (COMMUNITY_TYPE_ECOVILLAGE, _('Ecovillage')),
        (COMMUNITY_TYPE_COMUNE, _('Commune')),
        (COMMUNITY_TYPE_HOUSEPROJECT, _('Houseproject')),
        (COMMUNITY_TYPE_FARM, _('Permaculture Farm')),
    )
    community_type = models.CharField(_('Type of community'),
                                      max_length=2,
                                      blank=True,
                                      choices=COMMUNITY_TYPE_CHOICES,
                                      default=COMMUNITY_TYPE_ECOVILLAGE)
    name = models.CharField(_('name of community'), max_length=255)
    website = models.URLField(_('link of your communities website'),
                              max_length=250,
                              blank=True,
                              null=True)
    image = ThumbnailerImageField(
        verbose_name=_('image'),
        help_text=
        _('Header image for the community-profile, minimum resolution 1200x400'
          ),
        upload_to='community_images',
        max_length=255,
        blank=True,
        null=True)
    video = models.URLField(
        verbose_name=_('Video'),
        help_text=_('Link to a video showing your community'),
        max_length=255,
        blank=True,
        null=True)

    # contact info
    contact_telephone = models.CharField(_('telephone'),
                                         max_length=255,
                                         blank=True,
                                         null=True)
    contact_street = models.CharField(_('street'),
                                      max_length=255,
                                      blank=True,
                                      null=True)
    contact_location = OSMField(_('Location'), blank=True, null=True)
    contact_location_lat = LatitudeField(blank=True, null=True)
    contact_location_lon = LongitudeField(blank=True, null=True)
    contact_city = models.CharField(_('city'),
                                    max_length=255,
                                    blank=True,
                                    null=True)
    contact_zipcode = models.CharField(_('zipcode'),
                                       max_length=255,
                                       blank=True,
                                       null=True)
    contact_country = models.CharField(_('country'),
                                       max_length=2,
                                       blank=True,
                                       choices=COUNTRY_CHOICES,
                                       default='ZZ')
    contact_show = models.BooleanField(_('show address in profile'),
                                       default=False,
                                       blank=True)

    # visitors
    visitors_num = models.PositiveIntegerField(
        _('maximum number of people you can host'),
        blank=True,
        null=True,
        default=0)
    visitors_accommodation = models.TextField(
        _('accommodation for guests'),
        blank=True,
        null=True,
        help_text=
        _('Where can your visitors sleep? Do you have space for a bus, tents? How is the indoor sleeping situation? Do you have matresses, a couch? Do you have a donations or a pricing model? Required daily working amount or epxeriences?'
          ))

    # wishlist
    wishlist_projects = models.TextField(_(
        'Do you have any construction projects? List and describe them together with needed materials, tools, experts, time and knowledge.'
    ),
                                         blank=True,
                                         null=True)
    wishlist_materials = TaggableManager(
        _('What materials do you need?'),
        through=TaggedWishMaterial,
        related_name='_wishlist_material',
        blank=True,
        help_text=
        _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.'
          ))
    wishlist_materials_info = models.TextField(_(
        'Do you have any additional info about materials, or details to your request (like condition, when you need them)?'
    ),
                                               blank=True,
                                               null=True)
    wishlist_tools = TaggableManager(
        _('What tools or machines do you need?'),
        through=TaggedWishTool,
        related_name='_wishlist_tool',
        blank=True,
        help_text=
        _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.'
          ))
    wishlist_tools_info = models.TextField(_(
        'Do you have any additional info about tools, or details to your request (like condition, when you need them)?'
    ),
                                           blank=True,
                                           null=True)
    wishlist_skills = TaggableManager(
        _('Are you looking for some experts that could help you with a project or problem? Tag their desired skills here:'
          ),
        through=TaggedWishSkill,
        related_name='_wishlist_skill',
        blank=True,
        help_text=
        _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.'
          ))
    wishlist_special_needs = models.TextField(
        _('Special needs (knowledge, information)'), blank=True, null=True)

    # offers
    offers_services = TaggableManager(
        _('Services offered in your community'),
        through=TaggedOffersService,
        related_name='_offers_service',
        blank=True,
        help_text=
        _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.'
          ))
    offers_skills = TaggableManager(
        _('Skills people can learn in your community'),
        through=TaggedOffersSkill,
        related_name='_offers_skill',
        blank=True)
    offers_creations = TaggableManager(
        _('Creations/Products'),
        through=TaggedOffersCreation,
        related_name='_offers_creation',
        blank=True,
        help_text=
        _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.'
          ))
    offers_materials = TaggableManager(
        _('Do you have any materials that you produce or that you dont need anymore? (What you throw away, might be useful to somebody else..)'
          ),
        through=TaggedOffersMaterial,
        related_name='_offers_material',
        blank=True,
        help_text=
        _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.'
          ))
    offers_tools = TaggableManager(
        _('Do you have any tools that you produce or that you dont need anymore?'
          ),
        through=TaggedOffersTool,
        related_name='_offers_tool',
        blank=True,
        help_text=
        _('A comma-separated list of tags. You can type anything here. You can also chose from other users tags. Connect two words with a "-" to have one tag.'
          ))
    offers_workshop_spaces = models.TextField(_(
        'Do you have workshop spaces, where people can build/construct/manufacture things?'
    ),
                                              blank=True,
                                              null=True)
    offers_learning_seminars = models.TextField(
        _('Do you offer any seminars that visitors could attend?'),
        blank=True,
        null=True)

    # basic info
    basic_description = models.TextField(_('Describe your community'),
                                         blank=True,
                                         null=True)
    basic_inhabitants = models.CharField(
        _('how many people live in your community?'),
        max_length=255,
        null=True,
        blank=True)
    basic_inhabitants_underage = models.PositiveIntegerField(
        _('how many of them are under 18?'), null=True, blank=True, default=0)
    basic_brings_together = models.TextField(
        _('what brings your community together'), blank=True, null=True)
    MEMBERSHIP_OPEN = 'o'
    MEMBERSHIP_LOOKING = 'l'
    MEMBERSHIP_CLOSED = 'c'
    MEMBERSHIP_CHOICES = (
        (MEMBERSHIP_OPEN, _('looking for members')),
        (MEMBERSHIP_LOOKING, _('looking for volunteers')),
        (MEMBERSHIP_CLOSED, _('closed for the moment')),
    )
    basic_membership_status = models.CharField(_('member status'),
                                               max_length=2,
                                               blank=True,
                                               choices=MEMBERSHIP_CHOICES,
                                               default=MEMBERSHIP_OPEN)

    class Meta:
        app_label = 'ecobasa'

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        # copy profile name to cosinnus group name
        self.group.name = self.name
        # ensure the CosinnusGroup is always public!
        self.group.public = True
        self.group.save()
        return super(EcobasaCommunityProfile, self).save(*args, **kwargs)
Esempio n. 20
0
class DefaultNamingModel(models.Model):
    location = OSMField()
    location_lat = LatitudeField()
    location_lon = LongitudeField()
Esempio n. 21
0
class MixedNamingModel(models.Model):
    location = OSMField(lon_field='longitude')
    location_lat = LatitudeField()
    longitude = LongitudeField()
Esempio n. 22
0
class OpenStreetMaps(models.Model):
    location = OSMField()
    location_lat = LatitudeField()
    location_lon = LongitudeField()
Esempio n. 23
0
class Event(BaseTaggableObjectModel):

    SORT_FIELDS_ALIASES = [
        ('title', 'title'),
        ('from_date', 'from_date'),
        ('to_date', 'to_date'),
        ('city', 'city'),
        ('state', 'state'),
    ]

    STATE_SCHEDULED = 1
    STATE_VOTING_OPEN = 2
    STATE_CANCELED = 3
    STATE_ARCHIVED_DOODLE = 4

    STATE_CHOICES = (
        (STATE_SCHEDULED, _('Scheduled')),
        (STATE_VOTING_OPEN, _('Voting open')),
        (STATE_CANCELED, _('Canceled')),
        (STATE_ARCHIVED_DOODLE, _('Archived Event Poll')),
    )

    from_date = models.DateTimeField(_('Start'),
                                     default=None,
                                     blank=True,
                                     null=True,
                                     editable=True)

    to_date = models.DateTimeField(_('End'),
                                   default=None,
                                   blank=True,
                                   null=True,
                                   editable=True)

    state = models.PositiveIntegerField(
        _('State'),
        choices=STATE_CHOICES,
        default=STATE_VOTING_OPEN,
    )
    __state = None  # pre-save purpose

    note = models.TextField(_('Note'), blank=True, null=True)

    suggestion = models.ForeignKey(
        'Suggestion',
        verbose_name=_('Event date'),
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='selected_name',
    )

    location = OSMField(_('Location'), blank=True, null=True)
    location_lat = LatitudeField(_('Latitude'), blank=True, null=True)
    location_lon = LongitudeField(_('Longitude'), blank=True, null=True)

    street = models.CharField(_('Street'),
                              blank=True,
                              max_length=50,
                              null=True)

    zipcode = models.PositiveIntegerField(_('ZIP code'), blank=True, null=True)

    city = models.CharField(_('City'), blank=True, max_length=50, null=True)

    public = models.BooleanField(_('Is public (on website)'), default=False)

    image = models.ImageField(_('Image'),
                              upload_to=get_event_image_filename,
                              blank=True,
                              null=True)

    url = models.URLField(_('URL'), blank=True, null=True)

    original_doodle = models.OneToOneField(
        "self",
        verbose_name=_('Original Event Poll'),
        related_name='scheduled_event',
        null=True,
        blank=True,
        on_delete=models.SET_NULL)

    objects = EventManager()

    class Meta(BaseTaggableObjectModel.Meta):
        ordering = ['from_date', 'to_date']
        verbose_name = _('Event')
        verbose_name_plural = _('Events')

    def __init__(self, *args, **kwargs):
        super(Event, self).__init__(*args, **kwargs)
        self.__state = self.state

    def __str__(self):
        if self.state == Event.STATE_SCHEDULED:
            if self.single_day:
                readable = _('%(event)s (%(date)s - %(end)s)') % {
                    'event': self.title,
                    'date': localize(self.from_date, 'd. F Y h:i'),
                    'end': localize(self.to_date, 'h:i'),
                }
            else:
                readable = _('%(event)s (%(from)s - %(to)s)') % {
                    'event': self.title,
                    'from': localize(self.from_date, 'd. F Y h:i'),
                    'to': localize(self.to_date, 'd. F Y h:i'),
                }
        elif self.state == Event.STATE_CANCELED:
            readable = _('%(event)s (canceled)') % {'event': self.title}
        elif self.state == Event.STATE_VOTING_OPEN:
            readable = _('%(event)s (pending)') % {'event': self.title}
        else:
            readable = _('%(event)s (archived)') % {'event': self.title}

        return readable

    def save(self, created_from_doodle=False, *args, **kwargs):
        created = bool(self.pk) == False
        super(Event, self).save(*args, **kwargs)

        if created and not created_from_doodle:
            # event/doodle was created
            if self.state == Event.STATE_SCHEDULED:
                cosinnus_notifications.event_created.send(
                    sender=self,
                    user=self.creator,
                    obj=self,
                    audience=get_user_model().objects.filter(
                        id__in=self.group.members).exclude(id=self.creator.pk))
            else:
                cosinnus_notifications.doodle_created.send(
                    sender=self,
                    user=self.creator,
                    obj=self,
                    audience=get_user_model().objects.filter(
                        id__in=self.group.members).exclude(id=self.creator.pk))
        if created and created_from_doodle:
            # event went from being a doodle to being a real event, so fire event created
            cosinnus_notifications.event_created.send(
                sender=self,
                user=self.creator,
                obj=self,
                audience=get_user_model().objects.filter(
                    id__in=self.group.members).exclude(id=self.creator.pk))

        # create a "going" attendance for the event's creator
        if created and self.state == Event.STATE_SCHEDULED:
            EventAttendance.objects.get_or_create(
                event=self,
                user=self.creator,
                defaults={'state': EventAttendance.ATTENDANCE_GOING})

        self.__state = self.state

    def get_absolute_url(self):
        kwargs = {'group': self.group, 'slug': self.slug}
        if self.state == Event.STATE_VOTING_OPEN:
            return group_aware_reverse('cosinnus:event:doodle-vote',
                                       kwargs=kwargs)
        elif self.state == Event.STATE_ARCHIVED_DOODLE:
            return group_aware_reverse('cosinnus:event:doodle-archived',
                                       kwargs=kwargs)
        return group_aware_reverse('cosinnus:event:event-detail',
                                   kwargs=kwargs)

    def set_suggestion(
            self,
            sugg=None,
            update_fields=['from_date', 'to_date', 'state', 'suggestion']):
        if sugg is None:
            # No suggestion selected or remove selection
            self.from_date = None
            self.to_date = None
            self.state = Event.STATE_VOTING_OPEN
            self.suggestion = None
        elif sugg.event.pk == self.pk:
            # Make sure to not assign a suggestion belonging to another event.
            self.from_date = sugg.from_date
            self.to_date = sugg.to_date
            self.state = Event.STATE_SCHEDULED
            self.suggestion = sugg
        else:
            return
        self.save(update_fields=update_fields)

    @property
    def single_day(self):
        return localtime(self.from_date).date() == localtime(
            self.to_date).date()

    def get_period(self):
        if self.single_day:
            return localize(self.from_date, "d.m.Y")
        else:
            return "%s - %s" % (localize(
                self.from_date, "d.m."), localize(self.to_date, "d.m.Y"))

    @classmethod
    def get_current(self, group, user):
        """ Returns a queryset of the current upcoming events """
        qs = Event.objects.filter(group=group).filter(
            state__in=[Event.STATE_SCHEDULED, Event.STATE_VOTING_OPEN])
        if user:
            qs = filter_tagged_object_queryset_for_user(qs, user)
        return upcoming_event_filter(qs)

    @classmethod
    def get_current_for_portal(self):
        """ Returns a queryset of the current upcoming events in this portal """
        qs = Event.objects.filter(
            group__portal=CosinnusPortal.get_current()).filter(
                state__in=[Event.STATE_SCHEDULED])
        return upcoming_event_filter(qs)

    @property
    def is_same_day(self):
        return localtime(self.from_date).date() == localtime(
            self.to_date).date()

    @property
    def is_same_time(self):
        return self.from_date.time() == self.to_date.time()

    def get_voters_pks(self):
        """ Gets the pks of all Users that have voted for this event.
            Returns an empty list if nobody has voted or the event isn't a doodle. """
        return self.suggestions.all().values_list('votes__voter__id',
                                                  flat=True).distinct()
Esempio n. 24
0
class Location(models.Model):
    location = OSMField()
    location_lat = LatitudeField()
    location_lon = LongitudeField()
    details = models.TextField(blank=True)
Esempio n. 25
0
 def test_longitude_field(self):
     field = LongitudeField()
     field.set_attributes_from_name("location_lon")
     formfield = field.formfield()
     self.assertEqual(formfield.max_value, 180)
     self.assertEqual(formfield.min_value, -180)
Esempio n. 26
0
class Event(LikeableObjectMixin, BaseTaggableObjectModel):

    SORT_FIELDS_ALIASES = [
        ('title', 'title'),
        ('from_date', 'from_date'),
        ('to_date', 'to_date'),
        ('city', 'city'),
        ('state', 'state'),
    ]

    STATE_SCHEDULED = 1
    STATE_VOTING_OPEN = 2
    STATE_CANCELED = 3
    STATE_ARCHIVED_DOODLE = 4

    STATE_CHOICES = (
        (STATE_SCHEDULED, _('Scheduled')),
        (STATE_VOTING_OPEN, _('Voting open')),
        (STATE_CANCELED, _('Canceled')),
        (STATE_ARCHIVED_DOODLE, _('Archived Event Poll')),
    )

    from_date = models.DateTimeField(_('Start'),
                                     default=None,
                                     blank=True,
                                     null=True,
                                     editable=True)

    to_date = models.DateTimeField(_('End'),
                                   default=None,
                                   blank=True,
                                   null=True,
                                   editable=True)

    state = models.PositiveIntegerField(
        _('State'),
        choices=STATE_CHOICES,
        default=STATE_VOTING_OPEN,
    )
    __state = None  # pre-save purpose

    # used as special flag for a hidden conference event
    # that mimics the conference and can be used in normal Event querysets as proxy for the conference
    # the logic for this is in `cosinnus_event.hooks`
    is_hidden_group_proxy = models.BooleanField(
        _('Is hidden proxy'),
        help_text=
        'If set, this event is hidden in its own group, acting as a proxy for the group with from_date and to_date synced, to be able to be shown in other groups.',
        default=False)

    note = models.TextField(_('Note'), blank=True, null=True)

    suggestion = models.ForeignKey(
        'Suggestion',
        verbose_name=_('Event date'),
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='selected_name',
    )

    location = OSMField(_('Location'), blank=True, null=True)
    location_lat = LatitudeField(_('Latitude'), blank=True, null=True)
    location_lon = LongitudeField(_('Longitude'), blank=True, null=True)

    street = models.CharField(_('Street'),
                              blank=True,
                              max_length=50,
                              null=True)

    zipcode = models.PositiveIntegerField(_('ZIP code'), blank=True, null=True)

    city = models.CharField(_('City'), blank=True, max_length=50, null=True)

    public = models.BooleanField(_('Is public (on website)'), default=False)

    image = models.ImageField(_('Image'),
                              upload_to=get_event_image_filename,
                              blank=True,
                              null=True)

    url = models.URLField(_('URL'), blank=True, null=True)

    original_doodle = models.OneToOneField(
        "self",
        verbose_name=_('Original Event Poll'),
        related_name='scheduled_event',
        null=True,
        blank=True,
        on_delete=models.SET_NULL)

    objects = EventQuerySet.as_manager()

    timeline_template = 'cosinnus_event/v2/dashboard/timeline_item.html'

    class Meta(BaseTaggableObjectModel.Meta):
        ordering = ['from_date', 'to_date', 'title']
        verbose_name = _('Event')
        verbose_name_plural = _('Events')

    def __init__(self, *args, **kwargs):
        super(Event, self).__init__(*args, **kwargs)
        self.__state = self.state

    def __str__(self):
        if self.is_hidden_group_proxy:
            readable = _('%(event)s (hidden proxy)') % {'event': self.title}
        elif self.state == Event.STATE_SCHEDULED:
            if self.single_day:
                readable = _('%(event)s (%(date)s - %(end)s)') % {
                    'event': self.title,
                    'date': localize(self.from_date, 'd. F Y h:i'),
                    'end': localize(self.to_date, 'h:i'),
                }
            else:
                readable = _('%(event)s (%(from)s - %(to)s)') % {
                    'event': self.title,
                    'from': localize(self.from_date, 'd. F Y h:i'),
                    'to': localize(self.to_date, 'd. F Y h:i'),
                }
        elif self.state == Event.STATE_CANCELED:
            readable = _('%(event)s (canceled)') % {'event': self.title}
        elif self.state == Event.STATE_VOTING_OPEN:
            readable = _('%(event)s (pending)') % {'event': self.title}
        elif self.state == Event.STATE_ARCHIVED_DOODLE:
            readable = _('%(event)s (archived)') % {'event': self.title}
        else:
            readable = _('%(event)s (state unknown)') % {'event': self.title}

        return readable

    def get_icon(self):
        """ Returns the font-awesome icon specific to this object type """
        if self.state == 2:
            return 'fa-calendar-check-o'
        else:
            return 'fa-calendar'

    def save(self, created_from_doodle=False, *args, **kwargs):
        created = bool(self.pk) == False
        super(Event, self).save(*args, **kwargs)

        if created and not self.is_hidden_group_proxy:
            # event/doodle was created or
            # event went from being a doodle to being a real event, so fire event created
            session_id = uuid1().int
            audience = get_user_model().objects.filter(
                id__in=self.group.members)
            if self.creator:
                audience = audience.exclude(id=self.creator.pk)
            group_followers_except_creator_ids = [
                pk for pk in self.group.get_followed_user_ids()
                if not pk in [self.creator_id]
            ]
            group_followers_except_creator = get_user_model().objects.filter(
                id__in=group_followers_except_creator_ids)
            if self.state == Event.STATE_SCHEDULED:
                # followers for the group
                cosinnus_notifications.followed_group_event_created.send(
                    sender=self,
                    user=self.creator,
                    obj=self,
                    audience=group_followers_except_creator,
                    session_id=session_id)
                # regular members
                cosinnus_notifications.event_created.send(
                    sender=self,
                    user=self.creator,
                    obj=self,
                    audience=audience,
                    session_id=session_id,
                    end_session=True)
            else:
                # followers for the group
                cosinnus_notifications.followed_group_doodle_created.send(
                    sender=self,
                    user=self.creator,
                    obj=self,
                    audience=group_followers_except_creator,
                    session_id=session_id)
                # regular members
                cosinnus_notifications.doodle_created.send(
                    sender=self,
                    user=self.creator,
                    obj=self,
                    audience=audience,
                    session_id=session_id,
                    end_session=True)

        # create a "going" attendance for the event's creator
        if settings.COSINNUS_EVENT_MARK_CREATOR_AS_GOING and created and self.state == Event.STATE_SCHEDULED:
            EventAttendance.objects.get_or_create(
                event=self,
                user=self.creator,
                defaults={'state': EventAttendance.ATTENDANCE_GOING})

        self.__state = self.state

    def get_absolute_url(self):
        kwargs = {'group': self.group, 'slug': self.slug}
        if self.state == Event.STATE_VOTING_OPEN:
            return group_aware_reverse('cosinnus:event:doodle-vote',
                                       kwargs=kwargs)
        elif self.state == Event.STATE_ARCHIVED_DOODLE:
            return group_aware_reverse('cosinnus:event:doodle-archived',
                                       kwargs=kwargs)
        elif self.is_hidden_group_proxy:
            # hidden proxy events redirect to the group
            return self.group.get_absolute_url()
        return group_aware_reverse('cosinnus:event:event-detail',
                                   kwargs=kwargs)

    def get_edit_url(self):
        kwargs = {'group': self.group, 'slug': self.slug}
        if self.state == Event.STATE_VOTING_OPEN or self.state == Event.STATE_ARCHIVED_DOODLE:
            return group_aware_reverse('cosinnus:event:doodle-edit',
                                       kwargs=kwargs)
        elif self.is_hidden_group_proxy:
            # hidden proxy events redirect to the group
            return self.group.get_edit_url()
        return group_aware_reverse('cosinnus:event:event-edit', kwargs=kwargs)

    def get_delete_url(self):
        kwargs = {'group': self.group, 'slug': self.slug}
        if self.state == Event.STATE_VOTING_OPEN or self.state == Event.STATE_ARCHIVED_DOODLE:
            return group_aware_reverse('cosinnus:event:doodle-delete',
                                       kwargs=kwargs)
        elif self.is_hidden_group_proxy:
            # hidden proxy events redirect to the group
            return self.group.get_delete_url()
        return group_aware_reverse('cosinnus:event:event-delete',
                                   kwargs=kwargs)

    def is_user_attending(self, user):
        """ For notifications, statecheck if a user is attending this event """
        return self.attendances.filter(
            user=user,
            state__in=[
                EventAttendance.ATTENDANCE_GOING,
                EventAttendance.ATTENDANCE_MAYBE_GOING
            ]).count() >= 1

    def special_alert_check(self, user):
        """ Can override checking whether this user wants this alert """
        return self.is_user_attending(user)

    @property
    def sort_key(self):
        """ Overriding this sort key so re-ordering won't happen for widgets using events 
            (because all event querysets are already well-sorted.) """
        return 0

    @property
    def stream_sort_key(self):
        """ Sort key for activity streams returns the created date instead of the event date """
        return self.created

    def set_suggestion(
            self,
            sugg=None,
            update_fields=['from_date', 'to_date', 'state', 'suggestion']):
        if sugg is None:
            # No suggestion selected or remove selection
            self.from_date = None
            self.to_date = None
            self.state = Event.STATE_VOTING_OPEN
            self.suggestion = None
        elif sugg.event.pk == self.pk:
            # Make sure to not assign a suggestion belonging to another event.
            self.from_date = sugg.from_date
            self.to_date = sugg.to_date
            self.state = Event.STATE_SCHEDULED
            self.suggestion = sugg
        else:
            return
        self.save(update_fields=update_fields)

    @property
    def single_day(self):
        return localtime(self.from_date).date() == localtime(
            self.to_date).date()

    def get_humanized_event_time_html(self):
        return mark_safe(
            render_to_string('cosinnus_event/common/humanized_event_time.html',
                             {'event': self})).strip()

    def get_period(self):
        if self.single_day:
            return localize(self.from_date, "d.m.Y")
        else:
            return "%s - %s" % (localize(
                self.from_date, "d.m."), localize(self.to_date, "d.m.Y"))

    @classmethod
    def get_current(self, group, user, include_sub_projects=False):
        """ Returns a queryset of the current upcoming events """
        groups = [group]
        if include_sub_projects:
            groups = groups + list(group.get_children())

        qs = Event.objects.filter(group__in=groups).filter(state__in=[
            Event.STATE_SCHEDULED,
            Event.STATE_VOTING_OPEN,
        ])

        if not include_sub_projects:
            # mix in reflected objects, not needed if we are sub-grouping anyways
            for onegroup in groups:
                if "%s.%s" % (self._meta.app_label, self._meta.model_name
                              ) in settings.COSINNUS_REFLECTABLE_OBJECTS:
                    mixin = MixReflectedObjectsMixin()
                    qs = mixin.mix_queryset(qs, self._meta.model, onegroup)
        if user:
            qs = filter_tagged_object_queryset_for_user(qs, user)
        return upcoming_event_filter(qs).distinct()

    @classmethod
    def get_current_for_portal(self):
        """ Returns a queryset of the current upcoming events in this portal """
        qs = Event.objects.filter(
            group__portal=CosinnusPortal.get_current()).filter(
                state__in=[Event.STATE_SCHEDULED])
        return upcoming_event_filter(qs)

    @property
    def is_same_day(self):
        if not self.from_date or not self.to_date:
            return True
        return localtime(self.from_date).date() == localtime(
            self.to_date).date()

    @property
    def is_same_time(self):
        if not self.from_date or not self.to_date:
            return True
        return self.from_date.time() == self.to_date.time()

    @property
    def is_all_day(self):
        if not self.from_date or not self.to_date:
            return False
        return (localize(self.from_date, "H:i") == '00:00') and (localize(
            self.to_date, "H:i") == '23:59')

    def get_voters_pks(self):
        """ Gets the pks of all Users that have voted for this event.
            Returns an empty list if nobody has voted or the event isn't a doodle. """
        return self.suggestions.all().values_list('votes__voter__id',
                                                  flat=True).distinct()

    def get_suggestions_hash(self):
        """ Returns a hashable string containing all suggestions with their time.
            Useful to compare equality of suggestions for two doodles. """
        return ','.join([
            str(time.mktime(dt.timetuple()))
            for dt in self.suggestions.all().values_list('from_date',
                                                         flat=True)
        ])

    def get_comment_post_url(self):
        return group_aware_reverse('cosinnus:event:comment',
                                   kwargs={
                                       'group': self.group,
                                       'event_slug': self.slug
                                   })

    def get_attendants_count(self):
        all_attendants = EventAttendance.objects.filter(event=self)
        attendants_going = all_attendants.filter(
            state=EventAttendance.ATTENDANCE_GOING)
        return attendants_going.count()
Esempio n. 27
0
 def test_longitude_field(self):
     field = LongitudeField()
     field.set_attributes_from_name("location_lon")
     formfield = field.formfield()
     self.assertEqual(formfield.max_value, 180)
     self.assertEqual(formfield.min_value, -180)
Esempio n. 28
0
class BaseTagObject(models.Model):

    VISIBILITY_USER = 0  # for Users, this setting means: "Only Group Members can see me"
    VISIBILITY_GROUP = 1  # for Users, this setting means: "Only Logged in Users can see me"
    VISIBILITY_ALL = 2  # for Users, this setting means: "Everyone can see me"

    #: Choices for :attr:`visibility`: ``(int, str)``
    # Empty first choice must be included for select2 placeholder compatibility!
    VISIBILITY_CHOICES = (
        ('', ''),
        (VISIBILITY_USER, _('Only me')),
        (VISIBILITY_GROUP, _('Team members only')),
        (VISIBILITY_ALL, _('Public (visible without login)')),
    )

    group = models.ForeignKey(settings.COSINNUS_GROUP_OBJECT_MODEL,
                              verbose_name=_('Team'),
                              related_name='+',
                              null=True,
                              on_delete=models.CASCADE)

    persons = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                     blank=True,
                                     null=True,
                                     verbose_name=_('Persons'),
                                     related_name='+')

    tags = TaggableManager(_('Tags'), blank=True)

    visibility = models.PositiveSmallIntegerField(_('Permissions'),
                                                  blank=True,
                                                  default=VISIBILITY_GROUP,
                                                  choices=VISIBILITY_CHOICES)

    #: Choices for :attr:`approach`: ``(str, str)``
    # Empty first choice must be included for select2 placeholder compatibility!
    APPROACH_CHOICES = (
        ('', ''),
        ('zivilgesellschaft', 'Zivilgesellschaft'),
        ('politik', 'Politik'),
        ('forschung', 'Forschung'),
        ('unternehmen', 'Unternehmen'),
    )

    location = OSMField(_('Location'), blank=True, null=True)
    location_lat = LatitudeField(_('Latitude'), blank=True, null=True)
    location_lon = LongitudeField(_('Longitude'), blank=True, null=True)

    place = models.CharField(_('Place'),
                             max_length=100,
                             default='',
                             blank=True)

    valid_start = models.DateTimeField(_('Valid from'), blank=True, null=True)
    valid_end = models.DateTimeField(_('Valid to'), blank=True, null=True)

    approach = models.CharField(_('Approach'),
                                blank=True,
                                null=True,
                                choices=APPROACH_CHOICES,
                                max_length=255)

    #: Choices for :attr:`topics`: ``(int, str)``
    # Empty first choice must be included for select2 placeholder compatibility!
    TOPIC_CHOICES = getattr(settings, 'COSINNUS_TOPIC_CHOICES', [])

    topics = models.CommaSeparatedIntegerField(
        _('Topics'), blank=True, null=True,
        max_length=255)  # We cannot add choices here as this would
    # fail validation
    text_topics = models.ManyToManyField(CosinnusTopicCategory,
                                         verbose_name=_('Text Topics'),
                                         related_name='tagged_objects',
                                         blank=True,
                                         null=True)

    likes = models.PositiveSmallIntegerField(_('Likes'), blank=True, default=0)
    likers = models.ManyToManyField(
        settings.AUTH_USER_MODEL, blank=True, null=True,
        related_name='likes+')  # no reverse relation on model

    def save(self, *args, **kwargs):
        # update like count
        if self.pk:
            self.likes = self.likers.count()
        super(BaseTagObject, self).save(*args, **kwargs)

    def get_all_language_topics_rendered(self):
        """ Returns a single string with all assigned topic strings for each language """
        if not self.topics:
            return ''
        renders = []
        cur_language = translation.get_language()
        try:
            for lang in settings.LANGUAGES:
                translation.activate(lang[0])
                topi = self.get_topics_rendered()
                renders.append(topi)
        finally:
            if not cur_language:
                translation.deactivate()
            else:
                translation.activate(cur_language)
        return ', '.join([topic_str for topic_str in renders if topic_str])

    def get_topics_rendered(self):
        ret = ', '.join([force_text(t) for t in self.get_topics()])
        return ret

    def get_topics(self):
        ret = []
        if self.topics:
            m = dict(BaseTagObject.TOPIC_CHOICES)
            for i in [
                    int(x.strip()) for x in
                [topic for topic in self.topics.split(',') if topic]
            ]:
                t = m.get(i, None)
                if t:
                    ret.append(t)
        return ret

    @property
    def location_url(self):
        if not self.location_lat or not self.location_lon:
            return None
        return 'http://www.openstreetmap.org/?mlat=%s&mlon=%s&zoom=15&layers=M' % (
            self.location_lat, self.location_lon)

    class Meta(object):
        abstract = True

    def __str__(self):
        return "Tag object {0}".format(self.pk)